[
  {
    "path": ".gitignore",
    "content": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n\n\n# Distribution / packaging\n.Python\nenv/\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\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.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*,cover\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n"
  },
  {
    "path": "AUTHOURS",
    "content": "Huang Xiongbiao"
  },
  {
    "path": "Changelog",
    "content": "2016-08-18 version 0.2.6\n1.启动不再需要root权限\n2.更换键盘和音效实现\n3.更加人性化\n\n2016-08-02 version 0.2.5\n1.修复小键盘的123不能响应热键的问题\n2.修复隐藏按钮的一个交互问题\n3.增加英语翻译,语言切换\n\n2016-01-29 version 0.2.4\n1.修复一个配置的bug\n2.提供32位的deb包\n\n2016-01-27 version 0.2.3\n1.打包为deb包\n2.软件字体更换为DroidSansFallbackFull\n3.修复一些bug\n\n2016-01-25 version 0.2.2\n1.添加新音效（爆裂鼓手）\n2.修改界面，现在显示中文\n3.修改音效显示名称\n4.修复一个键盘监测bug\n5.再次运行程序自动打开设置界面\n\n2015-10-31 version 0.2.1\n1.修复错误弹出更新提示的bug\n\n2015-10-13 version 0.2.0\n1.打包成单独运行文件，制作了安装脚本，解决依赖问题\n2.改为使用pyinstaller打包\n\n2015-10-11 version 0.1.9\n1.UI微调(字体，颜色等)\n\n2015-10-10 version 0.1.8\n1.修改了背景颜色，与mac版同步\n2.同步了mac版的两款(Cherry)新音效\n\n2015-09-05 version 0.1.7\n1.增加了检查更新的功能\n\n2015-08-31 version 0.1.6\n1.实现将程序运行情况输出到log文件,以便调试 保存位置为/tmp/tickeys.log\n\n2015-08-10 version 0.1.5\n1.实现真正后台化，启动后会隐藏窗口\n2.修改当前音效显示颜色\n\n2015-08-10 version 0.1.4\n1.打开程序后会出现气泡提醒\n\n2015-08-04 version 0.1.3\n1.修正因路径问题导致的配置无法正确显示的问题\n\n2015-08-03 version 0.1.2\n1.更新键盘检测方法（测试中）\n2.增加配置自动保存功能\n3.修改默认音效为mechanical\n4.修改部分函数名称\n\n2015-08-02 version 0.1.1a6\n1.修改键盘检测方法，支持更多键盘类型（测试中）\n\n2015-08-02 version 0.1.1a5\n1.修改配色，使风格大致与mac版相同\n2.修改布局，适应大小变化\n3.加入开机自启动设置（测试中）\n\n2015-07-31 version 0.1.0a4\n1.加入changlog\n2.修改setup，修改相关安装依赖\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Xiongbiao Huang\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\n"
  },
  {
    "path": "MANIFEST.in",
    "content": "recursive-include tickeys/Resources/data *\nrecursive-include tickeys/Resources/fonts *\nrecursive-include tickeys/locale *\ninclude tickeys/requirements.txt\ninclude tickeys/tickeys\ninclude tickeys/tickeysui.kv\ninclude tickeys/tickeys.png\ninclude README.md\ninclude LICENSE\ninclude AUTHOURS\ninclude Changelog"
  },
  {
    "path": "README.md",
    "content": "# Tickeys-linux\n\nInstant audio feedback when typing. For Linux.\n\n![Tickeys Icon](http://img.blog.csdn.net/20150802103616846)\n\nEnglish Readme: [English Readme](https://github.com/BillBillBillBill/Tickeys-linux/blob/master/README_en_US.md)\n\n中文版Readme: [中文Readme](https://github.com/BillBillBillBill/Tickeys-linux/blob/master/README_zh_CN.md)\n\n# Screenshot\n\n## v0.2.5\n![Tickeys v0.2.5](https://github.com/BillBillBillBill/Tickeys-linux/blob/master/screenshot/tickeys_v0.2.5.png)\n\n## v0.2.2\n![Tickeys v0.2.2](https://github.com/BillBillBillBill/Tickeys-linux/blob/master/screenshot/tickeys_v0.2.2.png)\n\n## v0.1.9\n![Tickeys v0.1.9](https://github.com/BillBillBillBill/Tickeys-linux/blob/master/screenshot/tickeys_v0.1.9.png)\n\n## v0.1.8\n![Tickeys v0.1.8](https://github.com/BillBillBillBill/Tickeys-linux/blob/master/screenshot/tickeys_v0.1.8.png)\n\n## v0.1.1\n![Tickeys v0.1.1](https://github.com/BillBillBillBill/Tickeys-linux/blob/master/screenshot/tickeys_v0.1.1.png)\n\n## v0.0.1\n![Tickeys v0.0.1](https://github.com/BillBillBillBill/Tickeys-linux/blob/master/screenshot/tickeys_v0.0.1.png)\n"
  },
  {
    "path": "README_en_US.md",
    "content": "[Downlod 32 bit version tickeys_0.2.5_i386.deb：http://pan.baidu.com/s/1c2BN3Pm](http://pan.baidu.com/s/1c2BN3Pm)\n\n[Downlod 64 bit version tickeys_0.2.5_amd64.deb：http://pan.baidu.com/s/1o8AhmwM](http://pan.baidu.com/s/1o8AhmwM)\n\nBug or question?\n\nPlease tell me in issue.\n\n[![Join the chat at https://gitter.im/BillBillBillBill/Tickeys-linux](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/BillBillBillBill/Tickeys-linux?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)\n![Tickeys Icon](http://img.blog.csdn.net/20150802103616846)\n\n# Introduce\nTickeys is an powerful keyboard sound effect tool。Tickeys now brings seven sound styles，include Bubble, Typewriter, Mechanical, Sword, etc.\n\nThis tool have Windows and Mac version，Mac Version:([GitHub](https://github.com/yingDev/Tickeys))\n\n# Project Website\nhttp://www.yingdev.com/projects/tickeys\n\n#　PyPI\nhttps://pypi.python.org/pypi/tickeys\n\n# Tickeys Mac Version\nhttps://github.com/yingDev/Tickeys\n\n# Install\nTickeys has not been fully tested to install in different distribution yet, some distribution may need installing related requirements.\n\n## Download the packaged deb(suggest)\n\n* deb links：\n\n[Downlod 32 bit version tickeys_0.2.5_i386.deb：http://pan.baidu.com/s/1c2BN3Pm](http://pan.baidu.com/s/1c2BN3Pm)\n\n[Downlod 64 bit version tickeys_0.2.5_amd64.deb：http://pan.baidu.com/s/1o8AhmwM](http://pan.baidu.com/s/1o8AhmwM)\n\n* After install, find Tickeys on launcher and open it\n\n## Compile(Build from source, need requirements)：\n\n* next operation show **execute** `sudo apt-get install python-dev python-pip python-kivy xdotool gksu`first to meet the requirements for Tickeys to run.\n* install package(Notice Version)： sudo pip install cython==0.20.2 notify2 pyinstaller==3.0 kivy==1.9.0 evdev\n\n#### Quick Compile Install：\n\n* execute `sudo apt-get install python-dev python-pip python-kivy xdotool && sudo easy_install tickeys`。\n* execute `sudo easy_install tickeys` or `sudo pip install tickeys`\n* Use command `sudo tickeys` to open (`sudo tickeys -c` for CLI version)\n\n\n#### Running Problem\n\n* Couldn't hide window：\n\nSolve：execute `sudo apt-get install xdotool ` to install xdotool\n\n* no setuptools or pip\n\nSolve：execute `sudo apt-get install python-pip` to install\n\n* Python.h：no such file\n\nSolve：execute `sudo apt-get install python-dev` to install\n\n* ImportError: No module named Cython.Distutils\n\nSolve：execute `sudo easy_install cython` to install\n\n* ImportError: libSDL-1.2.so.0: cannot open shared object file: No such file or directory\n\n    Solve：execute `yum install libSDL-1.2.so.0` to install\n\n* NotImplementedError: mixer module not available\n\n    Solve：same with above\n\nDebian and Ubuntu User may try to install:\n\n    * sudo apt-get install xdotool\n    * sudo apt-get install libsdl1.2-dev\n    * sudo apt-get install libsdl-mixer1.2\n    * sudo apt-get install libsdl-ttf2.0\n\n# How to use\nRoot permission is needed，implement the CLI and GUI version，GUI version is run by default，it will auto hide after open，press QAZ123 to show the window of tickeys.\n\n\n# How to Develop\n* ####Code Style: PEP8\n\n* ####Application UI framework：Kivy\n\n* ####Open sources license： MIT License\n\nInstall requirements：\n\n    pip install -r requirements.txt\n\n# Project struct\nTickeys-linux\n```\n├── AUTHOURS\n├── build.sh\n├── build.spec               pyinstaller\n├── Changelog\n├── deb.sh\n├── dist\n│   ├── make_deb.sh          script for deb\n├── lib                      lib for run\n├── LICENSE\n├── MANIFEST.in\n├── README.md\n├── screenshot\n├── setup.py\n├── tickeys\n│   ├── locale              translation\n│   ├── build.py            cx_freeze(desperate)\n│   ├── CLI.py              start CLI\n│   ├── config.py           config controller\n│   ├── GUI.py              start GUI\n│   ├── __init__.py\n│   ├── keyboardHandler.py  handler keyboard events\n│   ├── logger.py\n│   ├── requirements.txt\n│   ├── Resources\n│   │   ├── data\n│   │   │   ├── bubble\n│   │   │   ├── Cherry_G80_3000\n│   │   │   ├── Cherry_G80_3494\n│   │   │   ├── drum\n│   │   │   ├── mechanical\n│   │   │   ├── sword\n│   │   │   └── typewriter\n│   │   │   ├── schemes.json\n│   │   └── fonts\n│   │       └── DroidSansFallbackFull.ttf\n│   ├── run.py            entry\n│   ├── run_with_CLI.py   entry with CLI\n│   ├── soundPlayer.py\n│   ├── startupHandler.py\n│   ├── tickeys\n│   ├── tickeys.png\n│   ├── tickeys_tray.py   (not use)\n│   ├── tickeysui.kv      (desperate)\n│   └── windowManager.py\n└── tickeys.egg-info\n```\n\n# Author\nHuang Xiongbiao\n\nbillo@qq.com\n"
  },
  {
    "path": "README_zh_CN.md",
    "content": "[下载32位tickeys_0.2.5_i386.deb：http://pan.baidu.com/s/1c2BN3Pm](http://pan.baidu.com/s/1c2BN3Pm)\n\n[下载64位tickeys_0.2.5_amd64.deb：http://pan.baidu.com/s/1o8AhmwM](http://pan.baidu.com/s/1o8AhmwM)\n\n如果有任何问题或者建议，请在issue中提出\n\n[![Join the chat at https://gitter.im/BillBillBillBill/Tickeys-linux](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/BillBillBillBill/Tickeys-linux?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)\n![Tickeys Icon](http://img.blog.csdn.net/20150802103616846)\n\n# 简介\nTickeys是一款很强大的键盘音效软件。Tickeys 自带了七种声音效果方案，有打字机、冒泡、机械键盘、剑气等。每天都听着键盘声音是不是很烦闷，现在有了这款神器你就可以瞬间帮助自己的键盘加上逼格特效。\n\n这个软件之前发布了Windows和Mac版，Tickeys 是由 Nozama 所做的一个 Mac 平台的开源小项目 ([GitHub](https://github.com/yingDev/Tickeys))，Windows 版由黄飞实现。我使用了之后，觉得挺有意思的，因此用Python写了个Linux版的。\n\n# 项目网站\nhttp://www.yingdev.com/projects/tickeys\n\nPyPI: https://pypi.python.org/pypi/tickeys\n\n# Tickeys的Mac版本\nhttps://github.com/yingDev/Tickeys\n\n# 安装说明\n在不同发行版上可能会有因为文件的缺失或者环境不同导致无法使用，需要安装相关依赖。\n\n## 下载打包好的安装包安装(建议)\n\n* 下载deb安装包：\n\n[下载32位tickeys_0.2.4_i386.deb：http://pan.baidu.com/s/1geOYtdp](http://pan.baidu.com/s/1c2BN3Pm)\n\n[下载64位tickeys_0.2.4_amd64.deb：http://pan.baidu.com/s/1o8AhmwM](http://pan.baidu.com/s/1o8AhmwM)\n\n* 安装后，在启动器中找到Tickeys打开。\n\n## 编译安装(需要安装依赖)：\n\n* 以下方法需要**先执行**`sudo apt-get install python-dev python-pip python-kivy xdotool gksu`来安装依赖，一般这样就可以满足运行条件了。\n* 安装库(注意版本)： sudo pip install cython==0.20.2 notify2 pyinstaller==3.0 kivy==1.9.0 evdev\n\n#### 快速编译安装：执行`sudo apt-get install python-dev python-pip python-kivy xdotool && sudo easy_install tickeys`。\n\n### 方法1.自动安装\n\n* 执行`sudo easy_install tickeys` or `sudo pip install tickeys`安装\n* 然后通过 `sudo tickeys` 来打开 (sudo tickeys -c 打开CLI版本)\n\n### 方法2.半自动安装\n\n* 下载 https://github.com/BillBillBillBill/Tickeys-linux/archive/master.zip ，解压后运行 `sudo python setup.py install`\n* 然后通过 `sudo tickeys` 来打开 (sudo tickeys -c 打开CLI版本)\n\n\n#### 错误解决方案：\n\n* 无法隐藏窗口：\n\n解决方法：使用`sudo apt-get install xdotool `安装xdotool\n\n* 若没有setuptools or pip\n\n解决方法：使用`sudo apt-get install python-pip` 安装\n\n* Python.h：没有那个文件或目录\n\n解决方法：使用`sudo apt-get install python-dev`安装\n\n* ImportError: No module named Cython.Distutils\n\n解决方法：使用`sudo easy_install cython`安装\n\n\n* ImportError: libSDL-1.2.so.0: cannot open shared object file: No such file or directory\n\n    解决方法：使用`yum install libSDL-1.2.so.0`安装依赖\n\n* NotImplementedError: mixer module not available\n\n    解决方法：同上\n\nDebian and Ubuntu 用户则可以尝试安装:\n\n    * sudo apt-get install xdotool\n    * sudo apt-get install libsdl1.2-dev\n    * sudo apt-get install libsdl-mixer1.2\n    * sudo apt-get install libsdl-ttf2.0\n\n# 使用说明\n需要以root权限才能启动，实现了CLI版本和GUI版本，默认启动GUI版本，GUI版本启动后会自动隐藏，按QAZ123唤出窗口。\n\n调整参数后会自动保存，下次开启会使用该设置。\n\nOpen at startup是开启开机自启动功能选项，开关置为ON开启功能，开关置为OFF关闭功能。\n\n# TODO\n1.打开程序后出现气泡提醒（已实现）\n2.使GUI真正后台化（已实现）\n3.按最小化按钮或退出按钮隐藏GUI\n4.程序运行情况输出到log文件中,以便调试（已实现）\n\n# 开发\n* ####编码规范: PEP8\n\n* ####应用UI框架：Kivy\n\n* ####开源许可证： MIT License\n\n依赖安装：\n\n    pip install -r requirements.txt\n\n使用pyinstaller打包\n    命令：`pyinstaller build.spec`\n\n播放音乐通过pygame的mixer实现。\n\n键盘事件的获取通过evdev实现。\n\n窗口的控制使用工具xdotool来实现。(另一方法是使用wmctrl来控制窗口)\n\nxdotool的使用：\n* 获取窗口ID：\n    WID=`xdotool search \"Tickeys\" | head -1`\n\n* 激活窗口：\n    xdotool windowactivate --sync $WID\n    xdotool windowmap --sync $WID && xdotool windowactivate --sync $WID\n\n* 隐藏窗口实现：\n    xdotool getactivewindow windowunmap\n    ～～xdotool getactivewindow windowminimize～～\n    或\n    ～～xdotool getactivewindow windowmove 999 0～～\n\n\n# 项目结构\nTickeys-linux\n```\n├── AUTHOURS\n├── build.sh\n├── build.spec               pyinstaller打包用\n├── Changelog                版本变动说明\n├── deb.sh\n├── dist\n│   ├── make_deb.sh          打包成deb包的脚本\n├── lib                      运行所用的一些库\n├── LICENSE\n├── MANIFEST.in\n├── README.md\n├── screenshot              Tickeys截图文件\n├── setup.py                分发用\n├── tickeys\n│   ├── locale              翻译文件\n│   ├── build.py            cx_freeze打包，已不用\n│   ├── CLI.py              启动CLI的模块\n│   ├── config.py            处理配置保存和读取的模块\n│   ├── GUI.py              启动GUI的模块\n│   ├── __init__.py\n│   ├── keyboardHandler.py  处理键盘输入的函数\n│   ├── logger.py           日志记录函数，调试时使用\n│   ├── requirements.txt    开发模块依赖包\n│   ├── Resources           程序资源，包括音效，字体等\n│   │   ├── data\n│   │   │   ├── bubble\n│   │   │   ├── Cherry_G80_3000\n│   │   │   ├── Cherry_G80_3494\n│   │   │   ├── drum\n│   │   │   ├── mechanical\n│   │   │   ├── sword\n│   │   │   └── typewriter\n│   │   │   ├── schemes.json\n│   │   └── fonts\n│   │       └── DroidSansFallbackFull.ttf\n│   ├── run.py            程序入口\n│   ├── run_with_CLI.py   程序入口，带CLI版（失败时运行CLI）\n│   ├── soundPlayer.py       播放声效的模块\n│   ├── startupHandler.py    控制开机自启动的模块\n│   ├── tickeys           启动tickeys的脚本，打包时放进打包后的文件夹使用\n│   ├── tickeys.png\n│   ├── tickeys_tray.py   托盘，由于打包大小问题尚未放入\n│   ├── tickeysui.kv      kv的ui文件，现在已直接写入GUI.py中\n│   └── windowManager.py  提供窗口控制的方法\n└── tickeys.egg-info\n```\n\n# 文件说明\n* build.py cx_freeze打包函数\n\n* run.py 存放入口函数\n\n* readme.txt 放进打包后程序文件夹的readme\n\n* requirements.txt\n\n* tickeys\n\n* CLI.py\n\n* GUI.py\n\n* config.py\n\n* tickeysui.kv\n\n* KeyboardHandler.py\n\n* logger.py\n\n* SoundPlayer.py\n\n* StartupHandler.py\n\n\n# 问题\n* 目前在Fedora上好像无法使用GUI的，不知道是因为我用虚拟机开的问题还是Kivy这个框架的问题，因为提示The 3D features of the virtual machine will be disabled。\n\n\n# 作者\nHuang Xiongbiao\n\nbillo@qq.com\n"
  },
  {
    "path": "build.sh",
    "content": "#!/bin/bash\npyinstaller build.spec"
  },
  {
    "path": "build32.sh",
    "content": "#!/bin/bash\npyinstaller build32.spec"
  },
  {
    "path": "deb.sh",
    "content": "#!/bin/bash\nsh build.sh\ncd dist\nsudo sh make_deb.sh"
  },
  {
    "path": "deb32.sh",
    "content": "#!/bin/bash\nsh build32.sh\ncd dist\nsudo sh make_deb32.sh"
  },
  {
    "path": "setup.py",
    "content": "from setuptools import setup, find_packages\nfrom tickeys import __version__, __author__, __email__\n\nrequirements = [\n    'cython==0.20.2',\n    'kivy==1.9.0',\n    'evdev',\n    'sounddevice',\n    'soundfile',\n    'notify2',\n]\n\n\nsetup(name='tickeys',\n      version=__version__,\n      download_url='https://github.com/BillBillBillBill/Tickeys-linux',\n      packages=['tickeys'],\n      package_dir={'tickeys': 'tickeys'},\n      include_package_data=True,\n      package_data={'tickeys': ['*.*']},\n      # data_files=[],\n      classifiers=[\n          'Intended Audience :: End Users/Desktop',\n          'Development Status :: 3 - Alpha',\n          'Environment :: X11 Applications',\n          'License :: OSI Approved :: MIT License',\n          'Operating System :: POSIX :: Linux',\n          'Natural Language :: Chinese (Simplified)',\n          'Programming Language :: Python :: 2.7',\n      ],\n      author=__author__,\n      author_email=__email__,\n      description='Instant audio feedback when typing. For Linux.',\n      long_description=open('README.md').read(),\n      keywords='keyboard typing audio feedback ',\n      url='https://github.com/BillBillBillBill/Tickeys-linux',\n      license='MIT',\n      entry_points={\n          'console_scripts': ['tickeys = tickeys:main']\n      },\n      install_requires=requirements,\n      tests_require=requirements)\n"
  },
  {
    "path": "tickeys/CLI.py",
    "content": "#!/usr/bin/env python\n# coding: utf-8\nimport cmd\nfrom keyboardHandler import KeyboardHandler\nfrom __init__ import __version__\nimport sys\nreload(sys)\n\nsys.setdefaultencoding(\"utf-8\")\n\n\nclass CLI(cmd.Cmd):\n\n    def __init__(self):\n        cmd.Cmd.__init__(self)\n        self.intro = \"Tickeys %s - Linux\\nType 'help' for help\" % __version__\n        self.prompt = \">>> \"\n        self.detecter = KeyboardHandler()\n        self.detecter.start_detecting()\n\n        self.volume = self.detecter.get_player_infor()['volume'] * 100.0\n        self.pitch = self.detecter.get_player_infor()['pitch'] * 10.0\n        self.style = self.detecter.get_player_infor()['style']\n\n    def default(self, line):\n        print \"Command '%s' is invalid, try 'help'\" % line\n\n    def help_setstyle(self):\n        print \"Set style, change the sound's effect\"\n\n    def do_setstyle(self, arg):\n        style_index = raw_input(\n            \"Input the effect style number you want\"\n            \"(0:bubble 1:mechanical 2:sword 3:typewriter 4:Cherry_G80_3000 5:Cherry_G80_3494 6:drum):\")\n        style_list = ['bubble', 'mechanical', 'sword', 'typewriter', 'Cherry_G80_3000', 'Cherry_G80_3494', 'drum']\n\n        try:\n            style_index = int(style_index)\n            assert(0 <= style_index <= 6)\n        except Exception:\n            print \"Input must between 0~6!!\"\n            return\n\n        self.style = style_list[style_index]\n        self.detecter.set_style(self.style)\n\n    def help_setvol(self):\n        print \"Set volume, input the volume you want\"\n\n    def do_setvol(self, arg):\n        volume = raw_input(\"Input the volume(0~100) you want:\")\n\n        try:\n            volume = float(volume)\n            assert(0 <= volume <= 100)\n        except Exception:\n            print \"Volume must between 0~100!!\"\n            return\n\n        self.volume = volume\n        self.detecter.set_volume(self.volume/100.0)\n\n    # def help_getvol(self):\n    #     print \"Get the volume\"\n\n    # def do_getvol(self, arg):\n    #     print self.volume\n\n    def help_setpitch(self):\n        print \"Set pitch, input the pitch you want\"\n\n    def do_setpitch(self, arg):\n        pitch = raw_input(\"Input the pitch(0~30, default 10) you want:\")\n\n        try:\n            pitch = float(pitch)\n            assert(0 <= pitch <= 30)\n        except Exception:\n            print \"Pitch must between 0~30!!\"\n            return\n\n        self.pitch = pitch\n        self.detecter.set_pitch(self.pitch/10.0)\n\n    # def help_getpitch(self):\n    #     print \"Get the pitch\"\n\n    # def do_getpitch(self, arg):\n    #     print self.pitch\n\n    def help_getinfo(self):\n        print \"Get tickeys' sound effect, volume and pitch\"\n\n    def do_getinfo(self, arg):\n        print \"Sound effect: %s  Volume: %s  Pitch: %s\" \\\n            % (self.style, self.volume, self.pitch)\n\n    def do_quit(self, arg):\n        try:\n            self.detecter.stop_detecting()\n        except Exception:\n            pass\n        finally:\n            sys.exit(0)\n            return True\n\n\nif __name__ == \"__main__\":\n    cli = CLI()\n    cli.cmdloop()\n"
  },
  {
    "path": "tickeys/GUI.py",
    "content": "#!/usr/bin/env python\n# coding: utf-8\nfrom kivy.app import App\nfrom kivy.uix.spinner import Spinner\nfrom kivy.uix.boxlayout import BoxLayout\nfrom kivy.uix.gridlayout import GridLayout\nfrom kivy.uix.modalview import ModalView\nfrom kivy.uix.button import Button\nfrom kivy.uix.label import Label\nfrom keyboardHandler import KeyboardHandler\nfrom kivy.lang import Builder\nfrom startupHandler import add_startup_linux, check_startup_file, delete_startup_linux\nfrom logger import logger\nfrom config import configer\nfrom __init__ import __version__, debug_mode\n\nimport sys\nimport os\nimport gettext\nfrom ast import literal_eval\n\nfrom threading import Thread\nimport notify2\nfrom windowManager import hide_GUI, save_GUI_window_id\n\nreload(sys)\nsys.setdefaultencoding(\"utf-8\")\n\n# set font\nfrom kivy.core.text import Label as textLabel\ntry:\n    os.chdir(os.path.dirname(__file__))\nexcept Exception:\n    pass\ntextLabel.register(\"DroidSans\", \"./Resources/fonts/DroidSansFallbackFull.ttf\")\n\n\nt = gettext.translation('tickeys', 'locale', languages=[configer.lang], fallback=True)\n_ = t.ugettext\n\nBuilder.load_string(('''\n<Main>:\n    pos: 0,0\n    padding: 50\n    rows: 6\n    row_force_default: True\n    row_default_height: 50\n    spacing: 50\n    orientation: 'vertical'\n\n    canvas:\n        Color:\n            rgba: 0.368, 0.384, 0.447, 0.8\n        Rectangle:\n            pos: 0,0\n            size: self.size\n    Label:\n        bold: True\n        text: 'Tickeys'\n        font_size: 50\n        size_hint_y: None\n\n    SpinnerRow\n    AdjustVol\n    AdjustPitch\n    ExitAndSwitchRow\n    InforRow\n\n\n<AdjustVol>\n    Label:\n        bold: True\n        color: 1, 1, 1, 1\n        font_size: 33\n        size_hint_x: None\n        width: 250\n        text: '%s'\n    Slider:\n        min: 0.0\n        max: 1.0\n        value: root.parent.configer.volume\n        width: 300\n        on_value: root.setVolume(self.value)\n\n<AdjustPitch>\n    Label:\n        bold: True\n        color: 1, 1, 1, 1\n        font_size: 33\n        size_hint_x: None\n        width: 250\n        text: '%s'\n    Slider:\n        min: 0.8\n        max: 2.5\n        value: root.parent.configer.pitch\n        width: 300\n        on_value: root.setPitch(self.value)\n\n\n<SpinnerRow>:\n    Label:\n        bold: True\n        color: 1, 1, 1, 1\n        font_size: 33\n        size_hint_x: None\n        text: \"%s\"\n        width: 250\n    EffectSpinner:\n        on_text: root.change_style()\n\n\n<EffectSpinner>:\n    bold: True\n    font_size: 30\n    text: root.get_style_name()\n    background_color: 3, 3, 3, 1\n    color: 0.1, 0.67, 0.93, 1\n    values: %s\n\n<ExitAndSwitchRow>:\n    Label:\n        size_hint_x: None\n        width: root.width/6.0 - 120\n    Label:\n        size_hint_x: None\n        color: 1, 1, 1, 1\n        font_size: 17\n        width: root.width/6.0 + 60\n        text: '%s：'\n    Switch:\n        size_hint_x: None\n        width: 40\n        id: switcher\n        active: root.have_added\n        on_active: root.add_delete_startup_file(self.active)\n    Label:\n        size_hint_x: None\n        width: root.width/6.0 - 85\n    Spinner:\n        width: 40\n        bold: True\n        font_size: 20\n        text: root.get_language_name()\n        background_color: 3, 3, 3, 1\n        color: 0.1, 0.67, 0.93, 1\n        values: ['English', '简体中文']\n        on_text: root.set_language(self.text)\n    Label:\n        size_hint_x: None\n        width: 20\n    Button:\n        size_hint_x: None\n        width: 150\n        font_size: 20\n        background_color: 3, 3, 3, 1\n        bold: True\n        text: \"%s\"\n        color: 0,0,0,1\n        on_press: root.Exit()\n    Label:\n        size_hint_x: None\n        width: 20\n    Button:\n        size_hint_x: None\n        width: 150\n        font_size: 20\n        background_color: 3, 3, 3, 1\n        bold: True\n        text: \"%s\"\n        color: 0,0,0,1\n        on_release: root.Hide()\n\n<InforRow>:\n    Label:\n        color: 0.8, 0.8, 0.8, 1\n        font_size: 20\n        size_hint_x: None\n        text: root.get_version()\n        width: root.width/3.0\n    Label:\n        color: 0.8, 0.8, 0.8, 1\n        font_size: 20\n        size_hint_x: None\n        markup: True\n        text: \"[ref=%s]%s[/ref]\"\n        width: root.width/3.0\n        on_ref_press:root.open_project_website()\n    Label:\n        color: 0.8, 0.8, 0.8, 1\n        font_size: 20\n        size_hint_x: None\n        text: \"%s： Bill (billo@qq.com)\"\n        width: root.width/3.0\n        border: 1,1,1,1\n        on_touch_move:\n''' % (_(\"Volume\"), _(\"Pitch\"), _(\"Sound Style\"), _(\"Sound Style Items\"), _(\"Start at startup\"), _(\"Quit\"), _(\"Hide\"), _(\"Project Website\"), _(\"Project Website\"), _(\"Author\"))).encode('utf-8'))\n\n\ndef show_notify(notify_content=\"\"):\n    try:\n        notify2.init('Tickeys')\n        title = 'Tickeys'\n        icon_file_path = os.getcwd() + '/tickeys.png'\n        notify = notify2.Notification(title, notify_content, icon_file_path)\n        notify.show()\n    except Exception, e:\n        logger.exception(e)\n        logger.error(\"show notify fail\")\n\n\ndef show_startup_notify():\n    notify_content = _(\"Startup Notify\")\n    show_notify(notify_content)\n\n\ndef check_update_and_notify():\n    try:\n        import urllib\n        import json\n        logger.info(\"Version checking...\")\n        r = urllib.urlopen('http://billbill.sinaapp.com/tickeys')\n        return_msg = json.loads(r.read())\n        print return_msg\n        if return_msg[\"version\"] <= __version__:\n            logger.debug(\"Version checking success. It is the latest version...\")\n        else:\n            # show update notify\n            notify_content = _(\"Update Notify\") % (return_msg[\"version\"], return_msg[\"update\"])\n            print notify_content\n            show_notify(notify_content)\n    except Exception, e:\n        logger.exception(e)\n        logger.error(\"Version checking fail:\" + str(e))\n\n\nclass EffectSpinner(Spinner):\n    def get_style_name(self):\n        style_list = literal_eval(_(\"Sound Style Items\"))\n        style_display_name_map = {\n            'bubble': style_list[0],\n            'typewriter': style_list[1],\n            'mechanical': style_list[2],\n            'sword': style_list[3],\n            'Cherry_G80_3000': style_list[4],\n            'Cherry_G80_3494': style_list[5],\n            'drum': style_list[6]\n        }\n        name = self.parent.parent.configer.style\n        return style_display_name_map.get(name, name)\n\n\nclass SpinnerRow(BoxLayout):\n    def change_style(self):\n        style_list = literal_eval(_(\"Sound Style Items\"))\n        style_display_name_map = {\n            style_list[0]: \"bubble\",\n            style_list[1]: \"typewriter\",\n            style_list[2]: \"mechanical\",\n            style_list[3]: \"sword\",\n            style_list[4]: \"Cherry_G80_3000\",\n            style_list[5]: \"Cherry_G80_3494\",\n            style_list[6]: \"drum\"\n        }\n        # for safe\n        if self.children[0].text not in style_display_name_map:\n            return\n        style_name = style_display_name_map[self.children[0].text]\n        self.parent.detecter.set_style(style_name)\n\n\nclass AdjustVol(BoxLayout):\n    def setVolume(self, volume):\n        self.parent.detecter.set_volume(volume)\n\n\nclass AdjustPitch(BoxLayout):\n    def setPitch(self, pitch):\n        self.parent.detecter.set_pitch(pitch)\n\n\nclass SwitcherRow(BoxLayout):\n    pass\n\n\nclass ExitAndSwitchRow(BoxLayout):\n    def Exit(self):\n        os._exit(0)\n\n    def Hide(self):\n        self.parent.Hide()\n\n    def add_delete_startup_file(self, active):\n        if active:\n            add_startup_linux()\n        else:\n            delete_startup_linux()\n\n    def set_language(self, language):\n        language_map = {\n            \"English\": \"en_US\",\n            \"简体中文\": \"zh_CN\"\n        }\n        self.parent.configer.lang = language_map.get(language, \"en_US\")\n        self.parent.configer.save_config()\n        # show popup hint\n        view = ModalView(size_hint=(None, None), size=(0, 0))\n        view.add_widget(Label(text=_(\"This will take effect next time you start\"), font_size=30))\n        view.open()\n\n    def get_language_name(self):\n        lang_display_name_map = {\n            \"en_US\": \"English\",\n            \"zh_CN\": \"简体中文\"\n        }\n        lang = self.parent.configer.lang\n        return lang_display_name_map.get(lang, \"English\")\n\n    @property\n    def have_added(self):\n        return check_startup_file()\n\n\nclass InforRow(BoxLayout):\n    def open_project_website(self, *args):\n        from webbrowser import open_new\n        open_new(\"https://github.com/BillBillBillBill/Tickeys-linux\")\n\n    def get_version(self):\n        return 'Version： ' + __version__\n\n\nclass Main(GridLayout):\n    def __init__(self, *args, **kwargs):\n        self.configer = configer\n        super(Main, self).__init__(**kwargs)\n        save_GUI_window_id()\n        self.Hide()\n        # set up keyboard detecter\n        self.detecter = KeyboardHandler()\n        self.detecter.start_detecting()\n        # show notify message\n        Thread(target=show_startup_notify).start()\n        # now not check update\n        # Thread(target=check_update_and_notify).start()\n\n    def Hide(self):\n        if not debug_mode:\n            hide_GUI()\n\n\nclass TickeysApp(App):\n    def __init__(self, *args, **kwargs):\n        super(TickeysApp, self).__init__(**kwargs)\n\n    def build(self):\n        self.icon = 'tickeys.png'\n        root = Main()\n        return root\n\n    def on_stop(self):\n        os._exit(0)\n\n\nif __name__ == '__main__':\n    TickeysApp().run()\n"
  },
  {
    "path": "tickeys/Resources/data/bubble/license.txt",
    "content": "Sound pack downloaded from Freesound.org\n----------------------------------------\n\nThis pack of sounds contains sounds by Glaneur de sons ( http://www.freesound.org/people/Glaneur%20de%20sons/  )\nYou can find this pack online at: http://www.freesound.org/people/Glaneur%20de%20sons/packs/6686/\n\n\nLicense details\n---------------\n\nSampling+: http://creativecommons.org/licenses/sampling+/1.0/\nCreative Commons 0: http://creativecommons.org/publicdomain/zero/1.0/\nAttribution: http://creativecommons.org/licenses/by/3.0/\nAttribution Noncommercial: http://creativecommons.org/licenses/by-nc/3.0/\n\n\nSounds in this pack\n-------------------\n\n  * 104950__Glaneur_de_sons__bubbles_2_.wav\n    * url: http://www.freesound.org/people/Glaneur%20de%20sons/sounds/104950/\n    * license: Attribution\n  * 104949__Glaneur_de_sons__bubbles_1_.wav\n    * url: http://www.freesound.org/people/Glaneur%20de%20sons/sounds/104949/\n    * license: Attribution\n  * 104948__Glaneur_de_sons__bubble_9_.wav\n    * url: http://www.freesound.org/people/Glaneur%20de%20sons/sounds/104948/\n    * license: Attribution\n  * 104947__Glaneur_de_sons__bubble_8_.wav\n    * url: http://www.freesound.org/people/Glaneur%20de%20sons/sounds/104947/\n    * license: Attribution\n  * 104946__Glaneur_de_sons__bubble_7_.wav\n    * url: http://www.freesound.org/people/Glaneur%20de%20sons/sounds/104946/\n    * license: Attribution\n  * 104945__Glaneur_de_sons__bubble_6_.wav\n    * url: http://www.freesound.org/people/Glaneur%20de%20sons/sounds/104945/\n    * license: Attribution\n  * 104944__Glaneur_de_sons__bubble_5_.wav\n    * url: http://www.freesound.org/people/Glaneur%20de%20sons/sounds/104944/\n    * license: Attribution\n  * 104943__Glaneur_de_sons__bubble_4_.wav\n    * url: http://www.freesound.org/people/Glaneur%20de%20sons/sounds/104943/\n    * license: Attribution\n  * 104942__Glaneur_de_sons__bubble_3_.wav\n    * url: http://www.freesound.org/people/Glaneur%20de%20sons/sounds/104942/\n    * license: Attribution\n  * 104941__Glaneur_de_sons__bubble_2_.wav\n    * url: http://www.freesound.org/people/Glaneur%20de%20sons/sounds/104941/\n    * license: Attribution\n  * 104940__Glaneur_de_sons__bubble_1_.wav\n    * url: http://www.freesound.org/people/Glaneur%20de%20sons/sounds/104940/\n    * license: Attribution\n\n"
  },
  {
    "path": "tickeys/Resources/data/drum/_readme_and_license.txt",
    "content": "Sound pack downloaded from Freesound.org\n----------------------------------------\n\nThis pack of sounds contains sounds by Veiler ( http://www.freesound.org/people/Veiler/  )\nYou can find this pack online at: http://www.freesound.org/people/Veiler/packs/16053/\n\n\nLicense details\n---------------\n\nSampling+: http://creativecommons.org/licenses/sampling+/1.0/\nCreative Commons 0: http://creativecommons.org/publicdomain/zero/1.0/\nAttribution: http://creativecommons.org/licenses/by/3.0/\nAttribution Noncommercial: http://creativecommons.org/licenses/by-nc/3.0/\n\n\nSounds in this pack\n-------------------\n\n  * 261413__veiler__crash.wav\n    * url: http://www.freesound.org/people/Veiler/sounds/261413/\n    * license: Creative Commons 0\n  * 261412__veiler__tom-2.wav\n    * url: http://www.freesound.org/people/Veiler/sounds/261412/\n    * license: Creative Commons 0\n  * 261411__veiler__tom-3.wav\n    * url: http://www.freesound.org/people/Veiler/sounds/261411/\n    * license: Creative Commons 0\n  * 261410__veiler__tom-4.wav\n    * url: http://www.freesound.org/people/Veiler/sounds/261410/\n    * license: Creative Commons 0\n  * 261409__veiler__kick-bass-win.wav\n    * url: http://www.freesound.org/people/Veiler/sounds/261409/\n    * license: Creative Commons 0\n  * 261408__veiler__snare-3.wav\n    * url: http://www.freesound.org/people/Veiler/sounds/261408/\n    * license: Creative Commons 0\n  * 261407__veiler__tom-1.wav\n    * url: http://www.freesound.org/people/Veiler/sounds/261407/\n    * license: Creative Commons 0\n\n"
  },
  {
    "path": "tickeys/Resources/data/mechanical/license.txt",
    "content": "Sound pack downloaded from Freesound.org\n----------------------------------------\n\nThis pack of sounds contains sounds by jim-ph ( http://www.freesound.org/people/jim-ph/  )\nYou can find this pack online at: http://www.freesound.org/people/jim-ph/packs/12363/\n\n\nLicense details\n---------------\n\nSampling+: http://creativecommons.org/licenses/sampling+/1.0/\nCreative Commons 0: http://creativecommons.org/publicdomain/zero/1.0/\nAttribution: http://creativecommons.org/licenses/by/3.0/\nAttribution Noncommercial: http://creativecommons.org/licenses/by-nc/3.0/\n\n\nSounds in this pack\n-------------------\n\n  * 194799__jim-ph__keyboard5.wav\n    * url: http://www.freesound.org/people/jim-ph/sounds/194799/\n    * license: Creative Commons 0\n  * 194798__jim-ph__vintage-keyboard-4.wav\n    * url: http://www.freesound.org/people/jim-ph/sounds/194798/\n    * license: Creative Commons 0\n  * 194797__jim-ph__vintage-keyboard-3.wav\n    * url: http://www.freesound.org/people/jim-ph/sounds/194797/\n    * license: Creative Commons 0\n  * 194796__jim-ph__vintage-keyboard-2.wav\n    * url: http://www.freesound.org/people/jim-ph/sounds/194796/\n    * license: Creative Commons 0\n  * 194795__jim-ph__vintage-keyboard-1.wav\n    * url: http://www.freesound.org/people/jim-ph/sounds/194795/\n    * license: Creative Commons 0\n\n"
  },
  {
    "path": "tickeys/Resources/data/schemes.json",
    "content": "[\n\t{\n\t\t\"name\":\"bubble\",\n\t\t\"display_name\":\"冒泡\",\n\t\t\"files\":[\"1.wav\",\"2.wav\",\"3.wav\",\"4.wav\",\"5.wav\",\"6.wav\",\"7.wav\",\"8.wav\", \"enter.wav\"],\n\t\t\"non_unique_count\":8,\n\t\t\"key_audio_map\":{\"36\":8}\n\t},\n\n\t{\n\t\t\"name\":\"typewriter\",\n\t\t\"display_name\":\"打字机\",\n\t\t\"files\":[\"key-new-05.wav\",\"key-new-04.wav\",\"key-new-03.wav\",\"key-new-02.wav\",\"key-new-01.wav\",\"space-new.wav\",\"scrollUp.wav\",\"scrollDown.wav\",\"backspace.wav\", \"return-new.wav\"],\n\t\t\"non_unique_count\":5,\n\t\t\"key_audio_map\":{\"36\":9, \"49\":5, \"51\":8}\n\t},\n\n\t{\n\t\t\"name\": \"mechanical\",\n\t\t\"display_name\":\"机械键盘\",\n\t\t\"files\":[\"1.wav\", \"2.wav\", \"3.wav\", \"4.wav\", \"5.wav\"],\n\t\t\"non_unique_count\":4,\n\t\t\"key_audio_map\":{\"36\":4}\n\t},\n\n\t{\n\t\t\"name\": \"sword\",\n\t\t\"display_name\": \"剑气\",\n\t\t\"files\": [\"1.wav\", \"2.wav\", \"3.wav\", \"4.wav\", \"5.wav\", \"6.wav\", \"back.wav\", \"enter.wav\", \"space.wav\"],\n\t\t\"non_unique_count\": 6,\n\t\t\"key_audio_map\":{\"36\": 7,\"49\":8, \"51\":6}\n\t},\n\n\t{\n\t\t\"name\": \"Cherry_G80_3000\",\n\t\t\"display_name\": \"Cherry G80-3000\",\n\t\t\"files\": [\"G80-3000.wav\",  \"G80-3000_fast1.wav\", \"G80-3000_slow1.wav\", \"G80-3000_fast2.wav\",\"G80-3000_slow2.wav\"],\n\t\t\"non_unique_count\": 5,\n\t\t\"key_audio_map\":{\"36\": 4, \"49\": 4}\n\t},\n\n\t{\n\t\t\"name\": \"Cherry_G80_3494\",\n\t\t\"display_name\": \"Cherry G80-3494\",\n\t\t\"files\": [\"G80-3494.wav\", \"G80-3494_fast1.wav\", \"G80-3494_slow1.wav\", \"G80-3494_enter.wav\", \"G80-3494_space.wav\", \"G80-3494_backspace.wav\"],\n\t\t\"non_unique_count\": 3,\n\t\t\"key_audio_map\":{\"36\": 3, \"49\": 4, \"51\": 5}\n\t},\n\n\t{\n\t\t\"name\": \"drum\",\n\t\t\"display_name\": \"爆裂鼓手\",\n\t\t\"files\": [\"1.wav\", \"2.wav\", \"3.wav\", \"4.wav\", \"space.wav\", \"backspace.wav\", \"enter.wav\"],\n\t\t\"non_unique_count\": 4,\n\t\t\"key_audio_map\":{\"36\": 6, \"49\": 4, \"51\": 5}\n\t}\n]"
  },
  {
    "path": "tickeys/__init__.py",
    "content": "__author__ = 'Huang Xiongbiao'\n__email__ = 'billo@qq.com'\n__version__ = '0.2.6'\ndebug_mode = False\n\nfrom run import main\n\n\ndef tickeys():\n    main()\n"
  },
  {
    "path": "tickeys/build.py",
    "content": "import shutil\nimport os\nfrom cx_Freeze import setup, Executable\nfrom __init__ import __version__\n\nexecutable_filename = \"tickeys\"\n\nif __name__ == '__main__':\n\n    buildOptions = dict(\n        compressed=True,\n        include_files=['kivy', 'tickeys', 'Resources'],)\n\n    setup(\n        name=executable_filename,\n        version=__version__,\n        description='Instant audio feedback when typing. For Linux.',\n        options=dict(build_exe=buildOptions),\n        executables=[Executable(\"run.py\")])\n\n    # print \"Move resources file...\"\n    # shutil.copytree(\"../Resources\", os.getcwd() + \"/build/Resources\")\n\n    print \"Add readme file...\"\n    shutil.copyfile(\"../README.md\", os.getcwd() + \"/build/README.md\")\n\n    print \"Add some docs...\"\n    shutil.copyfile(\"../AUTHOURS\", os.getcwd() + \"/build/AUTHOURS\")\n    shutil.copyfile(\"../Changelog\", os.getcwd() + \"/build/Changelog\")\n    shutil.copyfile(\"../LICENSE\", os.getcwd() + \"/build/LICENSE\")"
  },
  {
    "path": "tickeys/config.py",
    "content": "import ConfigParser\nimport os\nfrom logger import logger\n\n\nclass Configer():\n    \"\"\"docstring for Configer\"\"\"\n    def __init__(self, *arg):\n        try:\n            os.chdir(os.path.dirname(__file__))\n        except Exception:\n            pass\n        self.config_path = os.environ[\"HOME\"] + \"/.tickeys/tickeys.conf\"\n        self.cf = ConfigParser.ConfigParser()\n        self.read_config()\n\n    def init_config(self):\n        self.style = 'mechanical'\n        self.volume = 1.0\n        self.pitch = 1.0\n        self.lang = 'en_US'\n        self.autostart = False\n        self.save_config()\n\n    def read_config(self):\n        try:\n            if not os.path.exists(self.config_path):\n                self.init_config()\n            else:\n                self.cf.read(self.config_path)\n                self.volume = self.cf.getfloat('options', 'volume')\n                self.pitch = self.cf.getfloat('options', 'pitch')\n                self.style = self.cf.get('options', 'style')\n                self.autostart = self.cf.get('options', 'autostart')\n                self.lang = self.cf.get('options', 'lang')\n        except Exception, e:\n            self.init_config()\n            logger.debug(e)\n\n    def save_config(self):\n        if not self.cf.sections():\n            self.cf.add_section('options')\n        self.cf.set('options', 'volume', self.volume)\n        self.cf.set('options', 'pitch', self.pitch)\n        self.cf.set('options', 'style', self.style)\n        self.cf.set('options', 'lang', self.lang)\n        self.cf.set('options', 'autostart', self.autostart)\n\n        with open(self.config_path, 'w') as f:\n            self.cf.write(f)\n\n    @property\n    def volume(self):\n        return self.volume\n\n    @property\n    def pitch(self):\n        return self.pitch\n\n    @property\n    def style(self):\n        return self.style\n\n    @property\n    def lang(self):\n        return self.lang\n\n    @property\n    def autostart(self):\n        return self.autostart\n\nconfiger = Configer()\n"
  },
  {
    "path": "tickeys/keyboardHandler.py",
    "content": "#!/usr/bin/env python\n# coding: utf-8\nimport threading\nfrom soundPlayer import SoundPlayer\nfrom logger import logger\nfrom pyxhook import HookManager\nfrom windowManager import show_GUI\n\n__author__ = 'Huang xiongbiao(billo@qq.com)'\n\n\nclass KeyboardHandler():\n\n    def __init__(self):\n        logger.debug(\"Keyboard deteccter created.\")\n        self.hm = HookManager()\n        self.hm.KeyDown = self.key_down\n        self.hm_thread = None\n        self.input_record_list = []\n        self.hot_key_list = [24, 38, 52, 10, 11, 12]      # QAZ123\n        self.hot_key_list2 = [24, 38, 52, 87, 88, 89]  # QAZ123 with 123 in side keyboard\n        self.sp = SoundPlayer()\n\n    def set_style(self, style):\n        self.sp.set_style(style)\n\n    def set_volume(self, volume):\n        self.sp.set_volume(volume)\n\n    def set_pitch(self, pitch):\n        self.sp.set_pitch(pitch)\n\n    def get_player_infor(self):\n        return self.sp.get_infor()\n\n    def key_down(self, event):\n        self.sp.play(event.ScanCode)\n        self.check_show_window(event.ScanCode)\n        # logger.debug(str(event))\n\n    # check input if satisfy the hotkey\n    def check_show_window(self, key_code):\n        if self.input_record_list and key_code == self.input_record_list[-1]:\n            return\n        input_record_length = len(self.input_record_list)\n        next_key_code = self.hot_key_list[input_record_length]\n        next_key_code2 = self.hot_key_list2[input_record_length]\n        if key_code == next_key_code or key_code == next_key_code2:\n            self.input_record_list.append(key_code)\n            if input_record_length == 5:\n                show_GUI()\n                self.input_record_list = []\n        else:\n            # clear the record if not satisfy\n            self.input_record_list = []\n\n    def start_detecting(self):\n        self.hm_thread = threading.Thread(target=self.hm.start, args=())\n        self.hm_thread.start()\n\n    # kill all threads\n    def stop_detecting(self):\n        self.hm_thread._Thread__stop()\n        self.hm.cancel()\n\nif __name__ == '__main__':\n    detecter = KeyboardHandler()\n    detecter.start_detecting()\n"
  },
  {
    "path": "tickeys/kivy/__init__.py",
    "content": "'''\nKivy framework\n==============\n\nKivy is an open source library for developing multi-touch applications. It is\ncompletely cross-platform (Linux/OSX/Win) and released under the terms of the\nMIT License.\n\nIt comes with native support for many multi-touch input devices, a growing\nlibrary of multi-touch aware widgets and hardware accelerated OpenGL drawing.\nKivy is designed to let you focus on building custom and highly interactive\napplications as quickly and easily as possible.\n\nWith Kivy, you can take full advantage of the dynamic nature of Python. There\nare thousands of high-quality, free libraries that can be integrated in your\napplication. At the same time, performance-critical parts are implemented\nin the C language.\n\nSee http://kivy.org for more information.\n'''\n\n__all__ = (\n    'require',\n    'kivy_configure', 'kivy_register_post_configuration',\n    'kivy_options', 'kivy_base_dir',\n    'kivy_modules_dir', 'kivy_data_dir', 'kivy_shader_dir',\n    'kivy_icons_dir', 'kivy_home_dir', 'kivy_userexts_dir',\n    'kivy_config_fn', 'kivy_usermodules_dir',\n)\n\n__version__ = '1.9.0'\n\nimport sys\nimport shutil\nfrom getopt import getopt, GetoptError\nfrom os import environ, mkdir\nfrom os.path import dirname, join, basename, exists, expanduser\nfrom kivy.logger import Logger, LOG_LEVELS\nfrom kivy.utils import platform\n\n# internals for post-configuration\n__kivy_post_configuration = []\n\n\nif platform == 'macosx' and sys.maxsize < 9223372036854775807:\n    r = '''Unsupported Python version detected!:\n    Kivy requires a 64 bit version of Python to run on OS X. We strongly\n    advise you to use the version of Python that is provided by Apple\n    (don't use ports, fink or homebrew unless you know what you're\n    doing).\n    See http://kivy.org/docs/installation/installation-macosx.html for\n    details.\n    '''\n    Logger.critical(r)\n\n\ndef require(version):\n    '''Require can be used to check the minimum version required to run a Kivy\n    application. For example, you can start your application code like this::\n\n        import kivy\n        kivy.require('1.0.1')\n\n    If a user attempts to run your application with a version of Kivy that is\n    older than the specified version, an Exception is raised.\n\n    The Kivy version string is built like this::\n\n        X.Y.Z[-tag[-tagrevision]]\n\n        X is the major version\n        Y is the minor version\n        Z is the bugfixes revision\n\n    The tag is optional, but may be one of 'dev', 'alpha', or 'beta'.\n    The tagrevision is the revision of the tag.\n\n    .. warning::\n\n        You must not ask for a version with a tag, except -dev. Asking for a\n        'dev' version will just warn the user if the current Kivy\n        version is not a -dev, but it will never raise an exception.\n        You must not ask for a version with a tagrevision.\n\n    '''\n\n    def parse_version(version):\n        # check for tag\n        tag = None\n        tagrev = None\n        if '-' in version:\n            l = version.split('-')\n            if len(l) == 2:\n                version, tag = l\n            elif len(l) == 3:\n                version, tag, tagrev = l\n            else:\n                raise Exception('Revision format must be X.Y.Z[-tag]')\n\n        # check x y z\n        l = version.split('.')\n        if len(l) != 3:\n            raise Exception('Revision format must be X.Y.Z[-tag]')\n        return [int(x) for x in l], tag, tagrev\n\n    # user version\n    revision, tag, tagrev = parse_version(version)\n    # current version\n    sysrevision, systag, systagrev = parse_version(__version__)\n\n    # ensure that the required version don't contain tag, except dev\n    if tag not in (None, 'dev'):\n        raise Exception('Revision format must not have any tag except \"dev\"')\n    if tag == 'dev' and systag != 'dev':\n        Logger.warning('Application requested a -dev version of Kivy. '\n                       '(You have %s, but the application requires %s)' % (\n                           __version__, version))\n    # not tag rev (-alpha-1, -beta-x) allowed.\n    if tagrev is not None:\n        raise Exception('Revision format must not contain any tagrevision')\n\n    # finally, checking revision\n    if sysrevision < revision:\n        raise Exception('The version of Kivy installed on this system '\n                        'is too old. '\n                        '(You have %s, but the application requires %s)' % (\n                            __version__, version))\n\n\ndef kivy_configure():\n    '''Call post-configuration of Kivy.\n    This function must be called if you create the window yourself.\n    '''\n    for callback in __kivy_post_configuration:\n        callback()\n\n\ndef kivy_register_post_configuration(callback):\n    '''Register a function to be called when kivy_configure() is called.\n\n    .. warning::\n        Internal use only.\n    '''\n    __kivy_post_configuration.append(callback)\n\n\ndef kivy_usage():\n    '''Kivy Usage: %s [OPTION...]::\n\n        -h, --help\n            Prints this help message.\n        -d, --debug\n            Shows debug log.\n        -a, --auto-fullscreen\n            Force 'auto' fullscreen mode (no resolution change).\n            Uses your display's resolution. This is most likely what you want.\n        -c, --config section:key[:value]\n            Set a custom [section] key=value in the configuration object.\n        -f, --fullscreen\n            Force running in fullscreen mode.\n        -k, --fake-fullscreen\n            Force 'fake' fullscreen mode (no window border/decoration).\n            Uses the resolution specified by width and height in your config.\n        -w, --windowed\n            Force running in a window.\n        -p, --provider id:provider[,options]\n            Add an input provider (eg: ccvtable1:tuio,192.168.0.1:3333).\n        -m mod, --module=mod\n            Activate a module (use \"list\" to get a list of available modules).\n        -r, --rotation\n            Rotate the window's contents (0, 90, 180, 270).\n        -s, --save\n            Save current Kivy configuration.\n        --size=640x480\n            Size of window geometry.\n        --dpi=96\n            Manually overload the Window DPI (for testing only.)\n    '''\n    print(kivy_usage.__doc__ % (basename(sys.argv[0])))\n\n\n#: Global settings options for kivy\nkivy_options = {\n    'window': ('egl_rpi', 'sdl2', 'pygame', 'sdl', 'x11'),\n    'text': ('pil', 'sdl2', 'pygame', 'sdlttf'),\n    'video': (\n        'gstplayer', 'ffmpeg', 'ffpyplayer', 'gi', 'pygst', 'pyglet',\n        'null'),\n    'audio': ('gstplayer', 'pygame', 'gi', 'pygst', 'ffpyplayer', 'sdl2'),\n    'image': ('tex', 'imageio', 'dds', 'gif', 'sdl2', 'pygame', 'pil', 'ffpy'),\n    'camera': ('opencv', 'gi', 'pygst', 'videocapture', 'avfoundation'),\n    'spelling': ('enchant', 'osxappkit', ),\n    'clipboard': (\n        'android', 'winctypes', 'xsel', 'dbusklipper', 'nspaste', 'sdl2',\n        'pygame', 'dummy', 'gtk3', )}\n\n# Read environment\nfor option in kivy_options:\n    key = 'KIVY_%s' % option.upper()\n    if key in environ:\n        try:\n            if type(kivy_options[option]) in (list, tuple):\n                kivy_options[option] = environ[key].split(',')\n            else:\n                kivy_options[option] = environ[key].lower() in \\\n                    ('true', '1', 'yes', 'yup')\n        except Exception:\n            Logger.warning('Core: Wrong value for %s environment key' % key)\n            Logger.exception('')\n\n# Extract all needed path in kivy\n#: Kivy directory\nkivy_base_dir = dirname(sys.modules[__name__].__file__)\n#: Kivy modules directory\n\nkivy_modules_dir = environ.get('KIVY_MODULES_DIR',\n                               join(kivy_base_dir, 'modules'))\n#: Kivy extension directory\nkivy_exts_dir = environ.get('KIVY_EXTS_DIR',\n                            join(kivy_base_dir, 'extensions'))\n#: Kivy data directory\nkivy_data_dir = environ.get('KIVY_DATA_DIR',\n                            join(kivy_base_dir, 'data'))\n#: Kivy glsl shader directory\nkivy_shader_dir = join(kivy_data_dir, 'glsl')\n#: Kivy icons config path (don't remove the last '')\nkivy_icons_dir = join(kivy_data_dir, 'icons', '')\n#: Kivy user-home storage directory\nkivy_home_dir = ''\n#: Kivy configuration filename\nkivy_config_fn = ''\n#: Kivy user modules directory\nkivy_usermodules_dir = ''\n#: Kivy user extensions directory\nkivy_userexts_dir = ''\n\n\n# Don't go further if we generate documentation\nif any(name in sys.argv[0] for name in ('sphinx-build', 'autobuild.py')):\n    environ['KIVY_DOC'] = '1'\nif 'sphinx-build' in sys.argv[0]:\n    environ['KIVY_DOC_INCLUDE'] = '1'\nif any('nosetests' in arg for arg in sys.argv):\n    environ['KIVY_UNITTEST'] = '1'\nif any('pyinstaller' in arg for arg in sys.argv):\n    environ['KIVY_PACKAGING'] = '1'\n\nif not environ.get('KIVY_DOC_INCLUDE'):\n    # Configuration management\n    if 'KIVY_HOME' in environ:\n        kivy_home_dir = expanduser(environ['KIVY_HOME'])\n    else:\n        user_home_dir = expanduser('~')\n        if platform == 'android':\n            user_home_dir = environ['ANDROID_APP_PATH']\n        elif platform == 'ios':\n            user_home_dir = join(expanduser('~'), 'Documents')\n        kivy_home_dir = join(user_home_dir, '.kivy')\n    kivy_config_fn = join(kivy_home_dir, 'config.ini')\n    kivy_usermodules_dir = join(kivy_home_dir, 'mods')\n    kivy_userexts_dir = join(kivy_home_dir, 'extensions')\n    icon_dir = join(kivy_home_dir, 'icon')\n\n    if 'KIVY_NO_CONFIG' not in environ:\n        if not exists(kivy_home_dir):\n            mkdir(kivy_home_dir)\n        if not exists(kivy_usermodules_dir):\n            mkdir(kivy_usermodules_dir)\n        if not exists(kivy_userexts_dir):\n            mkdir(kivy_userexts_dir)\n        if not exists(icon_dir):\n            try:\n                shutil.copytree(join(kivy_data_dir, 'logo'), icon_dir)\n            except:\n                Logger.exception('Error when copying logo directory')\n\n    # configuration\n    from kivy.config import Config\n\n    # Set level of logger\n    level = LOG_LEVELS.get(Config.get('kivy', 'log_level'))\n    Logger.setLevel(level=level)\n\n    # Can be overrided in command line\n    if ('KIVY_UNITTEST' not in environ and\n        'KIVY_PACKAGING' not in environ and\n        'KIVY_NO_ARGS' not in environ):\n        # save sys argv, otherwize, gstreamer use it and display help..\n        sys_argv = sys.argv\n        sys.argv = sys.argv[:1]\n\n        try:\n            opts, args = getopt(sys_argv[1:], 'hp:fkawFem:sr:dc:', [\n                'help', 'fullscreen', 'windowed', 'fps', 'event',\n                'module=', 'save', 'fake-fullscreen', 'auto-fullscreen',\n                'display=', 'size=', 'rotate=', 'config=', 'debug',\n                'dpi='])\n\n        except GetoptError as err:\n            Logger.error('Core: %s' % str(err))\n            kivy_usage()\n            sys.exit(2)\n\n        # set argv to the non-read args\n        sys.argv = sys_argv[0:1] + args\n    else:\n        opts = []\n        args = []\n\n    need_save = False\n    for opt, arg in opts:\n        if opt in ('-h', '--help'):\n            kivy_usage()\n            sys.exit(0)\n        elif opt in ('-p', '--provider'):\n            try:\n                pid, args = arg.split(':', 1)\n                Config.set('input', pid, args)\n            except ValueError:\n                # when we are doing an executable on macosx with\n                # pyinstaller, they are passing information with -p. so\n                # it will conflict with our current -p option. since the\n                # format is not the same, just avoid it.\n                pass\n        elif opt in ('-a', '--auto-fullscreen'):\n            Config.set('graphics', 'fullscreen', 'auto')\n        elif opt in ('-c', '--config'):\n            l = arg.split(':', 2)\n            if len(l) == 2:\n                Config.set(l[0], l[1], '')\n            elif len(l) == 3:\n                Config.set(l[0], l[1], l[2])\n            else:\n                raise Exception('Invalid --config value')\n            if l[0] == 'kivy' and l[1] == 'log_level':\n                level = LOG_LEVELS.get(Config.get('kivy', 'log_level'))\n                Logger.setLevel(level=level)\n        elif opt in ('-k', '--fake-fullscreen'):\n            Config.set('graphics', 'fullscreen', 'fake')\n        elif opt in ('-f', '--fullscreen'):\n            Config.set('graphics', 'fullscreen', '1')\n        elif opt in ('-w', '--windowed'):\n            Config.set('graphics', 'fullscreen', '0')\n        elif opt in ('--size', ):\n            w, h = str(arg).split('x')\n            Config.set('graphics', 'width', w)\n            Config.set('graphics', 'height', h)\n        elif opt in ('--display', ):\n            Config.set('graphics', 'display', str(arg))\n        elif opt in ('-m', '--module'):\n            if str(arg) == 'list':\n                from kivy.modules import Modules\n                Modules.usage_list()\n                sys.exit(0)\n            args = arg.split(':', 1)\n            if len(args) == 1:\n                args += ['']\n            Config.set('modules', args[0], args[1])\n        elif opt in ('-s', '--save'):\n            need_save = True\n        elif opt in ('-r', '--rotation'):\n            Config.set('graphics', 'rotation', arg)\n        elif opt in ('-d', '--debug'):\n            level = LOG_LEVELS.get('debug')\n            Logger.setLevel(level=level)\n        elif opt == '--dpi':\n            environ['KIVY_DPI'] = arg\n\n    if need_save and 'KIVY_NO_CONFIG' not in environ:\n        try:\n            with open(kivy_config_fn, 'w') as fd:\n                Config.write(fd)\n        except Exception as e:\n            Logger.exception('Core: error while saving default'\n                             'configuration file:', str(e))\n        Logger.info('Core: Kivy configuration saved.')\n        sys.exit(0)\n\n    # configure all activated modules\n    from kivy.modules import Modules\n    Modules.configure()\n\n    # android hooks: force fullscreen and add android touch input provider\n    if platform in ('android', 'ios'):\n        from kivy.config import Config\n        Config.set('graphics', 'fullscreen', 'auto')\n        Config.remove_section('input')\n        Config.add_section('input')\n\n    if platform == 'android':\n        Config.set('input', 'androidtouch', 'android')\n\nLogger.info('Kivy: v%s' % (__version__))\nLogger.info('Python: v{}'.format(sys.version))\n\n"
  },
  {
    "path": "tickeys/kivy/_event.pxd",
    "content": "from cpython.ref cimport PyObject\n\ncdef class ObjectWithUid(object):\n    cdef readonly int uid\n\n\ncdef class Observable(ObjectWithUid):\n    cdef object __fast_bind_mapping\n    cdef object bound_uid\n\n\ncdef class EventDispatcher(ObjectWithUid):\n    cdef dict __event_stack\n    cdef dict __properties\n    cdef dict __storage\n    cdef object __weakref__\n    cpdef dict properties(self)\n\n\ncdef enum BoundLock:\n    # the state of the BoundCallback, i.e. whether it can be deleted\n    unlocked  # whether the BoundCallback is unlocked and can be deleted\n    locked  # whether the BoundCallback is locked and cannot be deleted\n    deleted  # whether the locked BoundCallback was marked for deletion\n\ncdef class BoundCallback:\n    cdef object func\n    cdef tuple largs\n    cdef dict kwargs\n    cdef int is_ref  # if func is a ref to the function\n    cdef BoundLock lock  # see BoundLock\n    cdef BoundCallback next  # next callback in chain\n    cdef BoundCallback prev  # previous callback in chain\n    cdef object uid  # the uid given for this callback, None if not given\n\n\ncdef class EventObservers:\n    # If dispatching should occur in normal or reverse order of binding.\n    cdef int dispatch_reverse\n    # If in dispatch, the value parameter is dispatched or ignored.\n    cdef int dispatch_value\n    # The first callback bound\n    cdef BoundCallback first_callback\n    # The last callback bound\n    cdef BoundCallback last_callback\n    # The uid to assign to the next bound callback.\n    cdef object uid\n\n    cdef inline void bind(self, object observer, int is_ref=*) except *\n    cdef inline object fast_bind(self, object observer, tuple largs, dict kwargs, int is_ref)\n    cdef inline void unbind(self, object observer, int is_ref, int stop_on_first) except *\n    cdef inline void fast_unbind(self, object observer, tuple largs, dict kwargs) except *\n    cdef inline object unbind_uid(self, object uid)\n    cdef inline void remove_callback(self, BoundCallback callback, int force=*) except *\n    cdef inline object _dispatch(\n        self, object f, tuple slargs, dict skwargs, object obj, object value, tuple largs, dict kwargs)\n    cdef inline int dispatch(self, object obj, object value, tuple largs, dict kwargs, int stop_on_true) except 2\n"
  },
  {
    "path": "tickeys/kivy/adapters/__init__.py",
    "content": "'''\nAdapters\n========\n\n.. versionadded:: 1.5.0\n\nAn adapter is a mediating controller-type class that processes and presents\ndata for use in views. It does this by generating models, generally lists of\n:class:`~kivy.uix.listview.SelectableView` items, that are consumed and\npresented by views. Views are top-level widgets, such as a\n:class:`~kivy.uix.listview.ListView`, that allow users to scroll through\nand (optionally) interact with your data.\n\nThe Concept\n-----------\n\nKivy adapters are modelled on the\n`Adapter design pattern <http://en.wikipedia.org/wiki/Adapter_pattern>`_.\nConceptually, they play the role of a 'controller' between you data and views\nin a `Model-View-Controller\n<https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller>`_\ntype architecture.\n\nThe role of an adapter can be depicted as follows:\n\n.. image:: images/adapters.png\n\n\nThe Components\n--------------\n\nThe components involved in this process are:\n\n- **Adapters**: The adapter plays a mediating role between the user interface\n  and your data. It manages the creation of the view elements for the model\n  using the args_converter to prepare the contructor arguments for your\n  cls/template view items.\n\n  The base :class:`Adapter` is subclassed by the\n  :class:`SimpleListAdapter` and :class:`ListAdapter`. The :class:`DictAdapter`\n  is a more advanced and flexible subclass of :class:`ListAdapter`.\n\n    :doc:`api-kivy.adapters.adapter`,\n    :doc:`api-kivy.adapters.simplelistadapter`,\n    :doc:`api-kivy.adapters.listadapter`,\n    :doc:`api-kivy.adapters.dictadapter`.\n\n- **Models**: The data for which an adapter serves as a bridge to views can be\n  any sort of data. However, for convenience, model mixin classes can ease the\n  preparation or shaping of data for use in the system. For selection\n  operations, the :class:`SelectableDataItem` can optionally prepare data items\n  to provide and receive selection information (data items are not required to\n  be \"selection-aware\", but in some cases it may be desired).\n\n    :doc:`api-kivy.adapters.models`.\n\n- **Args Converters**: Argument converters are made by the application\n  programmer to do the work of converting data items to argument dictionaries\n  suitable for instantiating views. In effect, they take each row of your data\n  and create dictionaries that are passed into the constructors of your\n  cls/template which are then used populate your View.\n\n    :doc:`api-kivy.adapters.args_converters`.\n\n- **Views**: Models of your data are presented to the user via views. Each of\n  your data items create a corresponding view subitem (the cls or template)\n  presented in a list by the View. The base :class:`AbstractView` currently has\n  one concrete implementation: the :class:`ListView`.\n\n    :doc:`api-kivy.uix.abstractview`,\n    :doc:`api-kivy.uix.listview`.\n\n----\n'''\n"
  },
  {
    "path": "tickeys/kivy/adapters/adapter.py",
    "content": "'''\nAdapter\n=======\n\n.. versionadded:: 1.5\n\n.. warning::\n\n    This code is still experimental, and its API is subject to change in a\n    future version.\n\nAn :class:`~kivy.adapters.adapter.Adapter` is a bridge between data and\nan :class:`~kivy.uix.abstractview.AbstractView` or one of its subclasses, such\nas a :class:`~kivy.uix.listview.ListView`.\n\nThe following arguments can be passed to the contructor to initialise the\ncorresponding properties:\n\n* :attr:`~Adapter.data`: for any sort of data to be used in a view. For an\n  :class:`~kivy.adapters.adapter.Adapter`, data can be an object as well as a\n  list, dict, etc. For a :class:`~kivy.adapters.listadapter.ListAdapter`, data\n  should be a list. For a :class:`~kivy.adapters.dictadapter.DictAdapter`,\n  data should be a dict.\n\n* :attr:`~Adapter.cls`: the class used to instantiate each list item view\n  instance (Use this or the template argument).\n\n* :attr:`~Adapter.template`: a kv template to use to instantiate each list item\n  view instance (Use this or the cls argument).\n\n* :attr:`~Adapter.args_converter`: a function used to transform the data items\n  in preparation for either a cls instantiation or a kv template\n  invocation. If no args_converter is provided, the data items are assumed\n  to be simple strings.\n\nPlease refer to the :mod:`~kivy.adapters` documentation for an overview of how\nadapters are used.\n\n'''\n\n__all__ = ('Adapter', )\n\nfrom kivy.event import EventDispatcher\nfrom kivy.properties import ObjectProperty\nfrom kivy.lang import Builder\nfrom kivy.adapters.args_converters import list_item_args_converter\nfrom kivy.factory import Factory\nfrom kivy.compat import string_types\n\n\nclass Adapter(EventDispatcher):\n    '''An :class:`~kivy.adapters.adapter.Adapter` is a bridge between data and\n    an :class:`~kivy.uix.abstractview.AbstractView` or one of its subclasses,\n    such as a :class:`~kivy.uix.listview.ListView`.\n    '''\n\n    data = ObjectProperty(None)\n    '''\n    The data for which a view is to be constructed using either the cls or\n    template provided, together with the args_converter provided or the default\n    args_converter.\n\n    In this base class, data is an ObjectProperty, so it could be used for a\n    wide variety of single-view needs.\n\n    Subclasses may override it in order to use another data type, such as a\n    :class:`~kivy.properties.ListProperty` or\n    :class:`~kivy.properties.DictProperty` as appropriate. For example, in a\n    :class:`~.kivy.adapters.listadapter.ListAdapter`, data is a\n    :class:`~kivy.properties.ListProperty`.\n\n    :attr:`data` is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    cls = ObjectProperty(None)\n    '''\n    A class for instantiating a given view item (Use this or template). If this\n    is not set and neither is the template, a :class:`~kivy.uix.label.Label`\n    is used for the view item.\n\n    :attr:`cls` is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    template = ObjectProperty(None)\n    '''\n    A kv template for instantiating a given view item (Use this or cls).\n\n    :attr:`template` is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    args_converter = ObjectProperty(None)\n    '''\n    A function that prepares an args dict for the cls or kv template to build\n    a view from a data item.\n\n    If an args_converter is not provided, a default one is set that assumes\n    simple content in the form of a list of strings.\n\n    :attr:`args_converter` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    def __init__(self, **kwargs):\n\n        if 'data' not in kwargs:\n            raise Exception('adapter: input must include data argument')\n\n        if 'cls' in kwargs:\n            if 'template' in kwargs:\n                msg = 'adapter: cannot use cls and template at the same time'\n                raise Exception(msg)\n            elif not kwargs['cls']:\n                raise Exception('adapter: a cls or template must be defined')\n        else:\n            if 'template' in kwargs:\n                if not kwargs['template']:\n                    msg = 'adapter: a cls or template must be defined'\n                    raise Exception(msg)\n            else:\n                raise Exception('adapter: a cls or template must be defined')\n\n        if 'args_converter' in kwargs:\n            self.args_converter = kwargs['args_converter']\n        else:\n            self.args_converter = list_item_args_converter\n\n        super(Adapter, self).__init__(**kwargs)\n\n    def bind_triggers_to_view(self, func):\n        self.bind(data=func)\n\n    def get_data_item(self):\n        return self.data\n\n    def get_cls(self):\n        '''\n        .. versionadded:: 1.9.0\n\n        Returns the widget type specified by self.cls. If it is a\n        string, the :class:`~kivy.factory.Factory` is queried to retrieve the\n        widget class with the given name, otherwise it is returned directly.\n        '''\n        cls = self.cls\n        if isinstance(cls, string_types):\n            try:\n                cls = getattr(Factory, cls)\n            except AttributeError:\n                raise AttributeError(\n                    'Listadapter cls widget does not exist.')\n        return cls\n\n    def get_view(self, index):  # pragma: no cover\n        item_args = self.args_converter(self.data)\n\n        cls = self.get_cls()\n        if cls:\n            return cls(**item_args)\n        else:\n            return Builder.template(self.template, **item_args)\n"
  },
  {
    "path": "tickeys/kivy/adapters/args_converters.py",
    "content": "'''\nList Item View Argument Converters\n==================================\n\n.. versionadded:: 1.5\n\n\nThe default list item args converter for list adapters is a function (shown\nbelow) that takes a row index and a string. It returns a dict with the string as\nthe *text* item, along with two properties suited for simple text items with\na height of 25.\n\nSimple Usage\n------------\n\nArgument converters may be normal functions or, as in the case of the default\nargs converter, lambdas::\n\n    list_item_args_converter = lambda row_index, x: {'text': x,\n                                                     'size_hint_y': None,\n                                                     'height': 25}\n\nAdvanced Usage\n--------------\n\nTypically, having the argument converter perform a simple mapping suffices.\nThere are times, however, when more complex manipulation is required. When using\na :class:`~kivy.uix.listview.CompositeListItem`, it is possible to specify\na list of cls dictionaries. This allows you so compose a single view item\nout of multiple classes, each of which can recieve their own class constructor\narguments via the *kwargs* keyword::\n\n    args_converter = lambda row_index, rec: \\\\\n            {'text': rec['text'],\n             'size_hint_y': None,\n             'height': 25,\n             'cls_dicts': [{'cls': ListItemButton,\n                            'kwargs': {'text': rec['text']}},\n                           {'cls': ListItemLabel,\n                            'kwargs': {'text': \"Middle-{0}\".format(rec['text']),\n                                       'is_representing_cls': True}},\n                           {'cls': ListItemButton,\n                            'kwargs': {'text': rec['text']}}]}\n\nPlease see the `list_composite.py <https://github.com/\\\nkivy/kivy/tree/master/examples/widgets/lists/list_composite.py>`_ for a complete\nexample.\n\n'''\nlist_item_args_converter = lambda row_index, x: {'text': x,\n                                                 'size_hint_y': None,\n                                                 'height': 25}\n"
  },
  {
    "path": "tickeys/kivy/adapters/dictadapter.py",
    "content": "'''\nDictAdapter\n===========\n\n.. versionadded:: 1.5\n\n.. warning::\n\n    This code is still experimental, and its API is subject to change in a\n    future version.\n\nA :class:`~kivy.adapters.dictadapter.DictAdapter` is an adapter around a\npython dictionary of records. It extends the list-like capabilities of the\n:class:`~kivy.adapters.listadapter.ListAdapter`.\n\nIf you wish to have a bare-bones list adapter, without selection, use the\n:class:`~kivy.adapters.simplelistadapter.SimpleListAdapter`.\n\n'''\n\n__all__ = ('DictAdapter', )\n\nfrom kivy.properties import ListProperty, DictProperty\nfrom kivy.adapters.listadapter import ListAdapter\n\n\nclass DictAdapter(ListAdapter):\n    '''A :class:`~kivy.adapters.dictadapter.DictAdapter` is an adapter around a\n    python dictionary of records. It extends the list-like capabilities of\n    the :class:`~kivy.adapters.listadapter.ListAdapter`.\n    '''\n\n    sorted_keys = ListProperty([])\n    '''The sorted_keys list property contains a list of hashable objects (can\n    be strings) that will be used directly if no args_converter function is\n    provided. If there is an args_converter, the record received from a\n    lookup of the data, using keys from sorted_keys, will be passed\n    to it for instantiation of list item view class instances.\n\n    :attr:`sorted_keys` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [].\n    '''\n\n    data = DictProperty(None)\n    '''A dict that indexes records by keys that are equivalent to the keys in\n    sorted_keys, or they are a superset of the keys in sorted_keys.\n\n    The values can be strings, class instances, dicts, etc.\n\n    :attr:`data` is a :class:`~kivy.properties.DictProperty` and defaults\n    to None.\n    '''\n\n    def __init__(self, **kwargs):\n        if 'sorted_keys' in kwargs:\n            if type(kwargs['sorted_keys']) not in (tuple, list):\n                msg = 'DictAdapter: sorted_keys must be tuple or list'\n                raise Exception(msg)\n        else:\n            self.sorted_keys = sorted(kwargs['data'].keys())\n\n        super(DictAdapter, self).__init__(**kwargs)\n\n        self.bind(sorted_keys=self.initialize_sorted_keys)\n\n    def bind_triggers_to_view(self, func):\n        self.bind(sorted_keys=func)\n        self.bind(data=func)\n\n    # self.data is paramount to self.sorted_keys. If sorted_keys is reset to\n    # mismatch data, force a reset of sorted_keys to data.keys(). So, in order\n    # to do a complete reset of data and sorted_keys, data must be reset\n    # first, followed by a reset of sorted_keys, if needed.\n    def initialize_sorted_keys(self, *args, **kwargs):\n        stale_sorted_keys = False\n        for key in self.sorted_keys:\n            if not key in self.data:\n                stale_sorted_keys = True\n                break\n        else:\n            if kwargs.get('new_data'):\n                if len(self.sorted_keys) != len(self.data):\n                    stale_sorted_keys = True\n        if stale_sorted_keys:\n            self.sorted_keys = sorted(self.data.keys())\n        self.delete_cache()\n        self.initialize_selection()\n\n    # Override ListAdapter.update_for_new_data().\n    def update_for_new_data(self, *args):\n        self.initialize_sorted_keys(new_data=True)\n\n    # Note: this is not len(self.data).\n    def get_count(self):\n        return len(self.sorted_keys)\n\n    def get_data_item(self, index):\n        if index < 0 or index >= len(self.sorted_keys):\n            return None\n        return self.data[self.sorted_keys[index]]\n\n    # [TODO] Also make methods for scroll_to_sel_start, scroll_to_sel_end,\n    #        scroll_to_sel_middle.\n\n    def trim_left_of_sel(self, *args):\n        '''Cut list items with indices in sorted_keys that are less than the\n        index of the first selected item, if there is a selection.\n\n        sorted_keys will be updated by update_for_new_data().\n        '''\n        if len(self.selection) > 0:\n            selected_keys = [sel.text for sel in self.selection]\n            first_sel_index = self.sorted_keys.index(selected_keys[0])\n            desired_keys = self.sorted_keys[first_sel_index:]\n            self.data = dict([(key, self.data[key]) for key in desired_keys])\n\n    def trim_right_of_sel(self, *args):\n        '''Cut list items with indices in sorted_keys that are greater than\n        the index of the last selected item, if there is a selection.\n\n        sorted_keys will be updated by update_for_new_data().\n        '''\n        if len(self.selection) > 0:\n            selected_keys = [sel.text for sel in self.selection]\n            last_sel_index = self.sorted_keys.index(selected_keys[-1])\n            desired_keys = self.sorted_keys[:last_sel_index + 1]\n            self.data = dict([(key, self.data[key]) for key in desired_keys])\n\n    def trim_to_sel(self, *args):\n        '''Cut list items with indices in sorted_keys that are les than or\n        greater than the index of the last selected item, if there is a\n        selection. This preserves intervening list items within the selected\n        range.\n\n        sorted_keys will be updated by update_for_new_data().\n        '''\n        if len(self.selection) > 0:\n            selected_keys = [sel.text for sel in self.selection]\n            first_sel_index = self.sorted_keys.index(selected_keys[0])\n            last_sel_index = self.sorted_keys.index(selected_keys[-1])\n            desired_keys = self.sorted_keys[first_sel_index:last_sel_index + 1]\n            self.data = dict([(key, self.data[key]) for key in desired_keys])\n\n    def cut_to_sel(self, *args):\n        '''Same as trim_to_sel, but intervening list items within the selected\n        range are also cut, leaving only list items that are selected.\n\n        sorted_keys will be updated by update_for_new_data().\n        '''\n        if len(self.selection) > 0:\n            selected_keys = [sel.text for sel in self.selection]\n            self.data = dict([(key, self.data[key]) for key in selected_keys])\n"
  },
  {
    "path": "tickeys/kivy/adapters/listadapter.py",
    "content": "'''\nListAdapter\n=================\n\n.. versionadded:: 1.5\n\n.. warning::\n\n    This code is still experimental, and its API is subject to change in a\n    future version.\n\nA :class:`ListAdapter` is an adapter around a python list and adds support\nfor selection operations. If you wish to have a bare-bones list adapter,\nwithout selection, use a\n:class:`~kivy.adapters.simplelistadapter.SimpleListAdapter`.\n\nFrom an :class:`~kivy.adapters.Adapter`, a :class:`ListAdapter` inherits cls,\ntemplate, and args_converter properties and adds others that control selection\nbehaviour:\n\n* :attr:`~ListAdapter.selection`: a list of selected items.\n\n* :attr:`~ListAdapter.selection_mode`: one of 'single', 'multiple' or 'none'.\n\n* :attr:`~ListAdapter.allow_empty_selection`: a boolean. If False, a selection\n  is forced. If True, and only user or programmatic action will change\n  selection, it can be empty.\n\nA :class:`~kivy.adapters.dictadapter.DictAdapter` is a subclass of a\n:class:`~kivy.adapters.listadapter.ListAdapter`. They both dispatch the\n:attr:`~ListAdapter.on_selection_change` event when selection changes.\n\n.. versionchanged:: 1.6.0\n    Added data = ListProperty([]), which was proably inadvertently deleted at\n    some point. This means that whenever data changes an update will fire,\n    instead of having to reset the data object (Adapter has data defined as\n    an ObjectProperty, so we need to reset it here to ListProperty). See also\n    DictAdapter and its set of data = DictProperty().\n\n'''\n\n__all__ = ('ListAdapter', )\n\nimport inspect\nfrom kivy.event import EventDispatcher\nfrom kivy.adapters.adapter import Adapter\nfrom kivy.adapters.models import SelectableDataItem\nfrom kivy.properties import ListProperty\nfrom kivy.properties import DictProperty\nfrom kivy.properties import BooleanProperty\nfrom kivy.properties import OptionProperty\nfrom kivy.properties import NumericProperty\nfrom kivy.lang import Builder\n\n\nclass ListAdapter(Adapter, EventDispatcher):\n    '''\n    A base class for adapters interfacing with lists, dictionaries or other\n    collection type data, adding selection, view creation and management\n    functonality.\n    '''\n\n    data = ListProperty([])\n    '''The data list property is redefined here, overriding its definition as\n    an ObjectProperty in the Adapter class. We bind to data so that any\n    changes will trigger updates. See also how the\n    :class:`~kivy.adapters.DictAdapter` redefines data as a\n    :class:`~kivy.properties.DictProperty`.\n\n    :attr:`data` is a :class:`~kivy.properties.ListProperty` and defaults\n    to [].\n    '''\n\n    selection = ListProperty([])\n    '''The selection list property is the container for selected items.\n\n    :attr:`selection` is a :class:`~kivy.properties.ListProperty` and defaults\n    to [].\n    '''\n\n    selection_mode = OptionProperty('single',\n            options=('none', 'single', 'multiple'))\n    '''The selection_mode is a string and can be set to one of the following\n    values:\n\n       * 'none': use the list as a simple list (no select action). This option\n         is here so that selection can be turned off, momentarily or\n         permanently, for an existing list adapter.\n         A :class:`~kivy.adapters.listadapter.ListAdapter` is not meant to be\n         used as a primary no-selection list adapter. Use a\n         :class:`~kivy.adapters.simplelistadapter.SimpleListAdapter` for that.\n\n       * 'single': multi-touch/click ignored. Single item selection only.\n\n       * 'multiple': multi-touch / incremental addition to selection allowed;\n         may be limited to a count by setting the\n         :attr:`~ListAdapter.selection_limit`.\n\n    :attr:`selection_mode` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to 'single'.\n    '''\n\n    propagate_selection_to_data = BooleanProperty(False)\n    '''Normally, data items are not selected/deselected because the data items\n    might not have an is_selected boolean property -- only the item view for a\n    given data item is selected/deselected as part of the maintained selection\n    list. However, if the data items do have an is_selected property, or if\n    they mix in :class:`~kivy.adapters.models.SelectableDataItem`, the\n    selection machinery can propagate selection to data items. This can be\n    useful for storing selection state in a local database or backend database\n    for maintaining state in game play or other similar scenarios. It is a\n    convenience function.\n\n    To propagate selection or not?\n\n    Consider a shopping list application for shopping for fruits at the\n    market. The app allows for the selection of fruits to buy for each day of\n    the week, presenting seven lists: one for each day of the week. Each list is\n    loaded with all the available fruits, but the selection for each is a\n    subset. There is only one set of fruit data shared between the lists, so\n    it would not make sense to propagate selection to the data because\n    selection in any of the seven lists would clash and mix with that of the\n    others.\n\n    However, consider a game that uses the same fruits data for selecting\n    fruits available for fruit-tossing. A given round of play could have a\n    full fruits list, with fruits available for tossing shown selected. If the\n    game is saved and rerun, the full fruits list, with selection marked on\n    each item, would be reloaded correctly if selection is always propagated to\n    the data. You could accomplish the same functionality by writing code to\n    operate on list selection, but having selection stored in the data\n    ListProperty might prove convenient in some cases.\n\n    .. note::\n\n        This setting should be set to True if you wish to initialize the view\n        with item views already selected.\n\n    :attr:`propagate_selection_to_data` is a\n    :class:`~kivy.properties.BooleanProperty` and defaults to False.\n    '''\n\n    allow_empty_selection = BooleanProperty(True)\n    '''The allow_empty_selection may be used for cascading selection between\n    several list views, or between a list view and an observing view. Such\n    automatic maintenance of the selection is important for all but simple\n    list displays. Set allow_empty_selection to False and the selection is\n    auto-initialized and always maintained, so any observing views\n    may likewise be updated to stay in sync.\n\n    :attr:`allow_empty_selection` is a\n    :class:`~kivy.properties.BooleanProperty` and defaults to True.\n    '''\n\n    selection_limit = NumericProperty(-1)\n    '''When the :attr:`~ListAdapter.selection_mode` is 'multiple' and the\n    selection_limit is\n    non-negative, this number will limit the number of selected items. It can\n    be set to 1, which is equivalent to single selection. If selection_limit is\n    not set, the default value is -1, meaning that no limit will be enforced.\n\n    :attr:`selection_limit` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to -1 (no limit).\n    '''\n\n    cached_views = DictProperty({})\n    '''View instances for data items are instantiated and managed by the\n    adapter. Here we maintain a dictionary containing the view\n    instances keyed to the indices in the data.\n\n    This dictionary works as a cache. get_view() only asks for a view from\n    the adapter if one is not already stored for the requested index.\n\n    :attr:`cached_views` is a :class:`~kivy.properties.DictProperty` and\n    defaults to {}.\n    '''\n\n    __events__ = ('on_selection_change', )\n\n    def __init__(self, **kwargs):\n        super(ListAdapter, self).__init__(**kwargs)\n\n        self.bind(selection_mode=self.selection_mode_changed,\n                  allow_empty_selection=self.check_for_empty_selection,\n                  data=self.update_for_new_data)\n\n        self.update_for_new_data()\n\n    def delete_cache(self, *args):\n        self.cached_views = {}\n\n    def get_count(self):\n        return len(self.data)\n\n    def get_data_item(self, index):\n        if index < 0 or index >= len(self.data):\n            return None\n        return self.data[index]\n\n    def selection_mode_changed(self, *args):\n        if self.selection_mode == 'none':\n            for selected_view in self.selection:\n                self.deselect_item_view(selected_view)\n        else:\n            self.check_for_empty_selection()\n\n    def get_view(self, index):\n        if index in self.cached_views:\n            return self.cached_views[index]\n        item_view = self.create_view(index)\n        if item_view:\n            self.cached_views[index] = item_view\n        return item_view\n\n    def create_view(self, index):\n        '''This method is more complicated than the ones in the\n        :class:`~kivy.adapters.adapter.Adapter` and\n        :class:`~kivy.adapters.simplelistadapter.SimpleListAdapter` classes\n        because here we create bindings for the data items and their children\n        back to the *self.handle_selection()* event. We also perform\n        other selection-related tasks to keep item views in sync with the data.\n        '''\n        item = self.get_data_item(index)\n        if item is None:\n            return None\n\n        item_args = self.args_converter(index, item)\n\n        item_args['index'] = index\n\n        cls = self.get_cls()\n        if cls:\n            view_instance = cls(**item_args)\n        else:\n            view_instance = Builder.template(self.template, **item_args)\n\n        if self.propagate_selection_to_data:\n            # The data item must be a subclass of SelectableDataItem, or must\n            # have an is_selected boolean or function, so it has is_selected\n            # available. If is_selected is unavailable on the data item, an\n            # exception is raised.\n            #\n            if isinstance(item, SelectableDataItem):\n                if item.is_selected:\n                    self.handle_selection(view_instance)\n            elif type(item) == dict and 'is_selected' in item:\n                if item['is_selected']:\n                    self.handle_selection(view_instance)\n            elif hasattr(item, 'is_selected'):\n                if (inspect.isfunction(item.is_selected)\n                        or inspect.ismethod(item.is_selected)):\n                    if item.is_selected():\n                        self.handle_selection(view_instance)\n                else:\n                    if item.is_selected:\n                        self.handle_selection(view_instance)\n            else:\n                msg = \"ListAdapter: unselectable data item for {0}\"\n                raise Exception(msg.format(index))\n\n        view_instance.bind(on_release=self.handle_selection)\n\n        for child in view_instance.children:\n            child.bind(on_release=self.handle_selection)\n\n        return view_instance\n\n    def on_selection_change(self, *args):\n        '''on_selection_change() is the default handler for the\n        on_selection_change event. You can bind to this event to get notified\n        of selection changes.\n\n        :Parameters:\n            adapter: :class:`~ListAdapter` or subclass\n                The instance of the list adapter where the selection changed.\n                Use the adapters :attr:`selection` property to see what has been\n                selected.\n        '''\n        pass\n\n    def handle_selection(self, view, hold_dispatch=False, *args):\n        if view not in self.selection:\n            if self.selection_mode in ['none', 'single'] and \\\n                    len(self.selection) > 0:\n                for selected_view in self.selection:\n                    self.deselect_item_view(selected_view)\n            if self.selection_mode != 'none':\n                if self.selection_mode == 'multiple':\n                    if self.allow_empty_selection:\n                        # If < 0, selection_limit is not active.\n                        if self.selection_limit < 0:\n                            self.select_item_view(view)\n                        else:\n                            if len(self.selection) < self.selection_limit:\n                                self.select_item_view(view)\n                    else:\n                        self.select_item_view(view)\n                else:\n                    self.select_item_view(view)\n        else:\n            self.deselect_item_view(view)\n            if self.selection_mode != 'none':\n                # If the deselection makes selection empty, the following call\n                # will check allows_empty_selection, and if False, will\n                # select the first item. If view happens to be the first item,\n                # this will be a reselection, and the user will notice no\n                # change, except perhaps a flicker.\n                #\n                self.check_for_empty_selection()\n\n        if not hold_dispatch:\n            self.dispatch('on_selection_change')\n\n    def select_data_item(self, item):\n        self.set_data_item_selection(item, True)\n\n    def deselect_data_item(self, item):\n        self.set_data_item_selection(item, False)\n\n    def set_data_item_selection(self, item, value):\n        if isinstance(item, SelectableDataItem):\n            item.is_selected = value\n        elif type(item) == dict:\n            item['is_selected'] = value\n        elif hasattr(item, 'is_selected'):\n            if (inspect.isfunction(item.is_selected)\n                    or inspect.ismethod(item.is_selected)):\n                item.is_selected()\n            else:\n                item.is_selected = value\n\n    def select_item_view(self, view):\n        view.select()\n        view.is_selected = True\n        self.selection.append(view)\n\n        # [TODO] sibling selection for composite items\n        #        Needed? Or handled from parent?\n        #        (avoid circular, redundant selection)\n        #if hasattr(view, 'parent') and hasattr(view.parent, 'children'):\n         #siblings = [child for child in view.parent.children if child != view]\n         #for sibling in siblings:\n             #if hasattr(sibling, 'select'):\n                 #sibling.select()\n\n        if self.propagate_selection_to_data:\n            data_item = self.get_data_item(view.index)\n            self.select_data_item(data_item)\n\n    def select_list(self, view_list, extend=True):\n        '''The select call is made for the items in the provided view_list.\n\n        Arguments:\n\n            view_list: the list of item views to become the new selection, or\n            to add to the existing selection\n\n            extend: boolean for whether or not to extend the existing list\n        '''\n        if not extend:\n            self.selection = []\n\n        for view in view_list:\n            self.handle_selection(view, hold_dispatch=True)\n\n        self.dispatch('on_selection_change')\n\n    def deselect_item_view(self, view):\n        view.deselect()\n        view.is_selected = False\n        self.selection.remove(view)\n\n        # [TODO] sibling deselection for composite items\n        #        Needed? Or handled from parent?\n        #        (avoid circular, redundant selection)\n        #if hasattr(view, 'parent') and hasattr(view.parent, 'children'):\n         #siblings = [child for child in view.parent.children if child != view]\n         #for sibling in siblings:\n             #if hasattr(sibling, 'deselect'):\n                 #sibling.deselect()\n\n        if self.propagate_selection_to_data:\n            item = self.get_data_item(view.index)\n            self.deselect_data_item(item)\n\n    def deselect_list(self, l):\n        for view in l:\n            self.handle_selection(view, hold_dispatch=True)\n\n        self.dispatch('on_selection_change')\n\n    # [TODO] Could easily add select_all() and deselect_all().\n\n    def update_for_new_data(self, *args):\n        self.delete_cache()\n        self.initialize_selection()\n\n    def initialize_selection(self, *args):\n        if len(self.selection) > 0:\n            self.selection = []\n            self.dispatch('on_selection_change')\n\n        self.check_for_empty_selection()\n\n    def check_for_empty_selection(self, *args):\n        if not self.allow_empty_selection:\n            if len(self.selection) == 0:\n                # Select the first item if we have it.\n                v = self.get_view(0)\n                if v is not None:\n                    self.handle_selection(v)\n\n    # [TODO] Also make methods for scroll_to_sel_start, scroll_to_sel_end,\n    #        scroll_to_sel_middle.\n\n    def trim_left_of_sel(self, *args):\n        '''Cut list items with indices in sorted_keys that are less than the\n        index of the first selected item if there is a selection.\n        '''\n        if len(self.selection) > 0:\n            first_sel_index = min([sel.index for sel in self.selection])\n            self.data = self.data[first_sel_index:]\n\n    def trim_right_of_sel(self, *args):\n        '''Cut list items with indices in sorted_keys that are greater than\n        the index of the last selected item if there is a selection.\n        '''\n        if len(self.selection) > 0:\n            last_sel_index = max([sel.index for sel in self.selection])\n            print('last_sel_index', last_sel_index)\n            self.data = self.data[:last_sel_index + 1]\n\n    def trim_to_sel(self, *args):\n        '''Cut list items with indices in sorted_keys that are less than or\n        greater than the index of the last selected item if there is a\n        selection. This preserves intervening list items within the selected\n        range.\n        '''\n        if len(self.selection) > 0:\n            sel_indices = [sel.index for sel in self.selection]\n            first_sel_index = min(sel_indices)\n            last_sel_index = max(sel_indices)\n            self.data = self.data[first_sel_index:last_sel_index + 1]\n\n    def cut_to_sel(self, *args):\n        '''Same as trim_to_sel, but intervening list items within the selected\n        range are also cut, leaving only list items that are selected.\n        '''\n        if len(self.selection) > 0:\n            self.data = self.selection\n"
  },
  {
    "path": "tickeys/kivy/adapters/models.py",
    "content": "'''\nSelectableDataItem\n==================\n\n.. versionadded:: 1.5\n\n.. warning::\n\n    This code is still experimental, and its API is subject to change in a\n    future version.\n\nData Models\n-----------\n\nKivy is open about the type of data used in applications built with\nthe system. However, base classes are sometimes needed to ensure data conforms\nto the requirements of some parts of the system.\n\nA :class:`SelectableDataItem` is a basic Python data model class that can be\nused as a mixin to build data objects that are compatible with Kivy's\n:class:`~kivy.adapters.adapter.Adapter`\nand selection system and which work with views such as a\n:class:`~kivy.uix.listview.ListView`. A boolean *is_selected*\nproperty a requirement.\n\nThe default operation of the selection system is to not propogate selection in\nviews such as ListView to the underlying data: selection is by default a\nview-only operation. However, in some cases, it is useful to propogate\nselection to the actual data items.\n\nYou may, of course, build your own Python data model system as the backend for\na Kivy application. For instance, to use the `Google App Engine Data Modeling\n<https://cloud.google.com/appengine/docs/python/datastore/datamodeling>`_\nsystem with Kivy, you could define your class as follows::\n\n    from google.appengine.ext import db\n\n    class MySelectableDataItem(db.Model):\n        # ... other properties\n        is_selected = db.BooleanProperty()\n\nIt is easy to build such a class with plain Python.\n\n'''\n\n__all__ = ('SelectableDataItem', )\n\n\nclass SelectableDataItem(object):\n    '''\n    A mixin class containing requirements for selection operations.\n    '''\n\n    def __init__(self, **kwargs):\n        super(SelectableDataItem, self).__init__()\n\n        self._is_selected = kwargs.get('is_selected', False)\n\n    @property\n    def is_selected(self):\n        \"\"\"A boolean property indicating whether the data item is selected or\n        not.\"\"\"\n        return self._is_selected\n\n    @is_selected.setter\n    def is_selected(self, value):\n        self._is_selected = value\n"
  },
  {
    "path": "tickeys/kivy/adapters/simplelistadapter.py",
    "content": "'''\nSimpleListAdapter\n=================\n\n.. versionadded:: 1.5\n\n.. warning::\n\n    This code is still experimental, and its API is subject to change in a\n    future version.\n\nThe :class:`~kivy.adapters.simplelistadapter.SimpleListAdapter` is used for\nbasic lists. For example, it can be used for displaying a list of read-only\nstrings that do not require user interaction.\n\n'''\n\n__all__ = ('SimpleListAdapter', )\n\nfrom kivy.adapters.adapter import Adapter\nfrom kivy.properties import ListProperty\nfrom kivy.lang import Builder\n\n\nclass SimpleListAdapter(Adapter):\n    '''A :class:`~kivy.adapters.simplelistadapter.SimpleListAdapter` is an\n    adapter around a Python list.\n\n    From :class:`~kivy.adapters.adapter.Adapter`, the\n    :class:`~kivy.adapters.simplelistadapter.ListAdapter` gets cls, template,\n    and args_converter properties.\n    '''\n\n    data = ListProperty([])\n    '''The data list property contains a list of objects (which can be strings)\n    that will be used directly if no args_converter function is provided. If\n    there is an args_converter, the data objects will be passed to it for\n    instantiating the item view class instances.\n\n    :attr:`data` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [].\n    '''\n\n    def __init__(self, **kwargs):\n        if 'data' not in kwargs:\n            raise Exception('list adapter: input must include data argument')\n        if not isinstance(kwargs['data'], list) and \\\n                not isinstance(kwargs['data'], tuple):\n            raise Exception('list adapter: data must be a tuple or list')\n        super(SimpleListAdapter, self).__init__(**kwargs)\n\n    def get_count(self):\n        return len(self.data)\n\n    def get_data_item(self, index):\n        if index < 0 or index >= len(self.data):\n            return None\n        return self.data[index]\n\n    # Returns a view instance for an item.\n    def get_view(self, index):\n        item = self.get_data_item(index)\n\n        if item is None:\n            return None\n\n        item_args = self.args_converter(index, item)\n\n        cls = self.get_cls()\n        if cls:\n            instance = cls(**item_args)\n            return instance\n        else:\n            return Builder.template(self.template, **item_args)\n"
  },
  {
    "path": "tickeys/kivy/animation.py",
    "content": "'''\nAnimation\n=========\n\n:class:`Animation` and :class:`AnimationTransition` are used to animate\n:class:`~kivy.uix.widget.Widget` properties. You must specify at least a\nproperty name and target value. To use an Animation, follow these steps:\n\n    * Setup an Animation object\n    * Use the Animation object on a Widget\n\nSimple animation\n----------------\n\nTo animate a Widget's x or y position, simply specify the target x/y values\nwhere you want the widget positioned at the end of the animation::\n\n    anim = Animation(x=100, y=100)\n    anim.start(widget)\n\nThe animation will last for 1 second unless :attr:`duration` is specified.\nWhen anim.start() is called, the Widget will move smoothly from the current\nx/y position to (100, 100).\n\nMultiple properties and transitions\n-----------------------------------\n\nYou can animate multiple properties and use built-in or custom transition\nfunctions using :attr:`transition` (or the `t=` shortcut). For example,\nto animate the position and size using the 'in_quad' transition::\n\n    anim = Animation(x=50, size=(80, 80), t='in_quad')\n    anim.start(widget)\n\nNote that the `t=` parameter can be the string name of a method in the\n:class:`AnimationTransition` class or your own animation function.\n\nSequential animation\n--------------------\n\nTo join animations sequentially, use the '+' operator. The following example\nwill animate to x=50 over 1 second, then animate the size to (80, 80) over the\nnext two seconds::\n\n    anim = Animation(x=50) + Animation(size=(80, 80), duration=2.)\n    anim.start(widget)\n\nParallel animation\n------------------\n\nTo join animations in parallel, use the '&' operator. The following example\nwill animate the position to (80, 10) over 1 second, whilst in parallel\nanimating the size to (800, 800)::\n\n    anim = Animation(pos=(80, 10))\n    anim &= Animation(size=(800, 800), duration=2.)\n    anim.start(widget)\n\nKeep in mind that creating overlapping animations on the same property may have\nunexpected results. If you want to apply multiple animations to the same\nproperty, you should either schedule them sequentially (via the '+' operator or\nusing the *on_complete* callback) or cancel previous animations using the\n:attr:`~Animation.cancel_all` method.\n\nRepeating animation\n-------------------\n\n.. versionadded:: 1.8.0\n\n.. note::\n    This is currently only implemented for 'Sequence' animations.\n\nTo set an animation to repeat, simply set the :attr:`Sequence.repeat`\nproperty to `True`::\n\n    anim = Animation(...) + Animation(...)\n    anim.repeat = True\n    anim.start(widget)\n\nFor flow control of animations such as stopping and cancelling, use the methods\nalready in place in the animation module.\n'''\n\n__all__ = ('Animation', 'AnimationTransition')\n\nfrom math import sqrt, cos, sin, pi\nfrom kivy.event import EventDispatcher\nfrom kivy.clock import Clock\nfrom kivy.compat import string_types, iterkeys\nfrom kivy.weakproxy import WeakProxy\n\n\nclass Animation(EventDispatcher):\n    '''Create an animation definition that can be used to animate a Widget.\n\n    :Parameters:\n        `duration` or `d`: float, defaults to 1.\n            Duration of the animation, in seconds.\n        `transition` or `t`: str or func\n            Transition function for animate properties. It can be the name of a\n            method from :class:`AnimationTransition`.\n        `step` or `s`: float\n            Step in milliseconds of the animation. Defaults to 1 / 60.\n\n    :Events:\n        `on_start`: widget\n            Fired when the animation is started on a widget.\n        `on_complete`: widget\n            Fired when the animation is completed or stopped on a widget.\n        `on_progress`: widget, progression\n            Fired when the progression of the animation is changing.\n\n    .. versionchanged:: 1.4.0\n        Added s/step parameter.\n\n    '''\n\n    _instances = set()\n\n    __events__ = ('on_start', 'on_progress', 'on_complete')\n\n    def __init__(self, **kw):\n        super(Animation, self).__init__(**kw)\n\n        # Initialize\n        self._clock_installed = False\n        self._duration = kw.get('d', kw.get('duration', 1.))\n        self._transition = kw.get('t', kw.get('transition', 'linear'))\n        self._step = kw.get('s', kw.get('step', 1. / 60.))\n        if isinstance(self._transition, string_types):\n            self._transition = getattr(AnimationTransition, self._transition)\n        for key in ('d', 't', 's', 'step', 'duration', 'transition'):\n            kw.pop(key, None)\n        self._animated_properties = kw\n        self._widgets = {}\n\n    @property\n    def duration(self):\n        '''Return the duration of the animation.\n        '''\n        return self._duration\n\n    @property\n    def transition(self):\n        '''Return the transition of the animation.\n        '''\n        return self._transition\n\n    @property\n    def animated_properties(self):\n        '''Return the properties used to animate.\n        '''\n        return self._animated_properties\n\n    @staticmethod\n    def stop_all(widget, *largs):\n        '''Stop all animations that concern a specific widget / list of\n        properties.\n\n        Example::\n\n            anim = Animation(x=50)\n            anim.start(widget)\n\n            # and later\n            Animation.stop_all(widget, 'x')\n        '''\n        if len(largs):\n            for animation in list(Animation._instances):\n                for x in largs:\n                    animation.stop_property(widget, x)\n        else:\n            for animation in set(Animation._instances):\n                animation.stop(widget)\n\n    @staticmethod\n    def cancel_all(widget, *largs):\n        '''Cancel all animations that concern a specific widget / list of\n        properties. See :attr:`cancel`.\n\n        Example::\n\n            anim = Animation(x=50)\n            anim.start(widget)\n\n            # and later\n            Animation.cancel_all(widget, 'x')\n\n        .. versionadded:: 1.4.0\n        '''\n        if len(largs):\n            for animation in list(Animation._instances):\n                for x in largs:\n                    animation.cancel_property(widget, x)\n        else:\n            for animation in set(Animation._instances):\n                animation.cancel(widget)\n\n    def start(self, widget):\n        '''Start the animation on a widget.\n        '''\n        self.stop(widget)\n        self._initialize(widget)\n        self._register()\n        self.dispatch('on_start', widget)\n\n    def stop(self, widget):\n        '''Stop the animation previously applied to a widget, triggering the\n        `on_complete` event.'''\n        props = self._widgets.pop(widget.uid, None)\n        if props:\n            self.dispatch('on_complete', widget)\n        self.cancel(widget)\n\n    def cancel(self, widget):\n        '''Cancel the animation previously applied to a widget. Same\n        effect as :attr:`stop`, except the `on_complete` event will\n        *not* be triggered!\n\n        .. versionadded:: 1.4.0\n        '''\n        self._widgets.pop(widget.uid, None)\n        self._clock_uninstall()\n        if not self._widgets:\n            self._unregister()\n\n    def stop_property(self, widget, prop):\n        '''Even if an animation is running, remove a property. It will not be\n        animated futher. If it was the only/last property being animated,\n        the animation will be stopped (see :attr:`stop`).\n        '''\n        props = self._widgets.get(widget.uid, None)\n        if not props:\n            return\n        props['properties'].pop(prop, None)\n\n        # no more properties to animation ? kill the animation.\n        if not props['properties']:\n            self.stop(widget)\n\n    def cancel_property(self, widget, prop):\n        '''Even if an animation is running, remove a property. It will not be\n        animated further. If it was the only/last property being animated,\n        the animation will be canceled (see :attr:`cancel`)\n\n        .. versionadded:: 1.4.0\n        '''\n        props = self._widgets.get(widget.uid, None)\n        if not props:\n            return\n        props['properties'].pop(prop, None)\n\n        # no more properties to animation ? kill the animation.\n        if not props['properties']:\n            self.cancel(widget)\n\n    def have_properties_to_animate(self, widget):\n        '''Return True if a widget still has properties to animate.\n\n        .. versionadded:: 1.8.0\n        '''\n        props = self._widgets.get(widget.uid, None)\n        if props and props['properties']:\n            return True\n\n    #\n    # Private\n    #\n    def _register(self):\n        Animation._instances.add(self)\n\n    def _unregister(self):\n        if self in Animation._instances:\n            Animation._instances.remove(self)\n\n    def _initialize(self, widget):\n        d = self._widgets[widget.uid] = {\n            'widget': widget,\n            'properties': {},\n            'time': None}\n\n        # get current values\n        p = d['properties']\n        for key, value in self._animated_properties.items():\n            original_value = getattr(widget, key)\n            if isinstance(original_value, (tuple, list)):\n                original_value = original_value[:]\n            elif isinstance(original_value, dict):\n                original_value = original_value.copy()\n            p[key] = (original_value, value)\n\n        # install clock\n        self._clock_install()\n\n    def _clock_install(self):\n        if self._clock_installed:\n            return\n        Clock.schedule_interval(self._update, self._step)\n        self._clock_installed = True\n\n    def _clock_uninstall(self):\n        if self._widgets or not self._clock_installed:\n            return\n        self._clock_installed = False\n        Clock.unschedule(self._update)\n\n    def _update(self, dt):\n        widgets = self._widgets\n        transition = self._transition\n        calculate = self._calculate\n        for uid in list(widgets.keys())[:]:\n            anim = widgets[uid]\n            widget = anim['widget']\n\n            if isinstance(widget, WeakProxy) and not len(dir(widget)):\n                # empty proxy, widget is gone. ref: #2458\n                del widgets[uid]\n                continue\n\n            if anim['time'] is None:\n                anim['time'] = 0.\n            else:\n                anim['time'] += dt\n\n            # calculate progression\n            if self._duration:\n                progress = min(1., anim['time'] / self._duration)\n            else:\n                progress = 1\n            t = transition(progress)\n\n            # apply progression on widget\n            for key, values in anim['properties'].items():\n                a, b = values\n                value = calculate(a, b, t)\n                setattr(widget, key, value)\n\n            self.dispatch('on_progress', widget, progress)\n\n            # time to stop ?\n            if progress >= 1.:\n                self.stop(widget)\n\n    def _calculate(self, a, b, t):\n        _calculate = self._calculate\n        if isinstance(a, list) or isinstance(a, tuple):\n            if isinstance(a, list):\n                tp = list\n            else:\n                tp = tuple\n            return tp([_calculate(a[x], b[x], t) for x in range(len(a))])\n        elif isinstance(a, dict):\n            d = {}\n            for x in iterkeys(a):\n                if x not in b:\n                    # User requested to animate only part of the dict.\n                    # Copy the rest\n                    d[x] = a[x]\n                else:\n                    d[x] = _calculate(a[x], b[x], t)\n            return d\n        else:\n            return (a * (1. - t)) + (b * t)\n\n    #\n    # Default handlers\n    #\n    def on_start(self, widget):\n        pass\n\n    def on_progress(self, widget, progress):\n        pass\n\n    def on_complete(self, widget):\n        pass\n\n    def __add__(self, animation):\n        return Sequence(self, animation)\n\n    def __and__(self, animation):\n        return Parallel(self, animation)\n\n\nclass Sequence(Animation):\n\n    def __init__(self, anim1, anim2):\n        super(Sequence, self).__init__()\n\n        #: Repeat the sequence. See 'Repeating animation' in the header\n        #: documentation.\n        self.repeat = False\n\n        self.anim1 = anim1\n        self.anim2 = anim2\n\n        self.anim1.bind(on_start=self.on_anim1_start,\n                        on_progress=self.on_anim1_progress)\n        self.anim2.bind(on_complete=self.on_anim2_complete,\n                        on_progress=self.on_anim2_progress)\n\n    @property\n    def duration(self):\n        return self.anim1.duration + self.anim2.duration\n\n    def start(self, widget):\n        self.stop(widget)\n        self._widgets[widget.uid] = True\n        self._register()\n        self.anim1.start(widget)\n        self.anim1.bind(on_complete=self.on_anim1_complete)\n\n    def stop(self, widget):\n        self.anim1.stop(widget)\n        self.anim2.stop(widget)\n        props = self._widgets.pop(widget.uid, None)\n        if props:\n            self.dispatch('on_complete', widget)\n        super(Sequence, self).cancel(widget)\n\n    def stop_property(self, widget, prop):\n        self.anim1.stop_property(widget, prop)\n        self.anim2.stop_property(widget, prop)\n        if (not self.anim1.have_properties_to_animate(widget) and\n                not self.anim2.have_properties_to_animate(widget)):\n            self.stop(widget)\n\n    def cancel(self, widget):\n        self.anim1.cancel(widget)\n        self.anim2.cancel(widget)\n        super(Sequence, self).cancel(widget)\n\n    def on_anim1_start(self, instance, widget):\n        self.dispatch('on_start', widget)\n\n    def on_anim1_complete(self, instance, widget):\n        self.anim1.unbind(on_complete=self.on_anim1_complete)\n        self.anim2.start(widget)\n\n    def on_anim1_progress(self, instance, widget, progress):\n        self.dispatch('on_progress', widget, progress / 2.)\n\n    def on_anim2_complete(self, instance, widget):\n        '''Repeating logic used with boolean variable \"repeat\".\n\n        .. versionadded:: 1.7.1\n        '''\n        if self.repeat:\n            self.anim1.start(widget)\n            self.anim1.bind(on_complete=self.on_anim1_complete)\n        else:\n            self.dispatch('on_complete', widget)\n\n    def on_anim2_progress(self, instance, widget, progress):\n        self.dispatch('on_progress', widget, .5 + progress / 2.)\n\n\nclass Parallel(Animation):\n\n    def __init__(self, anim1, anim2):\n        super(Parallel, self).__init__()\n        self.anim1 = anim1\n        self.anim2 = anim2\n\n        self.anim1.bind(on_complete=self.on_anim_complete)\n        self.anim2.bind(on_complete=self.on_anim_complete)\n\n    @property\n    def duration(self):\n        return max(self.anim1.duration, self.anim2.duration)\n\n    def start(self, widget):\n        self.stop(widget)\n        self.anim1.start(widget)\n        self.anim2.start(widget)\n        self._widgets[widget.uid] = {'complete': 0}\n        self._register()\n        self.dispatch('on_start', widget)\n\n    def stop(self, widget):\n        self.anim1.stop(widget)\n        self.anim2.stop(widget)\n        props = self._widgets.pop(widget.uid, None)\n        if props:\n            self.dispatch('on_complete', widget)\n        super(Parallel, self).cancel(widget)\n\n    def stop_property(self, widget, prop):\n        self.anim1.stop_property(widget, prop)\n        self.anim2.stop_property(widget, prop)\n        if (not self.anim1.have_properties_to_animate(widget) and\n                not self.anim2.have_properties_to_animate(widget)):\n            self.stop(widget)\n\n    def cancel(self, widget):\n        self.anim1.cancel(widget)\n        self.anim2.cancel(widget)\n        super(Parallel, self).cancel(widget)\n\n    def on_anim_complete(self, instance, widget):\n        self._widgets[widget.uid]['complete'] += 1\n        if self._widgets[widget.uid]['complete'] == 2:\n            self.stop(widget)\n\n\nclass AnimationTransition(object):\n    '''Collection of animation functions to be used with the Animation object.\n    Easing Functions ported to Kivy from the Clutter Project\n    http://www.clutter-project.org/docs/clutter/stable/ClutterAlpha.html\n\n    The `progress` parameter in each animation function is in the range 0-1.\n    '''\n\n    @staticmethod\n    def linear(progress):\n        '''.. image:: images/anim_linear.png'''\n        return progress\n\n    @staticmethod\n    def in_quad(progress):\n        '''.. image:: images/anim_in_quad.png\n        '''\n        return progress * progress\n\n    @staticmethod\n    def out_quad(progress):\n        '''.. image:: images/anim_out_quad.png\n        '''\n        return -1.0 * progress * (progress - 2.0)\n\n    @staticmethod\n    def in_out_quad(progress):\n        '''.. image:: images/anim_in_out_quad.png\n        '''\n        p = progress * 2\n        if p < 1:\n            return 0.5 * p * p\n        p -= 1.0\n        return -0.5 * (p * (p - 2.0) - 1.0)\n\n    @staticmethod\n    def in_cubic(progress):\n        '''.. image:: images/anim_in_cubic.png\n        '''\n        return progress * progress * progress\n\n    @staticmethod\n    def out_cubic(progress):\n        '''.. image:: images/anim_out_cubic.png\n        '''\n        p = progress - 1.0\n        return p * p * p + 1.0\n\n    @staticmethod\n    def in_out_cubic(progress):\n        '''.. image:: images/anim_in_out_cubic.png\n        '''\n        p = progress * 2\n        if p < 1:\n            return 0.5 * p * p * p\n        p -= 2\n        return 0.5 * (p * p * p + 2.0)\n\n    @staticmethod\n    def in_quart(progress):\n        '''.. image:: images/anim_in_quart.png\n        '''\n        return progress * progress * progress * progress\n\n    @staticmethod\n    def out_quart(progress):\n        '''.. image:: images/anim_out_quart.png\n        '''\n        p = progress - 1.0\n        return -1.0 * (p * p * p * p - 1.0)\n\n    @staticmethod\n    def in_out_quart(progress):\n        '''.. image:: images/anim_in_out_quart.png\n        '''\n        p = progress * 2\n        if p < 1:\n            return 0.5 * p * p * p * p\n        p -= 2\n        return -0.5 * (p * p * p * p - 2.0)\n\n    @staticmethod\n    def in_quint(progress):\n        '''.. image:: images/anim_in_quint.png\n        '''\n        return progress * progress * progress * progress * progress\n\n    @staticmethod\n    def out_quint(progress):\n        '''.. image:: images/anim_out_quint.png\n        '''\n        p = progress - 1.0\n        return p * p * p * p * p + 1.0\n\n    @staticmethod\n    def in_out_quint(progress):\n        '''.. image:: images/anim_in_out_quint.png\n        '''\n        p = progress * 2\n        if p < 1:\n            return 0.5 * p * p * p * p * p\n        p -= 2.0\n        return 0.5 * (p * p * p * p * p + 2.0)\n\n    @staticmethod\n    def in_sine(progress):\n        '''.. image:: images/anim_in_sine.png\n        '''\n        return -1.0 * cos(progress * (pi / 2.0)) + 1.0\n\n    @staticmethod\n    def out_sine(progress):\n        '''.. image:: images/anim_out_sine.png\n        '''\n        return sin(progress * (pi / 2.0))\n\n    @staticmethod\n    def in_out_sine(progress):\n        '''.. image:: images/anim_in_out_sine.png\n        '''\n        return -0.5 * (cos(pi * progress) - 1.0)\n\n    @staticmethod\n    def in_expo(progress):\n        '''.. image:: images/anim_in_expo.png\n        '''\n        if progress == 0:\n            return 0.0\n        return pow(2, 10 * (progress - 1.0))\n\n    @staticmethod\n    def out_expo(progress):\n        '''.. image:: images/anim_out_expo.png\n        '''\n        if progress == 1.0:\n            return 1.0\n        return -pow(2, -10 * progress) + 1.0\n\n    @staticmethod\n    def in_out_expo(progress):\n        '''.. image:: images/anim_in_out_expo.png\n        '''\n        if progress == 0:\n            return 0.0\n        if progress == 1.:\n            return 1.0\n        p = progress * 2\n        if p < 1:\n            return 0.5 * pow(2, 10 * (p - 1.0))\n        p -= 1.0\n        return 0.5 * (-pow(2, -10 * p) + 2.0)\n\n    @staticmethod\n    def in_circ(progress):\n        '''.. image:: images/anim_in_circ.png\n        '''\n        return -1.0 * (sqrt(1.0 - progress * progress) - 1.0)\n\n    @staticmethod\n    def out_circ(progress):\n        '''.. image:: images/anim_out_circ.png\n        '''\n        p = progress - 1.0\n        return sqrt(1.0 - p * p)\n\n    @staticmethod\n    def in_out_circ(progress):\n        '''.. image:: images/anim_in_out_circ.png\n        '''\n        p = progress * 2\n        if p < 1:\n            return -0.5 * (sqrt(1.0 - p * p) - 1.0)\n        p -= 2.0\n        return 0.5 * (sqrt(1.0 - p * p) + 1.0)\n\n    @staticmethod\n    def in_elastic(progress):\n        '''.. image:: images/anim_in_elastic.png\n        '''\n        p = .3\n        s = p / 4.0\n        q = progress\n        if q == 1:\n            return 1.0\n        q -= 1.0\n        return -(pow(2, 10 * q) * sin((q - s) * (2 * pi) / p))\n\n    @staticmethod\n    def out_elastic(progress):\n        '''.. image:: images/anim_out_elastic.png\n        '''\n        p = .3\n        s = p / 4.0\n        q = progress\n        if q == 1:\n            return 1.0\n        return pow(2, -10 * q) * sin((q - s) * (2 * pi) / p) + 1.0\n\n    @staticmethod\n    def in_out_elastic(progress):\n        '''.. image:: images/anim_in_out_elastic.png\n        '''\n        p = .3 * 1.5\n        s = p / 4.0\n        q = progress * 2\n        if q == 2:\n            return 1.0\n        if q < 1:\n            q -= 1.0\n            return -.5 * (pow(2, 10 * q) * sin((q - s) * (2.0 * pi) / p))\n        else:\n            q -= 1.0\n            return pow(2, -10 * q) * sin((q - s) * (2.0 * pi) / p) * .5 + 1.0\n\n    @staticmethod\n    def in_back(progress):\n        '''.. image:: images/anim_in_back.png\n        '''\n        return progress * progress * ((1.70158 + 1.0) * progress - 1.70158)\n\n    @staticmethod\n    def out_back(progress):\n        '''.. image:: images/anim_out_back.png\n        '''\n        p = progress - 1.0\n        return p * p * ((1.70158 + 1) * p + 1.70158) + 1.0\n\n    @staticmethod\n    def in_out_back(progress):\n        '''.. image:: images/anim_in_out_back.png\n        '''\n        p = progress * 2.\n        s = 1.70158 * 1.525\n        if p < 1:\n            return 0.5 * (p * p * ((s + 1.0) * p - s))\n        p -= 2.0\n        return 0.5 * (p * p * ((s + 1.0) * p + s) + 2.0)\n\n    @staticmethod\n    def _out_bounce_internal(t, d):\n        p = t / d\n        if p < (1.0 / 2.75):\n            return 7.5625 * p * p\n        elif p < (2.0 / 2.75):\n            p -= (1.5 / 2.75)\n            return 7.5625 * p * p + .75\n        elif p < (2.5 / 2.75):\n            p -= (2.25 / 2.75)\n            return 7.5625 * p * p + .9375\n        else:\n            p -= (2.625 / 2.75)\n            return 7.5625 * p * p + .984375\n\n    @staticmethod\n    def _in_bounce_internal(t, d):\n        return 1.0 - AnimationTransition._out_bounce_internal(d - t, d)\n\n    @staticmethod\n    def in_bounce(progress):\n        '''.. image:: images/anim_in_bounce.png\n        '''\n        return AnimationTransition._in_bounce_internal(progress, 1.)\n\n    @staticmethod\n    def out_bounce(progress):\n        '''.. image:: images/anim_out_bounce.png\n        '''\n        return AnimationTransition._out_bounce_internal(progress, 1.)\n\n    @staticmethod\n    def in_out_bounce(progress):\n        '''.. image:: images/anim_in_out_bounce.png\n        '''\n        p = progress * 2.\n        if p < 1.:\n            return AnimationTransition._in_bounce_internal(p, 1.) * .5\n        return AnimationTransition._out_bounce_internal(p - 1., 1.) * .5 + .5\n"
  },
  {
    "path": "tickeys/kivy/app.py",
    "content": "'''\nApplication\n===========\n\nThe :class:`App` class is the base for creating Kivy applications.\nThink of it as your main entry point into the Kivy run loop. In most\ncases, you subclass this class and make your own app. You create an\ninstance of your specific app class and then, when you are ready to\nstart the application's life cycle, you call your instance's\n:meth:`App.run` method.\n\n\nCreating an Application\n-----------------------\n\nMethod using build() override\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTo initialize your app with a widget tree, override the :meth:`~App.build`\nmethod in your app class and return the widget tree you constructed.\n\nHere's an example of a very simple application that just shows a button:\n\n.. include:: ../../examples/application/app_with_build.py\n   :literal:\n\nThe file is also available in the examples folder at\n:file:`kivy/examples/application/app_with_build.py`.\n\nHere, no widget tree was constructed (or if you will, a tree with only\nthe root node).\n\n\nMethod using kv file\n~~~~~~~~~~~~~~~~~~~~\n\nYou can also use the :doc:`api-kivy.lang` for creating applications. The\n.kv can contain rules and root widget definitions at the same time. Here\nis the same example as the Button one in a kv file.\n\nContents of 'test.kv':\n\n.. include:: ../../examples/application/test.kv\n   :literal:\n\nContents of 'main.py':\n\n.. include:: ../../examples/application/app_with_kv.py\n   :literal:\n\nSee :file:`kivy/examples/application/app_with_kv.py`.\n\nThe relation between main.py and test.kv is explained in :meth:`App.load_kv`.\n\n\nApplication configuration\n-------------------------\n\n.. versionadded:: 1.0.7\n\nUse the configuration file\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nYour application might want to have its own configuration file. The\n:class:`App` is able to handle an INI file automatically. You add your\nsection/key/value in the :meth:`App.build_config` method by using the `config`\nparameter (which is an instance of :class:`~kivy.config.ConfigParser`)::\n\n    class TestApp(App):\n        def build_config(self, config):\n            config.setdefaults('section1', {\n                'key1': 'value1',\n                'key2': '42'\n            })\n\nAs soon as you add one section in the config, a file is created on the\ndisk and named from the mangled name of your class. \"TestApp\" will give\na config file-name \"test.ini\" with the content::\n\n    [section1]\n    key1 = value1\n    key2 = 42\n\nThe \"test.ini\" will be automatically loaded at runtime and you can access the\nconfiguration in your :meth:`App.build` method::\n\n    class TestApp(App):\n        def build_config(self, config):\n            config.setdefaults('section1', {\n                'key1': 'value1',\n                'key2': '42'\n            })\n\n        def build(self):\n            config = self.config\n            return Label(text='key1 is %s and key2 is %d' % (\n                config.get('section1', 'key1'),\n                config.getint('section1', 'key2')))\n\nCreate a settings panel\n~~~~~~~~~~~~~~~~~~~~~~~\n\nYour application can have a settings panel to let your user configure some of\nyour config tokens. Here is an example done in the KinectViewer example\n(available in the examples directory):\n\n    .. image:: images/app-settings.jpg\n        :align: center\n\nYou can add your own panels of settings by extending\nthe :meth:`App.build_settings` method.\nCheck the :class:`~kivy.uix.settings.Settings` about how to create a panel,\nbecause you need a JSON file / data first.\n\nLet's take as an example the previous snippet of TestApp with custom\nconfig. We could create a JSON like this::\n\n    [\n        { \"type\": \"title\",\n          \"title\": \"Test application\" },\n\n        { \"type\": \"options\",\n          \"title\": \"My first key\",\n          \"desc\": \"Description of my first key\",\n          \"section\": \"section1\",\n          \"key\": \"key1\",\n          \"options\": [\"value1\", \"value2\", \"another value\"] },\n\n        { \"type\": \"numeric\",\n          \"title\": \"My second key\",\n          \"desc\": \"Description of my second key\",\n          \"section\": \"section1\",\n          \"key\": \"key2\" }\n    ]\n\nThen, we can create a panel using this JSON to automatically create all the\noptions and link them to our :attr:`App.config` ConfigParser instance::\n\n    class TestApp(App):\n        # ...\n        def build_settings(self, settings):\n            jsondata = \"\"\"... put the json data here ...\"\"\"\n            settings.add_json_panel('Test application',\n                self.config, data=jsondata)\n\nThat's all! Now you can press F1 (default keystroke) to toggle the\nsettings panel or press the \"settings\" key on your android device. You\ncan manually call :meth:`App.open_settings` and\n:meth:`App.close_settings` if you want to handle this manually. Every\nchange in the panel is automatically saved in the config file.\n\nYou can also use :meth:`App.build_settings` to modify properties of\nthe settings panel. For instance, the default panel has a sidebar for\nswitching between json panels whose width defaults to 200dp. If you'd\nprefer this to be narrower, you could add::\n\n    settings.interface.menu.width = dp(100)\n\nto your :meth:`build_settings` method.\n\nYou might want to know when a config value has been changed by the\nuser in order to adapt or reload your UI. You can then overload the\n:meth:`on_config_change` method::\n\n    class TestApp(App):\n        # ...\n        def on_config_change(self, config, section, key, value):\n            if config is self.config:\n                token = (section, key)\n                if token == ('section1', 'key1'):\n                    print('Our key1 have been changed to', value)\n                elif token == ('section1', 'key2'):\n                    print('Our key2 have been changed to', value)\n\nThe Kivy configuration panel is added by default to the settings\ninstance. If you don't want this panel, you can declare your Application as\nfollows::\n\n    class TestApp(App):\n        use_kivy_settings = False\n        # ...\n\nThis only removes the Kivy panel but does not stop the settings instance\nfrom appearing. If you want to prevent the settings instance from appearing\naltogether, you can do this::\n\n    class TestApp(App):\n        def open_settings(self, *largs):\n            pass\n\nProfiling with on_start and on_stop\n-----------------------------------\n\nIt is often useful to profile python code in order to discover locations to\noptimise. The standard library profilers\n(http://docs.python.org/2/library/profile.html) provides multiple options for\nprofiling code. For profiling the entire program, the natural\napproaches of using profile as a module or profile's run method does not work\nwith Kivy. It is however, possible to use :meth:`App.on_start` and\n:meth:`App.on_stop` methods::\n\n    import cProfile\n\n    class MyApp(App):\n        def on_start(self):\n            self.profile = cProfile.Profile()\n            self.profile.enable()\n\n        def on_stop(self):\n            self.profile.disable()\n            self.profile.dump_stats('myapp.profile')\n\nThis will create a file called `myapp.profile` when you exit your app.\n\nCustomising layout\n------------------\n\nYou can choose different settings widget layouts by setting\n:attr:`App.settings_cls`. By default, this is a\n:class:`~kivy.uix.settings.Settings` class which provides the pictured\nsidebar layout, but you could set it to any of the other layouts\nprovided in :mod:`kivy.uix.settings` or create your own. See the\nmodule documentation for :mod:`kivy.uix.settings` for more\ninformation.\n\nYou can customise how the settings panel is displayed by\noverriding :meth:`App.display_settings` which is called before\ndisplaying the settings panel on the screen. By default, it\nsimply draws the panel on top of the window, but you could modify it\nto (for instance) show the settings in a\n:class:`~kivy.uix.popup.Popup` or add it to your app's\n:class:`~kivy.uix.screenmanager.ScreenManager` if you are using\none. If you do so, you should also modify :meth:`App.close_settings`\nto exit the panel appropriately. For instance, to have the settings\npanel appear in a popup you can do::\n\n    def display_settings(self, settings):\n        try:\n            p = self.settings_popup\n        except AttributeError:\n            self.settings_popup = Popup(content=settings,\n                                        title='Settings',\n                                        size_hint=(0.8, 0.8))\n            p = self.settings_popup\n        if p.content is not settings:\n            p.content = settings\n        p.open()\n\n    def close_settings(self, *args):\n        try:\n            p = self.settings_popup\n            p.dismiss()\n        except AttributeError:\n            pass # Settings popup doesn't exist\n\nFinally, if you want to replace the current settings panel widget, you\ncan remove the internal references to it using\n:meth:`App.destroy_settings`. If you have modified\n:meth:`App.display_settings`, you should be careful to detect if the\nsettings panel has been replaced.\n\nPause mode\n----------\n\n.. versionadded:: 1.1.0\n\nOn tablets and phones, the user can switch at any moment to another\napplication. By default, your application will close and the\n:meth:`App.on_stop` event will be fired.\n\nIf you support Pause mode, when switching to another application, your\napplication will wait indefinitely until the user\nswitches back to your application. There is an issue with OpenGL on Android\ndevices: it is not guaranteed that the OpenGL ES Context will be restored when\nyour app resumes. The mechanism for restoring all the OpenGL data is not yet\nimplemented in Kivy.\n\nThe currently implemented Pause mechanism is:\n\n    #. Kivy checks every frame if Pause mode is activated by the Operating\n       System due to the user switching to another application, a phone\n       shutdown or any other reason.\n    #. :meth:`App.on_pause` is called:\n    #. If False is returned (default case), then :meth:`App.on_stop` is\n       called.\n    #. Otherwise the application will sleep until the OS resumes our App\n    #. When the app is resumed, :meth:`App.on_resume` is called.\n    #. If our app memory has been reclaimed by the OS, then nothing will be\n       called.\n\nHere is a simple example of how on_pause() should be used::\n\n   class TestApp(App):\n\n      def on_pause(self):\n         # Here you can save data if needed\n         return True\n\n      def on_resume(self):\n         # Here you can check if any data needs replacing (usually nothing)\n         pass\n\n.. warning::\n\n    Both `on_pause` and `on_stop` must save important data because after\n    `on_pause` is called, `on_resume` may not be called at all.\n\n'''\n\n__all__ = ('App', )\n\nimport os\nfrom inspect import getfile\nfrom os.path import dirname, join, exists, sep, expanduser, isfile\nfrom kivy.config import ConfigParser\nfrom kivy.base import runTouchApp, stopTouchApp\nfrom kivy.compat import string_types\nfrom kivy.factory import Factory\nfrom kivy.logger import Logger\nfrom kivy.event import EventDispatcher\nfrom kivy.lang import Builder\nfrom kivy.resources import resource_find\nfrom kivy.utils import platform as core_platform\nfrom kivy.uix.widget import Widget\nfrom kivy.properties import ObjectProperty, StringProperty\n\n\nplatform = core_platform\n\n\nclass App(EventDispatcher):\n    ''' Application class, see module documentation for more information.\n\n    :Events:\n        `on_start`:\n            Fired when the application is being started (before the\n            :func:`~kivy.base.runTouchApp` call.\n        `on_stop`:\n            Fired when the application stops.\n        `on_pause`:\n            Fired when the application is paused by the OS.\n        `on_resume`:\n            Fired when the application is resumed from pause by the OS. Beware:\n            you have no guarantee that this event will be fired after the\n            `on_pause` event has been called.\n\n    .. versionchanged:: 1.7.0\n        Parameter `kv_file` added.\n\n    .. versionchanged:: 1.8.0\n        Parameters `kv_file` and `kv_directory` are now properties of App.\n    '''\n\n    title = StringProperty(None)\n    '''\n    Title of your application. You can set this as follows::\n\n        class MyApp(App):\n            def build(self):\n                self.title = 'Hello world'\n\n    .. versionadded:: 1.0.5\n\n    .. versionchanged:: 1.8.0\n        `title` is now a :class:`~kivy.properties.StringProperty`. Don't set the\n        title in the class as previously stated in the documentation.\n\n    .. note::\n\n        For Kivy < 1.8.0, you can set this as follows::\n\n            class MyApp(App):\n                title = 'Custom title'\n\n        If you want to dynamically change the title, you can do::\n\n            from kivy.base import EventLoop\n            EventLoop.window.title = 'New title'\n\n    '''\n\n    icon = StringProperty(None)\n    '''Icon of your application.\n    The icon can be located in the same directory as your main file. You can set\n    this as follows::\n\n        class MyApp(App):\n            def build(self):\n                self.icon = 'myicon.png'\n\n    .. versionadded:: 1.0.5\n\n    .. versionchanged:: 1.8.0\n        `icon` is now a :class:`~kivy.properties.StringProperty`. Don't set the\n        icon in the class as previously stated in the documentation.\n\n    .. note::\n\n        For Kivy prior to 1.8.0, you need to set this as follows::\n\n            class MyApp(App):\n                icon = 'customicon.png'\n\n         Recommended 256x256 or 1024x1024? for GNU/Linux and Mac OSX\n         32x32 for Windows7 or less. <= 256x256 for windows 8\n         256x256 does work (on Windows 8 at least), but is scaled\n         down and doesn't look as good as a 32x32 icon.\n    '''\n\n    use_kivy_settings = True\n    '''.. versionadded:: 1.0.7\n\n    If True, the application settings will also include the Kivy settings. If\n    you don't want the user to change any kivy settings from your settings UI,\n    change this to False.\n    '''\n\n    settings_cls = ObjectProperty(None)\n    '''.. versionadded:: 1.8.0\n\n    The class used to construct the settings panel and\n    the instance passed to :meth:`build_config`. You should\n    use either :class:`~kivy.uix.settings.Settings` or one of the provided\n    subclasses with different layouts\n    (:class:`~kivy.uix.settings.SettingsWithSidebar`,\n    :class:`~kivy.uix.settings.SettingsWithSpinner`,\n    :class:`~kivy.uix.settings.SettingsWithTabbedPanel`,\n    :class:`~kivy.uix.settings.SettingsWithNoMenu`). You can also create your\n    own Settings subclass. See the documentation\n    of :mod:`~kivy.uix.settings.Settings` for more information.\n\n    :attr:`~App.settings_cls` is an :class:`~kivy.properties.ObjectProperty`\n    and defaults to :class:`~kivy.uix.settings.SettingsWithSpinner` which\n    displays settings panels with a spinner to switch between them. If you set a\n    string, the :class:`~kivy.factory.Factory` will be used to resolve the\n    class.\n\n    '''\n\n    kv_directory = StringProperty(None)\n    '''Path of the directory where application kv is stored, defaults to None\n\n    .. versionadded:: 1.8.0\n\n    If a kv_directory is set, it will be used to get the initial kv file. By\n    default, the file is assumed to be in the same directory as the current App\n    definition file.\n    '''\n\n    kv_file = StringProperty(None)\n    '''Filename of the Kv file to load, defaults to None.\n\n    .. versionadded:: 1.8.0\n\n    If a kv_file is set, it will be loaded when the application starts. The\n    loading of the \"default\" kv file will be prevented.\n    '''\n\n    # Return the current running App instance\n    _running_app = None\n\n    __events__ = ('on_start', 'on_stop', 'on_pause', 'on_resume')\n\n    def __init__(self, **kwargs):\n        App._running_app = self\n        self._app_directory = None\n        self._app_name = None\n        self._app_settings = None\n        self._app_window = None\n        super(App, self).__init__(**kwargs)\n        self.built = False\n\n        #: Options passed to the __init__ of the App\n        self.options = kwargs\n\n        #: Returns an instance of the :class:`~kivy.config.ConfigParser` for\n        #: the application configuration. You can use this to query some config\n        #: tokens in the :meth:`build` method.\n        self.config = None\n\n        #: The *root* widget returned by the :meth:`build` method or by the\n        #: :meth:`load_kv` method if the kv file contains a root widget.\n        self.root = None\n\n    def build(self):\n        '''Initializes the application; it will be called only once.\n        If this method returns a widget (tree), it will be used as the root\n        widget and added to the window.\n\n        :return:\n            None or a root :class:`~kivy.uix.widget.Widget` instance\n            if no self.root exists.'''\n\n        if not self.root:\n            return Widget()\n\n    def build_config(self, config):\n        '''.. versionadded:: 1.0.7\n\n        This method is called before the application is initialized to\n        construct your :class:`~kivy.config.ConfigParser` object. This\n        is where you can put any default section / key / value for your\n        config. If anything is set, the configuration will be\n        automatically saved in the file returned by\n        :meth:`get_application_config`.\n\n        :Parameters:\n            `config`: :class:`~kivy.config.ConfigParser`\n                Use this to add default section / key / value items\n\n        '''\n\n    def build_settings(self, settings):\n        '''.. versionadded:: 1.0.7\n\n        This method is called when the user (or you) want to show the\n        application settings. It is called once when the settings panel\n        is first opened, after which the panel is cached. It may be\n        called again if the cached settings panel is removed by\n        :meth:`destroy_settings`.\n\n        You can use this method to add settings panels and to\n        customise the settings widget e.g. by changing the sidebar\n        width. See the module documentation for full details.\n\n        :Parameters:\n            `settings`: :class:`~kivy.uix.settings.Settings`\n                Settings instance for adding panels\n\n        '''\n\n    def load_kv(self, filename=None):\n        '''This method is invoked the first time the app is being run if no\n        widget tree has been constructed before for this app.\n        This method then looks for a matching kv file in the same directory as\n        the file that contains the application class.\n\n        For example, say you have a file named main.py that contains::\n\n            class ShowcaseApp(App):\n                pass\n\n        This method will search for a file named `showcase.kv` in\n        the directory that contains main.py. The name of the kv file has to be\n        the lowercase name of the class, without the 'App' postfix at the end\n        if it exists.\n\n        You can define rules and a root widget in your kv file::\n\n            <ClassName>: # this is a rule\n                ...\n\n            ClassName: # this is a root widget\n                ...\n\n        There must be only one root widget. See the :doc:`api-kivy.lang`\n        documentation for more information on how to create kv files. If your\n        kv file contains a root widget, it will be used as self.root, the root\n        widget for the application.\n\n        .. note::\n\n            This function is called from :meth:`run`, therefore, any widget\n            whose styling is defined in this kv file and is created before\n            :meth:`run` is called (e.g. in `__init__`), won't have its styling\n            applied. Note that :meth:`build` is called after :attr:`load_kv`\n            has been called.\n        '''\n        # Detect filename automatically if it was not specified.\n        if filename:\n            filename = resource_find(filename)\n        else:\n            try:\n                default_kv_directory = dirname(getfile(self.__class__))\n                if default_kv_directory == '':\n                    default_kv_directory = '.'\n            except TypeError:\n                # if it's a builtin module.. use the current dir.\n                default_kv_directory = '.'\n\n            kv_directory = self.kv_directory or default_kv_directory\n            clsname = self.__class__.__name__.lower()\n            if (clsname.endswith('app') and\n                    not isfile(join(kv_directory, '%s.kv' % clsname))):\n                clsname = clsname[:-3]\n            filename = join(kv_directory, '%s.kv' % clsname)\n\n        # Load KV file\n        Logger.debug('App: Loading kv <{0}>'.format(filename))\n        rfilename = resource_find(filename)\n        if rfilename is None or not exists(rfilename):\n            Logger.debug('App: kv <%s> not found' % filename)\n            return False\n        root = Builder.load_file(rfilename)\n        if root:\n            self.root = root\n        return True\n\n    def get_application_name(self):\n        '''Return the name of the application.\n        '''\n        if self.title is not None:\n            return self.title\n        clsname = self.__class__.__name__\n        if clsname.endswith('App'):\n            clsname = clsname[:-3]\n        return clsname\n\n    def get_application_icon(self):\n        '''Return the icon of the application.\n        '''\n        if not resource_find(self.icon):\n            return ''\n        else:\n            return resource_find(self.icon)\n\n    def get_application_config(self, defaultpath='%(appdir)s/%(appname)s.ini'):\n        '''.. versionadded:: 1.0.7\n\n        .. versionchanged:: 1.4.0\n            Customized the default path for iOS and Android platforms. Added a\n            defaultpath parameter for desktop OS's (not applicable to iOS\n            and Android.)\n\n        Return the filename of your application configuration. Depending\n        on the platform, the application file will be stored in\n        different locations:\n\n            - on iOS: <appdir>/Documents/.<appname>.ini\n            - on Android: /sdcard/.<appname>.ini\n            - otherwise: <appdir>/<appname>.ini\n\n        When you are distributing your application on Desktops, please\n        note that if the application is meant to be installed\n        system-wide, the user might not have write-access to the\n        application directory. If you want to store user settings, you\n        should overload this method and change the default behavior to\n        save the configuration file in the user directory.::\n\n            class TestApp(App):\n                def get_application_config(self):\n                    return super(TestApp, self).get_application_config(\n                        '~/.%(appname)s.ini')\n\n        Some notes:\n\n        - The tilda '~' will be expanded to the user directory.\n        - %(appdir)s will be replaced with the application :attr:`directory`\n        - %(appname)s will be replaced with the application :attr:`name`\n        '''\n\n        if platform == 'android':\n            defaultpath = '/sdcard/.%(appname)s.ini'\n        elif platform == 'ios':\n            defaultpath = '~/Documents/%(appname)s.ini'\n        elif platform == 'win':\n            defaultpath = defaultpath.replace('/', sep)\n        return expanduser(defaultpath) % {\n            'appname': self.name, 'appdir': self.directory}\n\n    @property\n    def root_window(self):\n        '''.. versionadded:: 1.9.0\n\n        Returns the root window instance used by :meth:`run`.\n        '''\n        return self._app_window\n\n    def load_config(self):\n        '''(internal) This function is used for returning a ConfigParser with\n        the application configuration. It's doing 3 things:\n\n            #. Creating an instance of a ConfigParser\n            #. Loading the default configuration by calling\n               :meth:`build_config`, then\n            #. If it exists, it loads the application configuration file,\n               otherwise it creates one.\n\n        :return:\n            :class:`~kivy.config.ConfigParser` instance\n        '''\n        try:\n            config = ConfigParser.get_configparser('app')\n        except KeyError:\n            config = None\n        if config is None:\n            config = ConfigParser(name='app')\n        self.config = config\n        self.build_config(config)\n        # if no sections are created, that's mean the user don't have\n        # configuration.\n        if len(config.sections()) == 0:\n            return\n        # ok, the user have some sections, read the default file if exist\n        # or write it !\n        filename = self.get_application_config()\n        if filename is None:\n            return config\n        Logger.debug('App: Loading configuration <{0}>'.format(filename))\n        if exists(filename):\n            try:\n                config.read(filename)\n            except:\n                Logger.error('App: Corrupted config file, ignored.')\n                config.name = ''\n                try:\n                    config = ConfigParser.get_configparser('app')\n                except KeyError:\n                    config = None\n                if config is None:\n                    config = ConfigParser(name='app')\n                self.config = config\n                self.build_config(config)\n                pass\n        else:\n            Logger.debug('App: First configuration, create <{0}>'.format(\n                filename))\n            config.filename = filename\n            config.write()\n        return config\n\n    @property\n    def directory(self):\n        '''.. versionadded:: 1.0.7\n\n        Return the directory where the application lives.\n        '''\n        if self._app_directory is None:\n            try:\n                self._app_directory = dirname(getfile(self.__class__))\n                if self._app_directory == '':\n                    self._app_directory = '.'\n            except TypeError:\n                # if it's a builtin module.. use the current dir.\n                self._app_directory = '.'\n        return self._app_directory\n\n    @property\n    def user_data_dir(self):\n        '''\n        .. versionadded:: 1.7.0\n\n        Returns the path to the directory in the users file system which the\n        application can use to store additional data.\n\n        Different platforms have different conventions with regards to where\n        the user can store data such as preferences, saved games and settings.\n        This function implements these conventions. The <app_name> directory\n        is created when the property is called, unless it already exists.\n\n        On iOS, `~/Documents<app_name>` is returned (which is inside the\n        app's sandbox).\n\n        On Android, `/sdcard/<app_name>` is returned.\n\n        On Windows, `%APPDATA%/<app_name>` is returned.\n\n        On Mac OSX, `~/Library/Application Support/<app_name>` is returned.\n\n        On Linux, `$XDG_CONFIG_HOME/<app_name>` is returned.\n        '''\n        data_dir = \"\"\n        if platform == 'ios':\n            data_dir = join('~/Documents', self.name)\n        elif platform == 'android':\n            data_dir = join('/sdcard', self.name)\n        elif platform == 'win':\n            data_dir = os.path.join(os.environ['APPDATA'], self.name)\n        elif platform == 'macosx':\n            data_dir = '~/Library/Application Support/{}'.format(self.name)\n        else:  # _platform == 'linux' or anything else...:\n            data_dir = os.environ.get('XDG_CONFIG_HOME', '~/.config')\n            data_dir = join(data_dir, self.name)\n        data_dir = expanduser(data_dir)\n        if not exists(data_dir):\n            os.mkdir(data_dir)\n        return data_dir\n\n    @property\n    def name(self):\n        '''.. versionadded:: 1.0.7\n\n        Return the name of the application based on the class name.\n        '''\n        if self._app_name is None:\n            clsname = self.__class__.__name__\n            if clsname.endswith('App'):\n                clsname = clsname[:-3]\n            self._app_name = clsname.lower()\n        return self._app_name\n\n    def run(self):\n        '''Launches the app in standalone mode.\n        '''\n        if not self.built:\n            self.load_config()\n            self.load_kv(filename=self.kv_file)\n            root = self.build()\n            if root:\n                self.root = root\n        if self.root:\n            if not isinstance(self.root, Widget):\n                Logger.critical('App.root must be an _instance_ of Widget')\n                raise Exception('Invalid instance in App.root')\n            from kivy.core.window import Window\n            Window.add_widget(self.root)\n\n        # Check if the window is already created\n        from kivy.base import EventLoop\n        window = EventLoop.window\n        if window:\n            self._app_window = window\n            window.set_title(self.get_application_name())\n            icon = self.get_application_icon()\n            if icon:\n                window.set_icon(icon)\n            self._install_settings_keys(window)\n        else:\n            Logger.critical(\"Application: No window is created.\"\n                            \" Terminating application run.\")\n            return\n\n        self.dispatch('on_start')\n        runTouchApp()\n        self.stop()\n\n    def stop(self, *largs):\n        '''Stop the application.\n\n        If you use this method, the whole application will stop by issuing\n        a call to :func:`~kivy.base.stopTouchApp`.\n        '''\n        self.dispatch('on_stop')\n        stopTouchApp()\n\n        # Clear the window children\n        for child in self._app_window.children:\n            self._app_window.remove_widget(child)\n\n    def on_start(self):\n        '''Event handler for the `on_start` event which is fired after\n        initialization (after build() has been called) but before the\n        application has started running.\n        '''\n        pass\n\n    def on_stop(self):\n        '''Event handler for the `on_stop` event which is fired when the\n        application has finished running (i.e. the window is about to be\n        closed).\n        '''\n        pass\n\n    def on_pause(self):\n        '''Event handler called when Pause mode is requested. You should\n        return True if your app can go into Pause mode, otherwise\n        return False and your application will be stopped (the default).\n\n        You cannot control when the application is going to go into this mode.\n        It's determined by the Operating System and mostly used for mobile\n        devices (android/ios) and for resizing.\n\n        The default return value is False.\n\n        .. versionadded:: 1.1.0\n        '''\n        return False\n\n    def on_resume(self):\n        '''Event handler called when your application is resuming from\n        the Pause mode.\n\n        .. versionadded:: 1.1.0\n\n        .. warning::\n\n            When resuming, the OpenGL Context might have been damaged / freed.\n            This is where you can reconstruct some of your OpenGL state\n            e.g. FBO content.\n        '''\n        pass\n\n    @staticmethod\n    def get_running_app():\n        '''Return the currently running application instance.\n\n        .. versionadded:: 1.1.0\n        '''\n        return App._running_app\n\n    def on_config_change(self, config, section, key, value):\n        '''Event handler fired when a configuration token has been changed by\n        the settings page.\n        '''\n        pass\n\n    def open_settings(self, *largs):\n        '''Open the application settings panel. It will be created the very\n        first time, or recreated if the previously cached panel has been\n        removed by :meth:`destroy_settings`. The settings panel will be\n        displayed with the\n        :meth:`display_settings` method, which by default adds the\n        settings panel to the Window attached to your application. You\n        should override that method if you want to display the\n        settings panel differently.\n\n        :return:\n            True if the settings has been opened.\n\n        '''\n        if self._app_settings is None:\n            self._app_settings = self.create_settings()\n        displayed = self.display_settings(self._app_settings)\n        if displayed:\n            return True\n        return False\n\n    def display_settings(self, settings):\n        '''.. versionadded:: 1.8.0\n\n        Display the settings panel. By default, the panel is drawn directly\n        on top of the window. You can define other behaviour by overriding\n        this method, such as adding it to a ScreenManager or Popup.\n\n        You should return True if the display is successful, otherwise False.\n\n        :Parameters:\n            `settings`: :class:`~kivy.uix.settings.Settings`\n                You can modify this object in order to modify the settings\n                display.\n\n        '''\n        win = self._app_window\n        if not win:\n            raise Exception('No windows are set on the application, you cannot'\n                            ' open settings yet.')\n        if settings not in win.children:\n            win.add_widget(settings)\n            return True\n        return False\n\n    def close_settings(self, *largs):\n        '''Close the previously opened settings panel.\n\n        :return:\n            True if the settings has been closed.\n        '''\n        win = self._app_window\n        settings = self._app_settings\n        if win is None or settings is None:\n            return\n        if settings in win.children:\n            win.remove_widget(settings)\n            return True\n        return False\n\n    def create_settings(self):\n        '''Create the settings panel. This method will normally\n        be called only one time per\n        application life-time and the result is cached internally,\n        but it may be called again if the cached panel is removed\n        by :meth:`destroy_settings`.\n\n        By default, it will build a settings panel according to\n        :attr:`settings_cls`, call :meth:`build_settings`, add a Kivy panel if\n        :attr:`use_kivy_settings` is True, and bind to\n        on_close/on_config_change.\n\n        If you want to plug your own way of doing settings, without the Kivy\n        panel or close/config change events, this is the method you want to\n        overload.\n\n        .. versionadded:: 1.8.0\n        '''\n        if self.settings_cls is None:\n            from kivy.uix.settings import SettingsWithSpinner\n            self.settings_cls = SettingsWithSpinner\n        elif isinstance(self.settings_cls, string_types):\n            self.settings_cls = Factory.get(self.settings_cls)\n        s = self.settings_cls()\n        self.build_settings(s)\n        if self.use_kivy_settings:\n            s.add_kivy_panel()\n        s.bind(on_close=self.close_settings,\n               on_config_change=self._on_config_change)\n        return s\n\n    def destroy_settings(self):\n        '''.. versionadded:: 1.8.0\n\n        Dereferences the current settings panel if one\n        exists. This means that when :meth:`App.open_settings` is next\n        run, a new panel will be created and displayed. It doesn't\n        affect any of the contents of the panel, but lets you (for\n        instance) refresh the settings panel layout if you have\n        changed the settings widget in response to a screen size\n        change.\n\n        If you have modified :meth:`~App.open_settings` or\n        :meth:`~App.display_settings`, you should be careful to\n        correctly detect if the previous settings widget has been\n        destroyed.\n\n        '''\n        if self._app_settings is not None:\n            self._app_settings = None\n\n    #\n    # privates\n    #\n\n    def _on_config_change(self, *largs):\n        self.on_config_change(*largs[1:])\n\n    def _install_settings_keys(self, window):\n        window.bind(on_keyboard=self._on_keyboard_settings)\n\n    def _on_keyboard_settings(self, window, *largs):\n        key = largs[0]\n        setting_key = 282  # F1\n\n        # android hack, if settings key is pygame K_MENU\n        if platform == 'android':\n            import pygame\n            setting_key = pygame.K_MENU\n\n        if key == setting_key:\n            # toggle settings panel\n            if not self.open_settings():\n                self.close_settings()\n            return True\n        if key == 27:\n            return self.close_settings()\n\n    def on_title(self, instance, title):\n        if self._app_window:\n            self._app_window.set_title(title)\n\n    def on_icon(self, instance, icon):\n        if self._app_window:\n            self._app_window.set_icon(self.get_application_icon())\n\n"
  },
  {
    "path": "tickeys/kivy/atlas.py",
    "content": "'''\nAtlas\n=====\n\n.. versionadded:: 1.1.0\n\nAtlas manages texture atlases: packing multiple textures into\none. With it, you reduce the number of images loaded and speedup the\napplication loading. This module contains both the Atlas class and command line\nprocessing for creating an atlas from a set of individual PNG files. The\ncommand line section requires the Pillow library, or the defunct Python Imaging\nLibrary (PIL), to be installed.\n\nAn Atlas is composed of files:\n    - a json file (.atlas) that contains the image file names and texture\n      locations of the atlas.\n    - one or multiple image files containing textures referenced by the .atlas\n      file.\n\nDefinition of .atlas files\n--------------------------\n\nA file with ``<basename>.atlas`` is a json file formatted like this::\n\n    {\n        \"<basename>-<index>.png\": {\n            \"id1\": [ <x>, <y>, <width>, <height> ],\n            \"id2\": [ <x>, <y>, <width>, <height> ],\n            # ...\n        },\n        # ...\n    }\n\nExample from the Kivy ``data/images/defaulttheme.atlas``::\n\n    {\n        \"defaulttheme-0.png\": {\n            \"progressbar_background\": [431, 224, 59, 24],\n            \"image-missing\": [253, 344, 48, 48],\n            \"filechooser_selected\": [1, 207, 118, 118],\n            \"bubble_btn\": [83, 174, 32, 32],\n            # ... and more ...\n        }\n    }\n\nIn this example, \"defaulttheme-0.png\" is a large image, with the pixels in the\nrectangle from (431, 224) to (431 + 59, 224 + 24) usable as\n``atlas://data/images/defaulttheme/progressbar_background`` in\nany image parameter.\n\nHow to create an Atlas\n----------------------\n\n.. warning::\n\n    The atlas creation requires the Pillow library (or the defunct Imaging/PIL\n    library). This requirement will be removed in the future when the Kivy core\n    Image is able to support loading, blitting, and saving operations.\n\nYou can directly use this module to create atlas files with this command::\n\n    $ python -m kivy.atlas <basename> <size> <list of images...>\n\n\nLet's say you have a list of images that you want to put into an Atlas. The\ndirectory is named ``images`` with lots of 64x64 png files inside::\n\n    $ ls\n    images\n    $ cd images\n    $ ls\n    bubble.png bubble-red.png button.png button-down.png\n\nYou can combine all the png's into one and generate the atlas file with::\n\n    $ python -m kivy.atlas myatlas 256x256 *.png\n    Atlas created at myatlas.atlas\n    1 image has been created\n    $ ls\n    bubble.png bubble-red.png button.png button-down.png myatlas.atlas\n    myatlas-0.png\n\nAs you can see, we get 2 new files: ``myatlas.atlas`` and ``myatlas-0.png``.\n``myatlas-0.png`` is a new 256x256 .png composed of all your images.\n\n.. note::\n\n    When using this script, the ids referenced in the atlas are the base names\n    of the images without the extension. So, if you are going to name a file\n    ``../images/button.png``, the id for this image will be ``button``.\n\n    If you need path information included, you should include ``use_path`` as\n    follows::\n\n        $ python -m kivy.atlas use_path myatlas 256 *.png\n\n    In which case the id for ``../images/button.png`` will be ``images_button``\n\n\nHow to use an Atlas\n-------------------\n\nUsually, you would use the atlas as follows::\n\n    a = Button(background_normal='images/button.png',\n               background_down='images/button_down.png')\n\nIn our previous example, we have created the atlas containing both images and\nput them in ``images/myatlas.atlas``. You can use url notation to reference\nthem::\n\n    atlas://path/to/myatlas/id\n    # will search for the ``path/to/myatlas.atlas`` and get the image ``id``\n\nIn our case, it would be::\n\n    atlas://images/myatlas/button\n\n.. note::\n\n    In the atlas url, there is no need to add the ``.atlas`` extension. It will\n    be automatically append to the filename.\n\nManual usage of the Atlas\n-------------------------\n\n::\n\n    >>> from kivy.atlas import Atlas\n    >>> atlas = Atlas('path/to/myatlas.atlas')\n    >>> print(atlas.textures.keys())\n    ['bubble', 'bubble-red', 'button', 'button-down']\n    >>> print(atlas['button'])\n    <kivy.graphics.texture.TextureRegion object at 0x2404d10>\n'''\n\n__all__ = ('Atlas', )\n\nimport json\nfrom os.path import basename, dirname, join, splitext\nfrom kivy.event import EventDispatcher\nfrom kivy.logger import Logger\nfrom kivy.properties import AliasProperty, DictProperty\nimport os\n\n\n# late import to prevent recursion\nCoreImage = None\n\n\nclass Atlas(EventDispatcher):\n    '''Manage texture atlas. See module documentation for more information.\n    '''\n\n    textures = DictProperty({})\n    '''List of available textures within the atlas.\n\n    :attr:`textures` is a :class:`~kivy.properties.DictProperty` and defaults\n    to {}.\n    '''\n\n    def _get_filename(self):\n        return self._filename\n\n    filename = AliasProperty(_get_filename, None)\n    '''Filename of the current Atlas.\n\n    :attr:`filename` is an :class:`~kivy.properties.AliasProperty` and defaults\n    to None.\n    '''\n\n    def __init__(self, filename):\n        self._filename = filename\n        super(Atlas, self).__init__()\n        self._load()\n\n    def __getitem__(self, key):\n        return self.textures[key]\n\n    def _load(self):\n        # late import to prevent recursive import.\n        global CoreImage\n        if CoreImage is None:\n            from kivy.core.image import Image as CoreImage\n\n        # must be a name finished by .atlas ?\n        filename = self._filename\n        assert(filename.endswith('.atlas'))\n        filename = filename.replace('/', os.sep)\n\n        Logger.debug('Atlas: Load <%s>' % filename)\n        with open(filename, 'r') as fd:\n            meta = json.load(fd)\n\n        Logger.debug('Atlas: Need to load %d images' % len(meta))\n        d = dirname(filename)\n        textures = {}\n        for subfilename, ids in meta.items():\n            subfilename = join(d, subfilename)\n            Logger.debug('Atlas: Load <%s>' % subfilename)\n\n            # load the image\n            ci = CoreImage(subfilename)\n\n            # for all the uid, load the image, get the region, and put\n            # it in our dict.\n            for meta_id, meta_coords in ids.items():\n                x, y, w, h = meta_coords\n                textures[meta_id] = ci.texture.get_region(*meta_coords)\n\n        self.textures = textures\n\n    @staticmethod\n    def create(outname, filenames, size, padding=2, use_path=False):\n        '''This method can be used to create an atlas manually from a set of\n        images.\n\n        :Parameters:\n            `outname`: str\n                Basename to use for ``.atlas`` creation and ``-<idx>.png``\n                associated images.\n            `filenames`: list\n                List of filenames to put in the atlas.\n            `size`: int or list (width, height)\n                Size of the atlas image.\n            `padding`: int, defaults to 2\n                Padding to put around each image.\n\n                Be careful. If you're using a padding < 2, you might have\n                issues with the borders of the images. Because of the OpenGL\n                linearization, it might use the pixels of the adjacent image.\n\n                If you're using a padding >= 2, we'll automatically generate a\n                \"border\" of 1px around your image. If you look at\n                the result, don't be scared if the image inside is not\n                exactly the same as yours :).\n\n            `use_path`: bool, defaults to False\n                If True, the relative path of the source png\n                file names will be included in the atlas ids rather\n                that just in the file names. Leading dots and slashes will be\n                excluded and all other slashes in the path will be replaced\n                with underscores. For example, if `use_path` is False\n                (the default) and the file name is\n                ``../data/tiles/green_grass.png``, the id will be\n                ``green_grass``. If `use_path` is True, it will be\n                ``data_tiles_green_grass``.\n\n            .. versionchanged:: 1.8.0\n                Parameter use_path added\n        '''\n        # Thanks to\n        # omnisaurusgames.com/2011/06/texture-atlas-generation-using-python/\n        # for its initial implementation.\n        try:\n            from PIL import Image\n        except ImportError:\n            Logger.critical('Atlas: Imaging/PIL are missing')\n            raise\n\n        if isinstance(size, (tuple, list)):\n            size_w, size_h = map(int, size)\n        else:\n            size_w = size_h = int(size)\n\n        # open all of the images\n        ims = list()\n        for f in filenames:\n            fp = open(f, 'rb')\n            im = Image.open(fp)\n            im.load()\n            fp.close()\n            ims.append((f, im))\n\n        # sort by image area\n        ims = sorted(ims, key=lambda im: im[1].size[0] * im[1].size[1],\n                     reverse=True)\n\n        # free boxes are empty space in our output image set\n        # the freebox tuple format is: outidx, x, y, w, h\n        freeboxes = [(0, 0, 0, size_w, size_h)]\n        numoutimages = 1\n\n        # full boxes are areas where we have placed images in the atlas\n        # the full box tuple format is: image, outidx, x, y, w, h, filename\n        fullboxes = []\n\n        # do the actual atlasing by sticking the largest images we can\n        # have into the smallest valid free boxes\n        for imageinfo in ims:\n            im = imageinfo[1]\n            imw, imh = im.size\n            imw += padding\n            imh += padding\n            if imw > size_w or imh > size_h:\n                Logger.error(\n                    'Atlas: image %s (%d by %d) is larger than the atlas size!'\n                    % (imageinfo[0], imw, imh))\n                return\n\n            inserted = False\n            while not inserted:\n                for idx, fb in enumerate(freeboxes):\n                    # find the smallest free box that will contain this image\n                    if fb[3] >= imw and fb[4] >= imh:\n                        # we found a valid spot! Remove the current\n                        # freebox, and split the leftover space into (up to)\n                        # two new freeboxes\n                        del freeboxes[idx]\n                        if fb[3] > imw:\n                            freeboxes.append((\n                                fb[0], fb[1] + imw, fb[2],\n                                fb[3] - imw, imh))\n\n                        if fb[4] > imh:\n                            freeboxes.append((\n                                fb[0], fb[1], fb[2] + imh,\n                                fb[3], fb[4] - imh))\n\n                        # keep this sorted!\n                        freeboxes = sorted(freeboxes,\n                                           key=lambda fb: fb[3] * fb[4])\n                        fullboxes.append((im,\n                                          fb[0], fb[1] + padding,\n                                          fb[2] + padding, imw - padding,\n                                          imh - padding, imageinfo[0]))\n                        inserted = True\n                        break\n\n                if not inserted:\n                    # oh crap - there isn't room in any of our free\n                    # boxes, so we have to add a new output image\n                    freeboxes.append((numoutimages, 0, 0, size_w, size_h))\n                    numoutimages += 1\n\n        # now that we've figured out where everything goes, make the output\n        # images and blit the source images to the approriate locations\n        Logger.info('Atlas: create an {0}x{1} rgba image'.format(size_w,\n                                                                 size_h))\n        outimages = [Image.new('RGBA', (size_w, size_h))\n                     for i in range(0, int(numoutimages))]\n        for fb in fullboxes:\n            x, y = fb[2], fb[3]\n            out = outimages[fb[1]]\n            out.paste(fb[0], (fb[2], fb[3]))\n            w, h = fb[0].size\n            if padding > 1:\n                out.paste(fb[0].crop((0, 0, w, 1)), (x, y - 1))\n                out.paste(fb[0].crop((0, h - 1, w, h)), (x, y + h))\n                out.paste(fb[0].crop((0, 0, 1, h)), (x - 1, y))\n                out.paste(fb[0].crop((w - 1, 0, w, h)), (x + w, y))\n\n        # save the output images\n        for idx, outimage in enumerate(outimages):\n            outimage.save('%s-%d.png' % (outname, idx))\n\n        # write out an json file that says where everything ended up\n        meta = {}\n        for fb in fullboxes:\n            fn = '%s-%d.png' % (basename(outname), fb[1])\n            if fn not in meta:\n                d = meta[fn] = {}\n            else:\n                d = meta[fn]\n\n            # fb[6] contain the filename\n            if use_path:\n                # use the path with separators replaced by _\n                # example '../data/tiles/green_grass.png' becomes\n                # 'data_tiles_green_grass'\n                uid = splitext(fb[6])[0]\n                # remove leading dots and slashes\n                uid = uid.lstrip('./\\\\')\n                # replace remaining slashes with _\n                uid = uid.replace('/', '_').replace('\\\\', '_')\n            else:\n                # for example, '../data/tiles/green_grass.png'\n                # just get only 'green_grass' as the uniq id.\n                uid = splitext(basename(fb[6]))[0]\n\n            x, y, w, h = fb[2:6]\n            d[uid] = x, size_h - y - h, w, h\n\n        outfn = '%s.atlas' % outname\n        with open(outfn, 'w') as fd:\n            json.dump(meta, fd)\n\n        return outfn, meta\n\n\nif __name__ == '__main__':\n    \"\"\" Main line program. Process command line arguments\n    to make a new atlas. \"\"\"\n\n    import sys\n    from glob import glob\n    argv = sys.argv[1:]\n    # earlier import of kivy has already called getopt to remove kivy system\n    # arguments from this line. That is all arguments up to the first '--'\n    if len(argv) < 3:\n        print('Usage: python -m kivy.atlas [-- [--use-path] '\n              '[--padding=2]] <outname> '\n              '<size|512x256> <img1.png> [<img2.png>, ...]')\n        sys.exit(1)\n\n    options = {'use_path': False}\n    while True:\n        option = argv[0]\n        if option == '--use-path':\n            options['use_path'] = True\n        elif option.startswith('--padding='):\n            options['padding'] = int(option.split('=', 1)[-1])\n        elif option[:2] == '--':\n            print('Unknown option {}'.format(option))\n            sys.exit(1)\n        else:\n            break\n        argv = argv[1:]\n\n    outname = argv[0]\n    try:\n        if 'x' in argv[1]:\n            size = map(int, argv[1].split('x', 1))\n        else:\n            size = int(argv[1])\n    except ValueError:\n        print('Error: size must be an integer or <integer>x<integer>')\n        sys.exit(1)\n\n    filenames = [fname for fnames in argv[2:] for fname in glob(fnames)]\n    ret = Atlas.create(outname, filenames, size, **options)\n    if not ret:\n        print('Error while creating atlas!')\n        sys.exit(1)\n\n    fn, meta = ret\n    print('Atlas created at', fn)\n    print('%d image%s been created' % (len(meta),\n          's have' if len(meta) > 1 else ' has'))\n"
  },
  {
    "path": "tickeys/kivy/base.py",
    "content": "# pylint: disable=W0611\n'''\nKivy Base\n=========\n\nThis module contains core Kivy functionality and is not intended for end users.\nFeel free to look though it, but calling any of these methods directly may well\nresult in unpredicatable behavior.\n\nEvent loop management\n---------------------\n\n'''\n\n__all__ = (\n    'EventLoop',\n    'EventLoopBase',\n    'ExceptionHandler',\n    'ExceptionManagerBase',\n    'ExceptionManager',\n    'runTouchApp',\n    'stopTouchApp',\n)\n\nimport sys\nfrom kivy.config import Config\nfrom kivy.logger import Logger\nfrom kivy.utils import platform\nfrom kivy.clock import Clock\nfrom kivy.event import EventDispatcher\nfrom kivy.lang import Builder\nfrom kivy.context import register_context\n\n# private vars\nEventLoop = None\n\n\nclass ExceptionHandler(object):\n    '''Base handler that catches exceptions in :func:`runTouchApp`.\n    You can subclass and extend it as follows::\n\n        class E(ExceptionHandler):\n            def handle_exception(self, inst):\n                Logger.exception('Exception catched by ExceptionHandler')\n                return ExceptionManager.PASS\n\n        ExceptionManager.add_handler(E())\n\n    All exceptions will be set to PASS, and logged to the console!\n    '''\n\n    def __init__(self):\n        pass\n\n    def handle_exception(self, exception):\n        '''Handle one exception, defaults to returning\n        ExceptionManager.STOP.\n        '''\n        return ExceptionManager.RAISE\n\n\nclass ExceptionManagerBase:\n    '''ExceptionManager manages exceptions handlers.'''\n\n    RAISE = 0\n    PASS = 1\n\n    def __init__(self):\n        self.handlers = []\n        self.policy = ExceptionManagerBase.RAISE\n\n    def add_handler(self, cls):\n        '''Add a new exception handler to the stack.'''\n        if not cls in self.handlers:\n            self.handlers.append(cls)\n\n    def remove_handler(self, cls):\n        '''Remove a exception handler from the stack.'''\n        if cls in self.handlers:\n            self.handlers.remove(cls)\n\n    def handle_exception(self, inst):\n        '''Called when an exception occured in the runTouchApp() main loop.'''\n        ret = self.policy\n        for handler in self.handlers:\n            r = handler.handle_exception(inst)\n            if r == ExceptionManagerBase.PASS:\n                ret = r\n        return ret\n\n#: Instance of a :class:`ExceptionManagerBase` implementation.\nExceptionManager = register_context('ExceptionManager', ExceptionManagerBase)\n\n\nclass EventLoopBase(EventDispatcher):\n    '''Main event loop. This loop handles the updating of input and\n    dispatching events.\n    '''\n\n    __events__ = ('on_start', 'on_pause', 'on_stop')\n\n    def __init__(self):\n        super(EventLoopBase, self).__init__()\n        self.quit = False\n        self.input_events = []\n        self.postproc_modules = []\n        self.status = 'idle'\n        self.input_providers = []\n        self.input_providers_autoremove = []\n        self.event_listeners = []\n        self.window = None\n        self.me_list = []\n\n    @property\n    def touches(self):\n        '''Return the list of all touches currently in down or move states.\n        '''\n        return self.me_list\n\n    def ensure_window(self):\n        '''Ensure that we have a window.\n        '''\n        import kivy.core.window  # NOQA\n        if not self.window:\n            Logger.critical('App: Unable to get a Window, abort.')\n            sys.exit(1)\n\n    def set_window(self, window):\n        '''Set the window used for the event loop.\n        '''\n        self.window = window\n\n    def add_input_provider(self, provider, auto_remove=False):\n        '''Add a new input provider to listen for touch events.\n        '''\n        if provider not in self.input_providers:\n            self.input_providers.append(provider)\n            if auto_remove:\n                self.input_providers_autoremove.append(provider)\n\n    def remove_input_provider(self, provider):\n        '''Remove an input provider.\n        '''\n        if provider in self.input_providers:\n            self.input_providers.remove(provider)\n\n    def add_event_listener(self, listener):\n        '''Add a new event listener for getting touch events.\n        '''\n        if not listener in self.event_listeners:\n            self.event_listeners.append(listener)\n\n    def remove_event_listener(self, listener):\n        '''Remove an event listener from the list.\n        '''\n        if listener in self.event_listeners:\n            self.event_listeners.remove(listener)\n\n    def start(self):\n        '''Must be called only once before run().\n        This starts all configured input providers.'''\n        self.status = 'started'\n        self.quit = False\n        for provider in self.input_providers:\n            provider.start()\n        self.dispatch('on_start')\n\n    def close(self):\n        '''Exit from the main loop and stop all configured\n        input providers.'''\n        self.quit = True\n        self.stop()\n        self.status = 'closed'\n\n    def stop(self):\n        '''Stop all input providers and call callbacks registered using\n        EventLoop.add_stop_callback().'''\n\n        # XXX stop in reverse order that we started them!! (like push\n        # pop), very important because e.g. wm_touch and WM_PEN both\n        # store old window proc and the restore, if order is messed big\n        # problem happens, crashing badly without error\n        for provider in reversed(self.input_providers[:]):\n            provider.stop()\n            if provider in self.input_providers_autoremove:\n                self.input_providers_autoremove.remove(provider)\n                self.input_providers.remove(provider)\n\n        # ensure any restart will not break anything later.\n        self.input_events = []\n\n        self.status = 'stopped'\n        self.dispatch('on_stop')\n\n    def add_postproc_module(self, mod):\n        '''Add a postproc input module (DoubleTap, TripleTap, DeJitter\n        RetainTouch are defaults).'''\n        if mod not in self.postproc_modules:\n            self.postproc_modules.append(mod)\n\n    def remove_postproc_module(self, mod):\n        '''Remove a postproc module.'''\n        if mod in self.postproc_modules:\n            self.postproc_modules.remove(mod)\n\n    def post_dispatch_input(self, etype, me):\n        '''This function is called by dispatch_input() when we want to dispatch\n        an input event. The event is dispatched to all listeners and if\n        grabbed, it's dispatched to grabbed widgets.\n        '''\n        # update available list\n        if etype == 'begin':\n            self.me_list.append(me)\n        elif etype == 'end':\n            if me in self.me_list:\n                self.me_list.remove(me)\n\n        # dispatch to listeners\n        if not me.grab_exclusive_class:\n            for listener in self.event_listeners:\n                listener.dispatch('on_motion', etype, me)\n\n        # dispatch grabbed touch\n        me.grab_state = True\n        for _wid in me.grab_list[:]:\n\n            # it's a weakref, call it!\n            wid = _wid()\n            if wid is None:\n                # object is gone, stop.\n                me.grab_list.remove(_wid)\n                continue\n\n            root_window = wid.get_root_window()\n            if wid != root_window and root_window is not None:\n                me.push()\n                w, h = root_window.system_size\n                if platform == 'ios':\n                    w, h = root_window.size\n                kheight = root_window.keyboard_height\n                smode = root_window.softinput_mode\n                me.scale_for_screen(w, h, rotation=root_window.rotation,\n                                    smode=smode, kheight=kheight)\n                parent = wid.parent\n                # and do to_local until the widget\n                try:\n                    if parent:\n                        me.apply_transform_2d(parent.to_widget)\n                    else:\n                        me.apply_transform_2d(wid.to_widget)\n                        me.apply_transform_2d(wid.to_parent)\n                except AttributeError:\n                    # when using inner window, an app have grab the touch\n                    # but app is removed. the touch can't access\n                    # to one of the parent. (i.e, self.parent will be None)\n                    # and BAM the bug happen.\n                    me.pop()\n                    continue\n\n            me.grab_current = wid\n\n            wid._context.push()\n\n            if etype == 'begin':\n                # don't dispatch again touch in on_touch_down\n                # a down event are nearly uniq here.\n                # wid.dispatch('on_touch_down', touch)\n                pass\n            elif etype == 'update':\n                if wid._context.sandbox:\n                    with wid._context.sandbox:\n                        wid.dispatch('on_touch_move', me)\n                else:\n                    wid.dispatch('on_touch_move', me)\n\n            elif etype == 'end':\n                if wid._context.sandbox:\n                    with wid._context.sandbox:\n                        wid.dispatch('on_touch_up', me)\n                else:\n                    wid.dispatch('on_touch_up', me)\n\n            wid._context.pop()\n\n            me.grab_current = None\n\n            if wid != root_window and root_window is not None:\n                me.pop()\n        me.grab_state = False\n\n    def _dispatch_input(self, *ev):\n        # remove the save event for the touch if exist\n        if ev in self.input_events:\n            self.input_events.remove(ev)\n        self.input_events.append(ev)\n\n    def dispatch_input(self):\n        '''Called by idle() to read events from input providers, pass events to\n        postproc, and dispatch final events.\n        '''\n\n        # first, aquire input events\n        for provider in self.input_providers:\n            provider.update(dispatch_fn=self._dispatch_input)\n\n        # execute post-processing modules\n        for mod in self.postproc_modules:\n            self.input_events = mod.process(events=self.input_events)\n\n        # real dispatch input\n        input_events = self.input_events\n        pop = input_events.pop\n        post_dispatch_input = self.post_dispatch_input\n        while input_events:\n            post_dispatch_input(*pop(0))\n\n    def idle(self):\n        '''This function is called after every frame. By default:\n\n           * it \"ticks\" the clock to the next frame.\n           * it reads all input and dispatches events.\n           * it dispatches `on_update`, `on_draw` and `on_flip` events to the\n             window.\n        '''\n\n        # update dt\n        Clock.tick()\n\n        # read and dispatch input from providers\n        self.dispatch_input()\n\n        # flush all the canvas operation\n        Builder.sync()\n\n        # tick before draw\n        Clock.tick_draw()\n\n        # flush all the canvas operation\n        Builder.sync()\n\n        window = self.window\n        if window and window.canvas.needs_redraw:\n            window.dispatch('on_draw')\n            window.dispatch('on_flip')\n\n        # don't loop if we don't have listeners !\n        if len(self.event_listeners) == 0:\n            Logger.error('Base: No event listeners have been created')\n            Logger.error('Base: Application will leave')\n            self.exit()\n            return False\n\n        return self.quit\n\n    def run(self):\n        '''Main loop'''\n        while not self.quit:\n            self.idle()\n        self.exit()\n\n    def exit(self):\n        '''Close the main loop and close the window.'''\n        self.close()\n        if self.window:\n            self.window.close()\n\n    def on_stop(self):\n        '''Event handler for `on_stop` events which will be fired right\n        after all input providers have been stopped.'''\n        pass\n\n    def on_pause(self):\n        '''Event handler for `on_pause` which will be fired when\n        the event loop is paused.'''\n        pass\n\n    def on_start(self):\n        '''Event handler for `on_start` which will be fired right\n        after all input providers have been started.'''\n        pass\n\n#: EventLoop instance\nEventLoop = EventLoopBase()\n\n\ndef _run_mainloop():\n    '''If no window has been created, this will be the executed mainloop.'''\n    while True:\n        try:\n            EventLoop.run()\n            stopTouchApp()\n            break\n        except BaseException as inst:\n            # use exception manager first\n            r = ExceptionManager.handle_exception(inst)\n            if r == ExceptionManager.RAISE:\n                stopTouchApp()\n                raise\n            else:\n                pass\n\n\ndef runTouchApp(widget=None, slave=False):\n    '''Static main function that starts the application loop.\n    You can access some magic via the following arguments:\n\n    :Parameters:\n        `<empty>`\n            To make dispatching work, you need at least one\n            input listener. If not, application will leave.\n            (MTWindow act as an input listener)\n\n        `widget`\n            If you pass only a widget, a MTWindow will be created\n            and your widget will be added to the window as the root\n            widget.\n\n        `slave`\n            No event dispatching is done. This will be your job.\n\n        `widget + slave`\n            No event dispatching is done. This will be your job but\n            we try to get the window (must be created by you beforehand)\n            and add the widget to it. Very usefull for embedding Kivy\n            in another toolkit. (like Qt, check kivy-designed)\n\n    '''\n\n    from kivy.input import MotionEventFactory, kivy_postproc_modules\n\n    # Ok, we got one widget, and we are not in slave mode\n    # so, user don't create the window, let's create it for him !\n    if widget:\n        EventLoop.ensure_window()\n\n    # Instance all configured input\n    for key, value in Config.items('input'):\n        Logger.debug('Base: Create provider from %s' % (str(value)))\n\n        # split value\n        args = str(value).split(',', 1)\n        if len(args) == 1:\n            args.append('')\n        provider_id, args = args\n        provider = MotionEventFactory.get(provider_id)\n        if provider is None:\n            Logger.warning('Base: Unknown <%s> provider' % str(provider_id))\n            continue\n\n        # create provider\n        p = provider(key, args)\n        if p:\n            EventLoop.add_input_provider(p, True)\n\n    # add postproc modules\n    for mod in list(kivy_postproc_modules.values()):\n        EventLoop.add_postproc_module(mod)\n\n    # add main widget\n    if widget and EventLoop.window:\n        if widget not in EventLoop.window.children:\n            EventLoop.window.add_widget(widget)\n\n    # start event loop\n    Logger.info('Base: Start application main loop')\n    EventLoop.start()\n\n    # we are in a slave mode, don't do dispatching.\n    if slave:\n        return\n\n    # in non-slave mode, they are 2 issues\n    #\n    # 1. if user created a window, call the mainloop from window.\n    #    This is due to glut, it need to be called with\n    #    glutMainLoop(). Only FreeGLUT got a gluMainLoopEvent().\n    #    So, we are executing the dispatching function inside\n    #    a redisplay event.\n    #\n    # 2. if no window is created, we are dispatching event lopp\n    #    ourself (previous behavior.)\n    #\n    try:\n        if EventLoop.window is None:\n            _run_mainloop()\n        else:\n            EventLoop.window.mainloop()\n    finally:\n        stopTouchApp()\n\n\ndef stopTouchApp():\n    '''Stop the current application by leaving the main loop'''\n    if EventLoop is None:\n        return\n    if EventLoop.status != 'started':\n        return\n    Logger.info('Base: Leaving application in progress...')\n    EventLoop.close()\n"
  },
  {
    "path": "tickeys/kivy/cache.py",
    "content": "'''\nCache manager\n=============\n\nThe cache manager can be used to store python objects attached to a unique\nkey. The cache can be controlled in two ways: with a object limit or a\ntimeout.\n\nFor example, we can create a new cache with a limit of 10 objects and a\ntimeout of 5 seconds::\n\n    # register a new Cache\n    Cache.register('mycache', limit=10, timeout=5)\n\n    # create an object + id\n    key = 'objectid'\n    instance = Label(text=text)\n    Cache.append('mycache', key, instance)\n\n    # retrieve the cached object\n    instance = Cache.get('mycache', key)\n\nIf the instance is NULL, the cache may have trashed it because you've\nnot used the label for 5 seconds and you've reach the limit.\n'''\n\n__all__ = ('Cache', )\n\nfrom os import environ\nfrom kivy.logger import Logger\nfrom kivy.clock import Clock\n\n\nclass Cache(object):\n    '''See module documentation for more information.\n    '''\n\n    _categories = {}\n    _objects = {}\n\n    @staticmethod\n    def register(category, limit=None, timeout=None):\n        '''Register a new category in the cache with the specified limit.\n\n        :Parameters:\n            `category` : str\n                Identifier of the category.\n            `limit` : int (optional)\n                Maximum number of objects allowed in the cache.\n                If None, no limit is applied.\n            `timeout` : double (optional)\n                Time after which to delete the object if it has not been used.\n                If None, no timeout is applied.\n        '''\n        Cache._categories[category] = {\n            'limit': limit,\n            'timeout': timeout}\n        Cache._objects[category] = {}\n        Logger.debug(\n            'Cache: register <%s> with limit=%s, timeout=%s' %\n            (category, str(limit), str(timeout)))\n\n    @staticmethod\n    def append(category, key, obj, timeout=None):\n        '''Add a new object to the cache.\n\n        :Parameters:\n            `category` : str\n                Identifier of the category.\n            `key` : str\n                Unique identifier of the object to store.\n            `obj` : object\n                Object to store in cache.\n            `timeout` : double (optional)\n                Time after which to delete the object if it has not been used.\n                If None, no timeout is applied.\n        '''\n        #check whether obj should not be cached first\n        if getattr(obj, '_no_cache', False):\n            return\n        try:\n            cat = Cache._categories[category]\n        except KeyError:\n            Logger.warning('Cache: category <%s> not exist' % category)\n            return\n        timeout = timeout or cat['timeout']\n        # FIXME: activate purge when limit is hit\n        #limit = cat['limit']\n        #if limit is not None and len(Cache._objects[category]) >= limit:\n        #    Cache._purge_oldest(category)\n        Cache._objects[category][key] = {\n            'object': obj,\n            'timeout': timeout,\n            'lastaccess': Clock.get_time(),\n            'timestamp': Clock.get_time()}\n\n    @staticmethod\n    def get(category, key, default=None):\n        '''Get a object from the cache.\n\n        :Parameters:\n            `category` : str\n                Identifier of the category.\n            `key` : str\n                Unique identifier of the object in the store.\n            `default` : anything, defaults to None\n                Default value to be returned if the key is not found.\n        '''\n        try:\n            Cache._objects[category][key]['lastaccess'] = Clock.get_time()\n            return Cache._objects[category][key]['object']\n        except Exception:\n            return default\n\n    @staticmethod\n    def get_timestamp(category, key, default=None):\n        '''Get the object timestamp in the cache.\n\n        :Parameters:\n            `category` : str\n                Identifier of the category.\n            `key` : str\n                Unique identifier of the object in the store.\n            `default` : anything, defaults to None\n                Default value to be returned if the key is not found.\n        '''\n        try:\n            return Cache._objects[category][key]['timestamp']\n        except Exception:\n            return default\n\n    @staticmethod\n    def get_lastaccess(category, key, default=None):\n        '''Get the objects last access time in the cache.\n\n        :Parameters:\n            `category` : str\n                Identifier of the category.\n            `key` : str\n                Unique identifier of the object in the store.\n            `default` : anything, defaults to None\n                Default value to be returned if the key is not found.\n        '''\n        try:\n            return Cache._objects[category][key]['lastaccess']\n        except Exception:\n            return default\n\n    @staticmethod\n    def remove(category, key=None):\n        '''Purge the cache.\n\n        :Parameters:\n            `category` : str\n                Identifier of the category.\n            `key` : str (optional)\n                Unique identifier of the object in the store. If this\n                arguement is not supplied, the entire category will be purged.\n        '''\n        try:\n            if key is not None:\n                del Cache._objects[category][key]\n            else:\n                Cache._objects[category] = {}\n        except Exception:\n            pass\n\n    @staticmethod\n    def _purge_oldest(category, maxpurge=1):\n        print('PURGE', category)\n        import heapq\n        heap_list = []\n        for key in Cache._objects[category]:\n            obj = Cache._objects[category][key]\n            if obj['lastaccess'] == obj['timestamp']:\n                continue\n            heapq.heappush(heap_list, (obj['lastaccess'], key))\n            print('<<<', obj['lastaccess'])\n        n = 0\n        while n < maxpurge:\n            try:\n                lastaccess, key = heapq.heappop(heap_list)\n                print('=>', key, lastaccess, Clock.get_time())\n            except Exception:\n                return\n            del Cache._objects[category][key]\n\n    @staticmethod\n    def _purge_by_timeout(dt):\n        curtime = Clock.get_time()\n\n        for category in Cache._objects:\n            if category not in Cache._categories:\n                continue\n            timeout = Cache._categories[category]['timeout']\n            if timeout is not None and dt > timeout:\n                # XXX got a lag ! that may be because the frame take lot of\n                # time to draw. and the timeout is not adapted to the current\n                # framerate. So, increase the timeout by two.\n                # ie: if the timeout is 1 sec, and framerate go to 0.7, newly\n                # object added will be automaticly trashed.\n                timeout *= 2\n                Cache._categories[category]['timeout'] = timeout\n                continue\n\n            for key in list(Cache._objects[category].keys())[:]:\n                lastaccess = Cache._objects[category][key]['lastaccess']\n                objtimeout = Cache._objects[category][key]['timeout']\n\n                # take the object timeout if available\n                if objtimeout is not None:\n                    timeout = objtimeout\n\n                # no timeout, cancel\n                if timeout is None:\n                    continue\n\n                if curtime - lastaccess > timeout:\n                    del Cache._objects[category][key]\n\n    @staticmethod\n    def print_usage():\n        '''Print the cache usage to the console.'''\n        print('Cache usage :')\n        for category in Cache._categories:\n            print(' * %s : %d / %s, timeout=%s' % (\n                category.capitalize(),\n                len(Cache._objects[category]),\n                str(Cache._categories[category]['limit']),\n                str(Cache._categories[category]['timeout'])))\n\nif 'KIVY_DOC_INCLUDE' not in environ:\n    # install the schedule clock for purging\n    Clock.schedule_interval(Cache._purge_by_timeout, 1)\n"
  },
  {
    "path": "tickeys/kivy/clock.py",
    "content": "'''\nClock object\n============\n\nThe :class:`Clock` object allows you to schedule a function call in the\nfuture; once or repeatedly at specified intervals. You can get the time\nelapsed between the scheduling and the calling of the callback via the\n`dt` argument::\n\n    # dt means delta-time\n    def my_callback(dt):\n        pass\n\n    # call my_callback every 0.5 seconds\n    Clock.schedule_interval(my_callback, 0.5)\n\n    # call my_callback in 5 seconds\n    Clock.schedule_once(my_callback, 5)\n\n    # call my_callback as soon as possible (usually next frame.)\n    Clock.schedule_once(my_callback)\n\n.. note::\n\n    If the callback returns False, the schedule will be removed.\n\nIf you want to schedule a function to call with default arguments, you can use\nthe `functools.partial\n<http://docs.python.org/library/functools.html#functools.partial>`_ python\nmodule::\n\n    from functools import partial\n\n    def my_callback(value, key, *largs):\n        pass\n\n    Clock.schedule_interval(partial(my_callback, 'my value', 'my key'), 0.5)\n\nConversely, if you want to schedule a function that doesn't accept the dt\nargument, you can use a `lambda\n<http://docs.python.org/2/reference/expressions.html#lambda>`_ expression\nto write a short function that does accept dt. For Example::\n\n    def no_args_func():\n        print(\"I accept no arguments, so don't schedule me in the clock\")\n\n    Clock.schedule_once(lambda dt: no_args_func(), 0.5)\n\n.. note::\n\n    You cannot unschedule an anonymous function unless you keep a\n    reference to it. It's better to add \\*args to your function\n    definition so that it can be called with an arbitrary number of\n    parameters.\n\n.. important::\n\n    The callback is weak-referenced: you are responsible for keeping a\n    reference to your original object/callback. If you don't keep a\n    reference, the ClockBase will never execute your callback. For\n    example::\n\n        class Foo(object):\n            def start(self):\n                Clock.schedule_interval(self.callback, 0.5)\n\n            def callback(self, dt):\n                print('In callback')\n\n        # A Foo object is created and the method start is called.\n        # Because no reference is kept to the instance returned from Foo(),\n        # the object will be collected by the Python Garbage Collector and\n        # your callback will be never called.\n        Foo().start()\n\n        # So you should do the following and keep a reference to the instance\n        # of foo until you don't need it anymore!\n        foo = Foo()\n        foo.start()\n\n\n.. _schedule-before-frame:\n\nSchedule before frame\n---------------------\n\n.. versionadded:: 1.0.5\n\nSometimes you need to schedule a callback BEFORE the next frame. Starting\nfrom 1.0.5, you can use a timeout of -1::\n\n    Clock.schedule_once(my_callback, 0) # call after the next frame\n    Clock.schedule_once(my_callback, -1) # call before the next frame\n\nThe Clock will execute all the callbacks with a timeout of -1 before the\nnext frame even if you add a new callback with -1 from a running\ncallback. However, :class:`Clock` has an iteration limit for these\ncallbacks: it defaults to 10.\n\nIf you schedule a callback that schedules a callback that schedules a .. etc\nmore than 10 times, it will leave the loop and send a warning to the console,\nthen continue after the next frame. This is implemented to prevent bugs from\nhanging or crashing the application.\n\nIf you need to increase the limit, set the :attr:`max_iteration` property::\n\n    from kivy.clock import Clock\n    Clock.max_iteration = 20\n\n.. _triggered-events:\n\nTriggered Events\n----------------\n\n.. versionadded:: 1.0.5\n\nA triggered event is a way to defer a callback exactly like schedule_once(),\nbut with some added convenience. The callback will only be scheduled once per\nframe even if you call the trigger twice (or more). This is not the case\nwith :meth:`Clock.schedule_once`::\n\n    # will run the callback twice before the next frame\n    Clock.schedule_once(my_callback)\n    Clock.schedule_once(my_callback)\n\n    # will run the callback once before the next frame\n    t = Clock.create_trigger(my_callback)\n    t()\n    t()\n\nBefore triggered events, you may have used this approach in a widget::\n\n    def trigger_callback(self, *largs):\n        Clock.unschedule(self.callback)\n        Clock.schedule_once(self.callback)\n\nAs soon as you call `trigger_callback()`, it will correctly schedule the\ncallback once in the next frame. It is more convenient to create and bind to\nthe triggered event than using :meth:`Clock.schedule_once` in a function::\n\n    from kivy.clock import Clock\n    from kivy.uix.widget import Widget\n\n    class Sample(Widget):\n        def __init__(self, **kwargs):\n            self._trigger = Clock.create_trigger(self.cb)\n            super(Sample, self).__init__(**kwargs)\n            self.bind(x=self._trigger, y=self._trigger)\n\n        def cb(self, *largs):\n            pass\n\nEven if x and y changes within one frame, the callback is only run once.\n\n.. note::\n\n    :meth:`ClockBase.create_trigger` also has a timeout parameter that\n    behaves exactly like :meth:`ClockBase.schedule_once`.\n\nThreading\n----------\n\n.. versionadded:: 1.9.0\n\nOften, other threads are used to schedule callbacks with kivy's main thread\nusing :class:`ClockBase`. Therefore, it's important to know what is thread safe\nand what isn't.\n\nAll the :class:`ClockBase` and :class:`ClockEvent` methods are safe with\nrespect to kivy's thread. That is, it's always safe to call these methods\nfrom a single thread that is not the kivy thread. However, there are no\nguarantees as to the order in which these callbacks will be executed.\n\nCalling a previously created trigger from two different threads (even if one\nof them is the kivy thread), or calling the trigger and its\n:meth:`ClockEvent.cancel` method from two different threads at the same time is\nnot safe. That is, although no exception will be raised, there no guarantees\nthat calling the trigger from two different threads will not result in the\ncallback being executed twice, or not executed at all. Similarly, such issues\nmight arise when calling the trigger and canceling it with\n:meth:`ClockBase.unschedule` or :meth:`ClockEvent.cancel` from two threads\nsimultaneously.\n\nTherefore, it is safe to call :meth:`ClockBase.create_trigger`,\n:meth:`ClockBase.schedule_once`, :meth:`ClockBase.schedule_interval`, or\ncall or cancel a previously created trigger from an external thread.\nThe following code, though, is not safe because it calls or cancels\nfrom two threads simultaneously without any locking mechanism::\n\n    event = Clock.create_trigger(func)\n\n    # in thread 1\n    event()\n    # in thread 2\n    event()\n    # now, the event may be scheduled twice or once\n\n    # the following is also unsafe\n    # in thread 1\n    event()\n    # in thread 2\n    event.cancel()\n    # now, the event may or may not be scheduled and a subsequent call\n    # may schedule it twice\n\nNote, in the code above, thread 1 or thread 2 could be the kivy thread, not\njust an external thread.\n'''\n\n__all__ = ('Clock', 'ClockBase', 'ClockEvent', 'mainthread')\n\nfrom sys import platform\nfrom os import environ\nfrom functools import wraps, partial\nfrom kivy.context import register_context\nfrom kivy.weakmethod import WeakMethod\nfrom kivy.config import Config\nfrom kivy.logger import Logger\nimport time\n\ntry:\n    import ctypes\n    if platform in ('win32', 'cygwin'):\n        # Win32 Sleep function is only 10-millisecond resolution, so\n        # instead use a waitable timer object, which has up to\n        # 100-nanosecond resolution (hardware and implementation\n        # dependent, of course).\n\n        _kernel32 = ctypes.windll.kernel32\n\n        class _ClockBase(object):\n            def __init__(self):\n                self._timer = _kernel32.CreateWaitableTimerA(None, True, None)\n\n            def usleep(self, microseconds):\n                delay = ctypes.c_longlong(int(-microseconds * 10))\n                _kernel32.SetWaitableTimer(\n                    self._timer, ctypes.byref(delay), 0,\n                    ctypes.c_void_p(), ctypes.c_void_p(), False)\n                _kernel32.WaitForSingleObject(self._timer, 0xffffffff)\n\n        _default_time = time.clock\n    else:\n        if platform == 'darwin':\n            _libc = ctypes.CDLL('libc.dylib')\n        else:\n            _libc = ctypes.CDLL('libc.so')\n        _libc.usleep.argtypes = [ctypes.c_ulong]\n        _libc_usleep = _libc.usleep\n\n        class _ClockBase(object):\n            def usleep(self, microseconds):\n                _libc_usleep(int(microseconds))\n\n        _default_time = time.time\n\nexcept (OSError, ImportError):\n    # ImportError: ctypes is not available on python-for-android.\n    # OSError: if the libc cannot be readed (like with buildbot: invalid ELF\n    # header)\n\n    _default_time = time.time\n    _default_sleep = time.sleep\n\n    class _ClockBase(object):\n        def usleep(self, microseconds):\n            _default_sleep(microseconds / 1000000.)\n\n\ndef _hash(cb):\n    if hasattr(cb, '__self__') and cb.__self__ is not None:\n        return (id(cb.__self__) & 0xFF00) >> 8\n    return (id(cb) & 0xFF00) >> 8\n\n\nclass ClockEvent(object):\n    ''' A class that describes a callback scheduled with kivy's :attr:`Clock`.\n    This class is never created by the user; instead, kivy creates and returns\n    an instance of this class when scheduling a callback.\n\n    .. warning::\n        Most of the methods of this class are internal and can change without\n        notice. The only exception are the :meth:`cancel` and\n        :meth:`__call__` methods.\n    '''\n\n    def __init__(self, clock, loop, callback, timeout, starttime, cid,\n                 trigger=False):\n        self.clock = clock\n        self.cid = cid\n        self.loop = loop\n        self.weak_callback = None\n        self.callback = callback\n        self.timeout = timeout\n        self._is_triggered = trigger\n        self._last_dt = starttime\n        self._dt = 0.\n        if trigger:\n            clock._events[cid].append(self)\n\n    def __call__(self, *largs):\n        ''' Schedules the callback associated with this instance.\n        If the callback is already scheduled, it will not be scheduled again.\n        '''\n        # if the event is not yet triggered, do it !\n        if self._is_triggered is False:\n            self._is_triggered = True\n            # update starttime\n            self._last_dt = self.clock._last_tick\n            self.clock._events[self.cid].append(self)\n            return True\n\n    def get_callback(self):\n        callback = self.callback\n        if callback is not None:\n            return callback\n        callback = self.weak_callback\n        if callback.is_dead():\n            return None\n        return callback()\n\n    @property\n    def is_triggered(self):\n        return self._is_triggered\n\n    def cancel(self):\n        ''' Cancels the callback if it was scheduled to be called.\n        '''\n        if self._is_triggered:\n            self._is_triggered = False\n            try:\n                self.clock._events[self.cid].remove(self)\n            except ValueError:\n                pass\n\n    def release(self):\n        self.weak_callback = WeakMethod(self.callback)\n        self.callback = None\n\n    def tick(self, curtime, remove):\n        # timeout happened ? (check also if we would miss from 5ms) this\n        # 5ms increase the accuracy if the timing of animation for\n        # example.\n        if curtime - self._last_dt < self.timeout - 0.005:\n            return True\n\n        # calculate current timediff for this event\n        self._dt = curtime - self._last_dt\n        self._last_dt = curtime\n        loop = self.loop\n\n        # get the callback\n        callback = self.get_callback()\n        if callback is None:\n            self._is_triggered = False\n            try:\n                remove(self)\n            except ValueError:\n                pass\n            return False\n\n        # if it's a trigger, allow to retrigger inside the callback\n        # we have to remove event here, otherwise, if we remove later, the user\n        # might have canceled in the callback and then re-triggered. That'd\n        # result in the removal of the re-trigger\n        if not loop:\n            self._is_triggered = False\n            try:\n                remove(self)\n            except ValueError:\n                pass\n\n        # call the callback\n        ret = callback(self._dt)\n\n        # if the user returns False explicitly, remove the event\n        if loop and ret is False:\n            self._is_triggered = False\n            try:\n                remove(self)\n            except ValueError:\n                pass\n            return False\n        return loop\n\n    def __repr__(self):\n        return '<ClockEvent callback=%r>' % self.get_callback()\n\n\nclass ClockBase(_ClockBase):\n    '''A clock object with event support.\n    '''\n    __slots__ = ('_dt', '_last_fps_tick', '_last_tick', '_fps', '_rfps',\n                 '_start_tick', '_fps_counter', '_rfps_counter', '_events',\n                 '_frames', '_frames_displayed',\n                 '_max_fps', 'max_iteration')\n\n    MIN_SLEEP = 0.005\n    SLEEP_UNDERSHOOT = MIN_SLEEP - 0.001\n\n    def __init__(self):\n        super(ClockBase, self).__init__()\n        self._dt = 0.0001\n        self._start_tick = self._last_tick = self.time()\n        self._fps = 0\n        self._rfps = 0\n        self._fps_counter = 0\n        self._rfps_counter = 0\n        self._last_fps_tick = None\n        self._frames = 0\n        self._frames_displayed = 0\n        self._events = [[] for i in range(256)]\n        self._max_fps = float(Config.getint('graphics', 'maxfps'))\n\n        #: .. versionadded:: 1.0.5\n        #:     When a schedule_once is used with -1, you can add a limit on\n        #:     how iteration will be allowed. That is here to prevent too much\n        #:     relayout.\n        self.max_iteration = 10\n\n    @property\n    def frametime(self):\n        '''Time spent between the last frame and the current frame\n        (in seconds).\n\n        .. versionadded:: 1.8.0\n        '''\n        return self._dt\n\n    @property\n    def frames(self):\n        '''Number of internal frames (not necesseraly drawed) from the start of\n        the clock.\n\n        .. versionadded:: 1.8.0\n        '''\n        return self._frames\n\n    @property\n    def frames_displayed(self):\n        '''Number of displayed frames from the start of the clock.\n        '''\n        return self._frames_displayed\n\n    def tick(self):\n        '''Advance the clock to the next step. Must be called every frame.\n        The default clock has a tick() function called by the core Kivy\n        framework.'''\n\n        self._release_references()\n\n        # do we need to sleep ?\n        if self._max_fps > 0:\n            min_sleep = self.MIN_SLEEP\n            sleep_undershoot = self.SLEEP_UNDERSHOOT\n            fps = self._max_fps\n            usleep = self.usleep\n\n            sleeptime = 1 / fps - (self.time() - self._last_tick)\n            while sleeptime - sleep_undershoot > min_sleep:\n                usleep(1000000 * (sleeptime - sleep_undershoot))\n                sleeptime = 1 / fps - (self.time() - self._last_tick)\n\n        # tick the current time\n        current = self.time()\n        self._dt = current - self._last_tick\n        self._frames += 1\n        self._fps_counter += 1\n        self._last_tick = current\n\n        # calculate fps things\n        if self._last_fps_tick is None:\n            self._last_fps_tick = current\n        elif current - self._last_fps_tick > 1:\n            d = float(current - self._last_fps_tick)\n            self._fps = self._fps_counter / d\n            self._rfps = self._rfps_counter\n            self._last_fps_tick = current\n            self._fps_counter = 0\n            self._rfps_counter = 0\n\n        # process event\n        self._process_events()\n\n        return self._dt\n\n    def tick_draw(self):\n        '''Tick the drawing counter.\n        '''\n        self._process_events_before_frame()\n        self._rfps_counter += 1\n        self._frames_displayed += 1\n\n    def get_fps(self):\n        '''Get the current average FPS calculated by the clock.\n        '''\n        return self._fps\n\n    def get_rfps(self):\n        '''Get the current \"real\" FPS calculated by the clock.\n        This counter reflects the real framerate displayed on the screen.\n\n        In contrast to get_fps(), this function returns a counter of the\n        number of frames, not the average of frames per second.\n        '''\n        return self._rfps\n\n    def get_time(self):\n        '''Get the last tick made by the clock.'''\n        return self._last_tick\n\n    def get_boottime(self):\n        '''Get the time in seconds from the application start.'''\n        return self._last_tick - self._start_tick\n\n    def create_trigger(self, callback, timeout=0):\n        '''Create a Trigger event. Check module documentation for more\n        information.\n\n        :returns:\n\n            A :class:`ClockEvent` instance. To schedule the callback of this\n            instance, you can call it.\n\n        .. versionadded:: 1.0.5\n        '''\n        ev = ClockEvent(self, False, callback, timeout, 0, _hash(callback))\n        ev.release()\n        return ev\n\n    def schedule_once(self, callback, timeout=0):\n        '''Schedule an event in <timeout> seconds. If <timeout> is unspecified\n        or 0, the callback will be called after the next frame is rendered.\n\n        :returns:\n\n            A :class:`ClockEvent` instance. As opposed to\n            :meth:`create_trigger` which only creates the trigger event, this\n            method also schedules it.\n\n        .. versionchanged:: 1.0.5\n            If the timeout is -1, the callback will be called before the next\n            frame (at :meth:`tick_draw`).\n        '''\n        if not callable(callback):\n            raise ValueError('callback must be a callable, got %s' % callback)\n        event = ClockEvent(\n            self, False, callback, timeout, self._last_tick, _hash(callback),\n            True)\n        return event\n\n    def schedule_interval(self, callback, timeout):\n        '''Schedule an event to be called every <timeout> seconds.\n\n        :returns:\n\n            A :class:`ClockEvent` instance. As opposed to\n            :meth:`create_trigger` which only creates the trigger event, this\n            method also schedules it.\n        '''\n        if not callable(callback):\n            raise ValueError('callback must be a callable, got %s' % callback)\n        event = ClockEvent(\n            self, True, callback, timeout, self._last_tick, _hash(callback),\n            True)\n        return event\n\n    def unschedule(self, callback, all=True):\n        '''Remove a previously scheduled event.\n\n        :parameters:\n\n            `callback`: :class:`ClockEvent` or a callable.\n                If it's a :class:`ClockEvent` instance, then the callback\n                associated with this event will be canceled if it is\n                scheduled. If it's a callable, then the callable will be\n                unscheduled if it is scheduled.\n            `all`: bool\n                If True and if `callback` is a callable, all instances of this\n                callable will be unscheduled (i.e. if this callable was\n                scheduled multiple times). Defaults to `True`.\n\n        .. versionchanged:: 1.9.0\n            The all parameter was added. Before, it behaved as if `all` was\n            `True`.\n        '''\n        if isinstance(callback, ClockEvent):\n            callback.cancel()\n        else:\n            if all:\n                for ev in self._events[_hash(callback)][:]:\n                    if ev.get_callback() == callback:\n                        ev.cancel()\n            else:\n                for ev in self._events[_hash(callback)][:]:\n                    if ev.get_callback() == callback:\n                        ev.cancel()\n                        break\n\n    def _release_references(self):\n        # call that function to release all the direct reference to any\n        # callback and replace it with a weakref\n        events = self._events\n        for events in self._events:\n            for event in events[:]:\n                if event.callback is not None:\n                    event.release()\n\n    def _process_events(self):\n        for events in self._events:\n            remove = events.remove\n            for event in events[:]:\n                # event may be already removed from original list\n                if event in events:\n                    event.tick(self._last_tick, remove)\n\n    def _process_events_before_frame(self):\n        found = True\n        count = self.max_iteration\n        events = self._events\n        while found:\n            count -= 1\n            if count == -1:\n                Logger.critical(\n                    'Clock: Warning, too much iteration done before'\n                    ' the next frame. Check your code, or increase'\n                    ' the Clock.max_iteration attribute')\n                break\n\n            # search event that have timeout = -1\n            found = False\n            for events in self._events:\n                remove = events.remove\n                for event in events[:]:\n                    if event.timeout != -1:\n                        continue\n                    found = True\n                    # event may be already removed from original list\n                    if event in events:\n                        event.tick(self._last_tick, remove)\n\n    time = staticmethod(partial(_default_time))\n\nClockBase.time.__doc__ = '''Proxy method for time.time() or time.clock(),\nwhichever is more suitable for the running OS'''\n\n\ndef mainthread(func):\n    '''Decorator that will schedule the call of the function for the next\n    available frame in the mainthread. It can be useful when you use\n    :class:`~kivy.network.urlrequest.UrlRequest` or when you do Thread\n    programming: you cannot do any OpenGL-related work in a thread.\n\n    Please note that this method will return directly and no result can be\n    returned::\n\n        @mainthread\n        def callback(self, *args):\n            print('The request succedded!',\n                  'This callback is called in the main thread.')\n\n        self.req = UrlRequest(url='http://...', on_success=callback)\n\n    .. versionadded:: 1.8.0\n    '''\n    @wraps(func)\n    def delayed_func(*args, **kwargs):\n        def callback_func(dt):\n            func(*args, **kwargs)\n        Clock.schedule_once(callback_func, 0)\n    return delayed_func\n\nif 'KIVY_DOC_INCLUDE' in environ:\n    #: Instance of :class:`ClockBase`.\n    Clock = None\nelse:\n    Clock = register_context('Clock', ClockBase)\n"
  },
  {
    "path": "tickeys/kivy/compat.py",
    "content": "'''\nCompatibility module for Python 2.7 and > 3.3\n=============================================\n'''\n\n__all__ = ('PY2', 'string_types', 'queue', 'iterkeys',\n           'itervalues', 'iteritems')\n\nimport sys\ntry:\n    import queue\nexcept ImportError:\n    import Queue as queue\n\n#: True if Python 2 intepreter is used\nPY2 = sys.version_info[0] == 2\n\n#: String types that can be used for checking if a object is a string\nstring_types = None\ntext_type = None\nif PY2:\n    string_types = basestring\n    text_type = unicode\nelse:\n    string_types = text_type = str\n\n#: unichr is just chr in py3, since all strings are unicode\nif PY2:\n    unichr = unichr\nelse:\n    unichr = chr\n\nif PY2:\n    iterkeys = lambda d: d.iterkeys()\n    itervalues = lambda d: d.itervalues()\n    iteritems = lambda d: d.iteritems()\nelse:\n    iterkeys = lambda d: iter(d.keys())\n    itervalues = lambda d: iter(d.values())\n    iteritems = lambda d: iter(d.items())\n"
  },
  {
    "path": "tickeys/kivy/config.py",
    "content": "'''\nConfiguration object\n====================\n\nThe :class:`Config` object is an instance of a modified Python ConfigParser.\nSee the `ConfigParser documentation\n<http://docs.python.org/library/configparser.html>`_ for more information.\n\nKivy has a configuration file which determines the default settings. In\norder to change these settings, you can alter this file manually or use\nthe Config object. Please see the :ref:`Configure Kivy` section for more\ninformation.\n\nNote: To avoid instances where the config settings do not work or they are\nnot applied before window creation (like setting an initial window size),\nConfig.set should be used before importing any modules that affect the\napplication window (ie. importing Window). Ideally, these settings should\nbe declared right at the start of your main.py script.\n\nUsage of the Config object\n--------------------------\n\nTo read a configuration token from a particular section::\n\n    >>> from kivy.config import Config\n    >>> Config.getint('kivy', 'show_fps')\n    0\n\nChange the configuration and save it::\n\n    >>> Config.set('postproc', 'retain_time', '50')\n    >>> Config.write()\n\n.. versionchanged:: 1.7.1\n    The ConfigParser should work correctly with utf-8 now. The values are\n    converted from ascii to unicode only when needed. The method get() returns\n    utf-8 strings.\n\n.. _configuration-tokens:\n\nAvailable configuration tokens\n------------------------------\n\n.. |log_levels| replace:: 'debug', 'info', 'warning', 'error' or 'critical'\n\n:kivy:\n\n    `desktop`: int, 0 or 1\n        This option controls desktop OS specific features, such as enabling\n        drag-able scroll-bar in scroll views, disabling of bubbles in\n        TextInput etc. 0 is disabled, 1 is enabled.\n    `exit_on_escape`: int, 0 or 1\n        Enables exiting kivy when escape is pressed.\n        0 is disabled, 1 is enabled.\n    `pause_on_minimize`: int, 0 or 1\n        If set to `1`, the main loop is paused and the `on_pause` event\n        is dispatched when the window is minimized. This option is intended\n        for desktop use only. Defaults to `0`.\n    `keyboard_layout`: string\n        Identifier of the layout to use.\n    `keyboard_mode`: string\n        Specifies the keyboard mode to use. If can be one of the following:\n\n        * '' - Let Kivy choose the best option for your current platform.\n        * 'system' - real keyboard.\n        * 'dock' - one virtual keyboard docked to a screen side.\n        * 'multi' - one virtual keyboard for every widget request.\n        * 'systemanddock' - virtual docked keyboard plus input from real\n          keyboard.\n        * 'systemandmulti' - analogous.\n    `log_dir`: string\n        Path of log directory.\n    `log_enable`: int, 0 or 1\n        Activate file logging. 0 is disabled, 1 is enabled.\n    `log_level`: string, one of |log_levels|\n        Set the minimum log level to use.\n    `log_name`: string\n        Format string to use for the filename of log file.\n    `window_icon`: string\n        Path of the window icon. Use this if you want to replace the default\n        pygame icon.\n\n:postproc:\n\n    `double_tap_distance`: float\n        Maximum distance allowed for a double tap, normalized inside the range\n        0 - 1000.\n    `double_tap_time`: int\n        Time allowed for the detection of double tap, in milliseconds.\n    `ignore`: list of tuples\n        List of regions where new touches are ignored.\n        This configuration token can be used to resolve hotspot problems\n        with DIY hardware. The format of the list must be::\n\n            ignore = [(xmin, ymin, xmax, ymax), ...]\n\n        All the values must be inside the range 0 - 1.\n    `jitter_distance`: int\n        Maximum distance for jitter detection, normalized inside the range 0\n        - 1000.\n    `jitter_ignore_devices`: string, separated with commas\n        List of devices to ignore from jitter detection.\n    `retain_distance`: int\n        If the touch moves more than is indicated by retain_distance, it will\n        not be retained. Argument should be an int between 0 and 1000.\n    `retain_time`: int\n        Time allowed for a retain touch, in milliseconds.\n    `triple_tap_distance`: float\n        Maximum distance allowed for a triple tap, normalized inside the range\n        0 - 1000.\n    `triple_tap_time`: int\n        Time allowed for the detection of triple tap, in milliseconds.\n\n:graphics:\n    `borderless`: int , one of 0 or 1\n        If set to `1`, removes the window border/decoration.\n    `window_state`: string , one of 'visible', 'hidden', 'maximized'\n    or 'minimized'\n        Sets the window state, defaults to 'visible'. This option is available\n        only for the SDL2 window provider and it should be used on desktop\n        OSes.\n    `fbo`: string, one of 'hardware', 'software' or 'force-hardware'\n        Selects the FBO backend to use.\n    `fullscreen`: int or string, one of 0, 1, 'fake' or 'auto'\n        Activate fullscreen. If set to `1`, a resolution of `width`\n        times `height` pixels will be used.\n        If set to `auto`, your current display's resolution will be\n        used instead. This is most likely what you want.\n        If you want to place the window in another display,\n        use `fake`, or set the `borderless` option from the graphics section,\n        then adjust `width`, `height`, `top` and `left`.\n    `height`: int\n        Height of the :class:`~kivy.core.window.Window`, not used if\n        `fullscreen` is set to `auto`.\n    `left`: int\n        Left position of the :class:`~kivy.core.window.Window`.\n    `maxfps`: int, defaults to 60\n        Maximum FPS allowed.\n    'multisamples': int, defaults to 2\n        Sets the `MultiSample Anti-Aliasing (MSAA)\n        <http://en.wikipedia.org/wiki/Multisample_anti-aliasing>`_ level.\n        Increasing this value results in smoother graphics but at the cost of\n        processing time.\n\n        .. note::\n\n           This feature is limited by device hardware support and will have no\n           effect on devices which do not support the level of MSAA requested.\n\n    `position`: string, one of 'auto' or 'custom'\n        Position of the window on your display. If `auto` is used, you have no\n        control of the initial position: `top` and `left` are ignored.\n    `show_cursor`: int, one of 0 or 1\n        Show the cursor on the screen.\n    `top`: int\n        Top position of the :class:`~kivy.core.window.Window`.\n    `resizable`: int, one of 0 or 1\n        If 0, the window will have a fixed size. If 1, the window will be\n        resizable.\n    `rotation`: int, one of 0, 90, 180 or 270\n        Rotation of the :class:`~kivy.core.window.Window`.\n    `width`: int\n        Width of the :class:`~kivy.core.window.Window`, not used if\n        `fullscreen` is set to `auto`.\n\n:input:\n\n    You can create new input devices using this syntax::\n\n        # example of input provider instance\n        yourid = providerid,parameters\n\n        # example for tuio provider\n        default = tuio,127.0.0.1:3333\n        mytable = tuio,192.168.0.1:3334\n\n    .. seealso::\n\n        Check the providers in kivy.input.providers for the syntax to use\n        inside the configuration file.\n\n:widgets:\n\n    `scroll_distance`: int\n        Default value of the\n        :attr:`~kivy.uix.scrollview.ScrollView.scroll_distance`\n        property used by the :class:`~kivy.uix.scrollview.ScrollView` widget.\n        Check the widget documentation for more information.\n\n    `scroll_friction`: float\n        Default value of the\n        :attr:`~kivy.uix.scrollview.ScrollView.scroll_friction`\n        property used by the :class:`~kivy.uix.scrollview.ScrollView` widget.\n        Check the widget documentation for more information.\n\n    `scroll_timeout`: int\n        Default value of the\n        :attr:`~kivy.uix.scrollview.ScrollView.scroll_timeout`\n        property used by the  :class:`~kivy.uix.scrollview.ScrollView` widget.\n        Check the widget documentation for more information.\n\n    `scroll_stoptime`: int\n        Default value of the\n        :attr:`~kivy.uix.scrollview.ScrollView.scroll_stoptime`\n        property used by the :class:`~kivy.uix.scrollview.ScrollView` widget.\n        Check the widget documentation for more information.\n\n        .. deprecated:: 1.7.0\n            Please use\n            :class:`~kivy.uix.scrollview.ScrollView.effect_cls` instead.\n\n    `scroll_moves`: int\n        Default value of the\n        :attr:`~kivy.uix.scrollview.ScrollView.scroll_moves`\n        property used by the :class:`~kivy.uix.scrollview.ScrollView` widget.\n        Check the widget documentation for more information.\n\n        .. deprecated:: 1.7.0\n            Please use\n            :class:`~kivy.uix.scrollview.ScrollView.effect_cls` instead.\n\n:modules:\n\n    You can activate modules with this syntax::\n\n        modulename =\n\n    Anything after the = will be passed to the module as arguments.\n    Check the specific module's documentation for a list of accepted\n    arguments.\n\n.. note::\n\n    These options control only the initalization of the app and a restart\n    is required for value changes to take effect.\n\n.. versionchanged:: 1.9.0\n    `borderless` and `window_state` have been added to the graphics section.\n    The `fake` setting of the `fullscreen` option has been deprecated,\n    use the `borderless` option instead.\n    `pause_on_minimize` has been added to the kivy section.\n\n.. versionchanged:: 1.8.0\n    `systemanddock` and `systemandmulti` has been added as possible values for\n    `keyboard_mode` in the kivy section. `exit_on_escape` has been added\n    to the kivy section.\n\n.. versionchanged:: 1.2.0\n    `resizable` has been added to graphics section.\n\n.. versionchanged:: 1.1.0\n    tuio no longer listens by default. Window icons are not copied to\n    user directory anymore. You can still set a new window icon by using the\n    ``window_icon`` config setting.\n\n.. versionchanged:: 1.0.8\n    `scroll_timeout`, `scroll_distance` and `scroll_friction` have been added.\n    `list_friction`, `list_trigger_distance` and `list_friction_bound`\n    have been removed. `keyboard_type` and `keyboard_layout` have been\n    removed from the widget. `keyboard_mode` and `keyboard_layout` have\n    been added to the kivy section.\n'''\n\n__all__ = ('Config', 'ConfigParser')\n\ntry:\n    from ConfigParser import ConfigParser as PythonConfigParser\nexcept ImportError:\n    from configparser import RawConfigParser as PythonConfigParser\nfrom os import environ\nfrom os.path import exists\nfrom kivy import kivy_config_fn\nfrom kivy.logger import Logger, logger_config_update\nfrom collections import OrderedDict\nfrom kivy.utils import platform\nfrom kivy.compat import PY2, string_types\nfrom weakref import ref\n\n_is_rpi = exists('/opt/vc/include/bcm_host.h')\n\n# Version number of current configuration format\nKIVY_CONFIG_VERSION = 13\n\nConfig = None\n'''Kivy configuration object. Its :attr:`~kivy.config.ConfigParser.name` is\n`'kivy'`\n'''\n\n\nclass ConfigParser(PythonConfigParser, object):\n    '''Enhanced ConfigParser class that supports the addition of default\n    sections and default values.\n\n    By default, the kivy ConfigParser instance, :attr:`~kivy.config.Config`,\n    is given the name `'kivy'` and the ConfigParser instance used by App,\n    :meth:`~kivy.app.App.build_settings`, is given the name `'app'`.\n\n    :Parameters:\n        `name`: string\n            The name of the instance. See :attr:`name`. Defaults to `''`.\n\n    ..versionchanged:: 1.9.0\n        Each ConfigParser can now be named, :attr:`name`. You can get the\n        ConfigParser associated with a name using :meth:`get_configparser`.\n        In addition, you can now control the config values with\n        :class:`~kivy.properties.ConfigParserProperty`.\n\n    .. versionadded:: 1.0.7\n    '''\n\n    def __init__(self, name=''):\n        PythonConfigParser.__init__(self)\n        self._sections = OrderedDict()\n        self.filename = None\n        self._callbacks = []\n        self.name = name\n\n    def add_callback(self, callback, section=None, key=None):\n        '''Add a callback to be called when a specific section/key changed. If\n        you don't specify a section or a key, it will call the callback\n        for all section/keys changes.\n\n        Callbacks will receive 3 arguments: the section, key and value.\n\n        .. versionadded:: 1.4.1\n        '''\n        if section is None and key is not None:\n            raise Exception('You cannot specify a key without a section')\n        self._callbacks.append((callback, section, key))\n\n    def remove_callback(self, callback, section=None, key=None):\n        '''Removes a callback added with :meth:`add_callback`.\n        :meth:`remove_callback` must be called with the same parameters as\n        :meth:`add_callback`.\n\n        Raises a `ValueError` if not found.\n\n        .. versionadded:: 1.9.0\n        '''\n        self._callbacks.remove((callback, section, key))\n\n    def _do_callbacks(self, section, key, value):\n        for callback, csection, ckey in self._callbacks:\n            if csection is not None and csection != section:\n                continue\n            elif ckey is not None and ckey != key:\n                continue\n            callback(section, key, value)\n\n    def read(self, filename):\n        '''Read only one filename. In contrast to the original ConfigParser of\n        Python, this one is able to read only one file at a time. The last\n        read file will be used for the :meth:`write` method.\n\n        .. versionchanged:: 1.9.0\n            :meth:`read` now calls the callbacks if read changed any values.\n\n        '''\n        if not isinstance(filename, string_types):\n            raise Exception('Only one filename is accepted ({})'.format(\n                string_types.__name__))\n        self.filename = filename\n        # If we try to open directly the configuration file in utf-8,\n        # we correctly get the unicode value by default.\n        # But, when we try to save it again, all the values we didn't changed\n        # are still unicode, and then the PythonConfigParser internal do\n        # a str() conversion -> fail.\n        # Instead we currently to the conversion to utf-8 when value are\n        # \"get()\", but we internally store them in ascii.\n        #with codecs.open(filename, 'r', encoding='utf-8') as f:\n        #    self.readfp(f)\n        old_vals = {sect: {k: v for k, v in self.items(sect)} for sect in\n                    self.sections()}\n        PythonConfigParser.read(self, filename)\n\n        # when reading new file, sections/keys are only increased, not removed\n        f = self._do_callbacks\n        for section in self.sections():\n            if section not in old_vals:  # new section\n                for k, v in self.items(section):\n                    f(section, k, v)\n                continue\n\n            old_keys = old_vals[section]\n            for k, v in self.items(section):  # just update new/changed keys\n                if k not in old_keys or v != old_keys[k]:\n                    f(section, k, v)\n\n    def set(self, section, option, value):\n        '''Functions similarly to PythonConfigParser's set method, except that\n        the value is implicitly converted to a string.\n        '''\n        e_value = value\n        if not isinstance(value, string_types):\n            # might be boolean, int, etc.\n            e_value = str(value)\n        if PY2:\n            if isinstance(value, unicode):\n                e_value = value.encode('utf-8')\n        ret = PythonConfigParser.set(self, section, option, e_value)\n        self._do_callbacks(section, option, value)\n        return ret\n\n    def setall(self, section, keyvalues):\n        '''Set a lot of keys/values in one section at the same time.\n        '''\n        for key, value in keyvalues.items():\n            self.set(section, key, value)\n\n    def get(self, section, option, **kwargs):\n        value = PythonConfigParser.get(self, section, option, **kwargs)\n        if PY2:\n            if type(value) is str:\n                return value.decode('utf-8')\n        return value\n\n    def setdefaults(self, section, keyvalues):\n        '''Set a lot of keys/value defaults in one section at the same time.\n        '''\n        self.adddefaultsection(section)\n        for key, value in keyvalues.items():\n            self.setdefault(section, key, value)\n\n    def setdefault(self, section, option, value):\n        '''Set the default value of a particular option.\n        '''\n        if self.has_option(section, option):\n            return\n        self.set(section, option, value)\n\n    def getdefault(self, section, option, defaultvalue):\n        '''Get an option. If not found, it will return the default value.\n        '''\n        if not self.has_section(section):\n            return defaultvalue\n        if not self.has_option(section, option):\n            return defaultvalue\n        return self.get(section, option)\n\n    def getdefaultint(self, section, option, defaultvalue):\n        '''Get an option. If not found, it will return the default value.\n        The return value will be always converted as an integer.\n\n        .. versionadded:: 1.6.0\n        '''\n        return int(self.getdefault(section, option, defaultvalue))\n\n    def adddefaultsection(self, section):\n        '''Add a section if the section is missing.\n        '''\n        if self.has_section(section):\n            return\n        self.add_section(section)\n\n    def write(self):\n        '''Write the configuration to the last file opened using the\n         :meth:`read` method.\n\n        Return True if the write finished successfully.\n        '''\n        if self.filename is None:\n            return False\n        try:\n            with open(self.filename, 'w') as fd:\n                PythonConfigParser.write(self, fd)\n        except IOError:\n            Logger.exception('Unable to write the config <%s>' % self.filename)\n            return False\n        return True\n\n    def update_config(self, filename, overwrite=False):\n        '''Upgrade the configuration based on a new default config file.\n           Overwrite any existing values if overwrite is True.\n        '''\n        pcp = PythonConfigParser()\n        pcp.read(filename)\n        confset = self.setall if overwrite else self.setdefaults\n        for section in pcp.sections():\n            confset(section, dict(pcp.items(section)))\n        self.write()\n\n    @staticmethod\n    def _register_named_property(name, widget_ref, *largs):\n        ''' Called by the ConfigParserProperty to register a property which\n        was created with a config name instead of a config object.\n\n        When a ConfigParser with this name is later created, the properties\n        are then notified that this parser now exists so they can use it.\n        If the parser already exists, the property is notified here. See\n        :meth:`~kivy.properties.ConfigParserProperty.set_config`.\n\n        :Parameters:\n            `name`: a non-empty string\n                The name of the ConfigParser that is associated with the\n                property. See :attr:`name`.\n            `widget_ref`: 2-tuple.\n                The first element is a reference to the widget containing the\n                property, the second element is the name of the property. E.g.:\n\n                    class House(Widget):\n                        address = ConfigParserProperty('', 'info', 'street',\n                            'directory')\n\n                Then, the first element is a ref to a House instance, and the\n                second is `'address'`.\n        '''\n        configs = ConfigParser._named_configs\n        try:\n            config, props = configs[name]\n        except KeyError:\n            configs[name] = (None, [widget_ref])\n            return\n\n        props.append(widget_ref)\n        if config:\n            config = config()\n        widget = widget_ref[0]()\n\n        if config and widget:  # associate this config with property\n            widget.property(widget_ref[1]).set_config(config)\n\n    @staticmethod\n    def get_configparser(name):\n        '''Returns the :class:`ConfigParser` instance whose name is `name`, or\n        None if not found.\n\n        :Parameters:\n            `name`: string\n                The name of the :class:`ConfigParser` instance to return.\n        '''\n        try:\n            config = ConfigParser._named_configs[name][0]\n            return config() if config else None\n        except KeyError:\n            return None\n\n    # keys are configparser names, values are 2-tuple of (ref(configparser),\n    # widget_ref), where widget_ref is same as in _register_named_property\n    _named_configs = {}\n    _name = ''\n\n    @property\n    def name(self):\n        ''' The name associated with this ConfigParser instance, if not `''`.\n        Defaults to `''`. It can be safely dynamically changed or set to `''`.\n\n        When a ConfigParser is given a name, that config object can be\n        retrieved using :meth:`get_configparser`. In addition, that config\n        instance can also be used with a\n        :class:`~kivy.properties.ConfigParserProperty` instance that set its\n        `config` value to this name.\n\n        Setting more than one ConfigParser with the same name will raise a\n        `ValueError`.\n        '''\n        return self._name\n\n    @name.setter\n    def name(self, value):\n        old_name = self._name\n        if value is old_name:\n            return\n        self._name = value\n        configs = ConfigParser._named_configs\n\n        if old_name:  # disconnect this parser from previously connected props\n            _, props = configs.get(old_name, (None, []))\n            for widget, prop in props:\n                widget = widget()\n                if widget:\n                    widget.property(prop).set_config(None)\n            configs[old_name] = (None, props)\n\n        if not value:\n            return\n\n        # if given new name, connect it with property that used this name\n        try:\n            config, props = configs[value]\n        except KeyError:\n            configs[value] = (ref(self), [])\n            return\n\n        if config is not None:\n            raise ValueError('A parser named {} already exists'.format(value))\n        for widget, prop in props:\n            widget = widget()\n            if widget:\n                widget.property(prop).set_config(self)\n        configs[value] = (ref(self), props)\n\n\nif not environ.get('KIVY_DOC_INCLUDE'):\n\n    #\n    # Read, analyse configuration file\n    # Support upgrade of older config file versions\n    #\n\n    # Create default configuration\n    Config = ConfigParser(name='kivy')\n    Config.add_callback(logger_config_update, 'kivy', 'log_level')\n\n    # Read config file if exist\n    if (exists(kivy_config_fn) and\n            'KIVY_USE_DEFAULTCONFIG' not in environ and\n            'KIVY_NO_CONFIG' not in environ):\n        try:\n            Config.read(kivy_config_fn)\n        except Exception as e:\n            Logger.exception('Core: error while reading local'\n                             'configuration')\n\n    version = Config.getdefaultint('kivy', 'config_version', 0)\n\n    # Add defaults section\n    Config.adddefaultsection('kivy')\n    Config.adddefaultsection('graphics')\n    Config.adddefaultsection('input')\n    Config.adddefaultsection('postproc')\n    Config.adddefaultsection('widgets')\n    Config.adddefaultsection('modules')\n\n    # Upgrade default configuration until we have the current version\n    need_save = False\n    if version != KIVY_CONFIG_VERSION and 'KIVY_NO_CONFIG' not in environ:\n        Logger.warning('Config: Older configuration version detected'\n                       ' ({0} instead of {1})'.format(\n                           version, KIVY_CONFIG_VERSION))\n        Logger.warning('Config: Upgrading configuration in progress.')\n        need_save = True\n\n    while version < KIVY_CONFIG_VERSION:\n        Logger.debug('Config: Upgrading from %d to %d' %\n                     (version, version + 1))\n\n        if version == 0:\n\n            # log level\n            Config.setdefault('kivy', 'keyboard_repeat_delay', '300')\n            Config.setdefault('kivy', 'keyboard_repeat_rate', '30')\n            Config.setdefault('kivy', 'log_dir', 'logs')\n            Config.setdefault('kivy', 'log_enable', '1')\n            Config.setdefault('kivy', 'log_level', 'info')\n            Config.setdefault('kivy', 'log_name', 'kivy_%y-%m-%d_%_.txt')\n            Config.setdefault('kivy', 'window_icon', '')\n\n            # default graphics parameters\n            Config.setdefault('graphics', 'display', '-1')\n            Config.setdefault('graphics', 'fullscreen', 'no')\n            Config.setdefault('graphics', 'height', '600')\n            Config.setdefault('graphics', 'left', '0')\n            Config.setdefault('graphics', 'maxfps', '0')\n            Config.setdefault('graphics', 'multisamples', '2')\n            Config.setdefault('graphics', 'position', 'auto')\n            Config.setdefault('graphics', 'rotation', '0')\n            Config.setdefault('graphics', 'show_cursor', '1')\n            Config.setdefault('graphics', 'top', '0')\n            Config.setdefault('graphics', 'vsync', '1')\n            Config.setdefault('graphics', 'width', '800')\n\n            # input configuration\n            Config.setdefault('input', 'mouse', 'mouse')\n\n            # activate native input provider in configuration\n            # from 1.0.9, don't activate mactouch by default, or app are\n            # unusable.\n            if platform == 'win':\n                Config.setdefault('input', 'wm_touch', 'wm_touch')\n                Config.setdefault('input', 'wm_pen', 'wm_pen')\n            elif platform == 'linux':\n                probesysfs = 'probesysfs'\n                if _is_rpi:\n                    probesysfs += ',provider=hidinput'\n                Config.setdefault('input', '%(name)s', probesysfs)\n\n            # input postprocessing configuration\n            Config.setdefault('postproc', 'double_tap_distance', '20')\n            Config.setdefault('postproc', 'double_tap_time', '250')\n            Config.setdefault('postproc', 'ignore', '[]')\n            Config.setdefault('postproc', 'jitter_distance', '0')\n            Config.setdefault('postproc', 'jitter_ignore_devices',\n                              'mouse,mactouch,')\n            Config.setdefault('postproc', 'retain_distance', '50')\n            Config.setdefault('postproc', 'retain_time', '0')\n\n            # default configuration for keyboard repeatition\n            Config.setdefault('widgets', 'keyboard_layout', 'qwerty')\n            Config.setdefault('widgets', 'keyboard_type', '')\n            Config.setdefault('widgets', 'list_friction', '10')\n            Config.setdefault('widgets', 'list_friction_bound', '20')\n            Config.setdefault('widgets', 'list_trigger_distance', '5')\n\n        elif version == 1:\n            Config.remove_option('graphics', 'vsync')\n            Config.set('graphics', 'maxfps', '60')\n\n        elif version == 2:\n            # was a version to automatically copy windows icon in the user\n            # directory, but it's now not used anymore. User can still change\n            # the window icon by touching the config.\n            pass\n\n        elif version == 3:\n            # add token for scrollview\n            Config.setdefault('widgets', 'scroll_timeout', '55')\n            Config.setdefault('widgets', 'scroll_distance', '20')\n            Config.setdefault('widgets', 'scroll_friction', '1.')\n\n            # remove old list_* token\n            Config.remove_option('widgets', 'list_friction')\n            Config.remove_option('widgets', 'list_friction_bound')\n            Config.remove_option('widgets', 'list_trigger_distance')\n\n        elif version == 4:\n            Config.remove_option('widgets', 'keyboard_type')\n            Config.remove_option('widgets', 'keyboard_layout')\n\n            # add keyboard token\n            Config.setdefault('kivy', 'keyboard_mode', '')\n            Config.setdefault('kivy', 'keyboard_layout', 'qwerty')\n\n        elif version == 5:\n            Config.setdefault('graphics', 'resizable', '1')\n\n        elif version == 6:\n            # if the timeout is still the default value, change it\n            Config.setdefault('widgets', 'scroll_stoptime', '300')\n            Config.setdefault('widgets', 'scroll_moves', '5')\n\n        elif version == 7:\n            # desktop bool indicating whether to use desktop specific features\n            is_desktop = int(platform in ('win', 'macosx', 'linux'))\n            Config.setdefault('kivy', 'desktop', is_desktop)\n            Config.setdefault('postproc', 'triple_tap_distance', '20')\n            Config.setdefault('postproc', 'triple_tap_time', '375')\n\n        elif version == 8:\n            if Config.getint('widgets', 'scroll_timeout') == 55:\n                Config.set('widgets', 'scroll_timeout', '250')\n\n        elif version == 9:\n            Config.setdefault('kivy', 'exit_on_escape', '1')\n\n        elif version == 10:\n            Config.set('graphics', 'fullscreen', '0')\n            Config.setdefault('graphics', 'borderless', '0')\n\n        elif version == 11:\n            Config.setdefault('kivy', 'pause_on_minimize', '0')\n\n        elif version == 12:\n            Config.set('graphics', 'window_state', 'visible')\n\n        #elif version == 1:\n        #   # add here the command for upgrading from configuration 0 to 1\n        #\n        else:\n            # for future.\n            break\n\n        # Pass to the next version\n        version += 1\n\n    # Indicate to the Config that we've upgrade to the latest version.\n    Config.set('kivy', 'config_version', KIVY_CONFIG_VERSION)\n\n    # Now, activate log file\n    Logger.logfile_activated = bool(Config.getint('kivy', 'log_enable'))\n\n    # If no configuration exist, write the default one.\n    if ((not exists(kivy_config_fn) or need_save) and\n            'KIVY_NO_CONFIG' not in environ):\n        try:\n            Config.filename = kivy_config_fn\n            Config.write()\n        except Exception as e:\n            Logger.exception('Core: Error while saving default config file')\n"
  },
  {
    "path": "tickeys/kivy/context.py",
    "content": "'''\nContext\n=======\n\n.. versionadded:: 1.8.0\n\n.. warning::\n\n    This is experimental and subject to change as long as this warning notice\n    is present.\n\nKivy has a few \"global\" instances that are used directly by many pieces of the\nframework: `Cache`, `Builder`, `Clock`.\n\nTODO: document this module.\n\n'''\n\n__all__ = ('Context', 'ProxyContext', 'register_context',\n           'get_current_context')\n\n_contexts = {}\n_default_context = None\n_context_stack = []\n\n\nclass ProxyContext(object):\n\n    __slots__ = ['_obj']\n\n    def __init__(self, obj):\n        object.__init__(self)\n        object.__setattr__(self, '_obj', obj)\n\n    def __getattribute__(self, name):\n        return getattr(object.__getattribute__(self, '_obj'), name)\n\n    def __delattr__(self, name):\n        delattr(object.__getattribute__(self, '_obj'), name)\n\n    def __setattr__(self, name, value):\n        setattr(object.__getattribute__(self, '_obj'), name, value)\n\n    def __bool__(self):\n        return bool(object.__getattribute__(self, '_obj'))\n\n    def __str__(self):\n        return str(object.__getattribute__(self, '_obj'))\n\n    def __repr__(self):\n        return repr(object.__getattribute__(self, '_obj'))\n\n\nclass Context(dict):\n\n    def __init__(self, init=False):\n        dict.__init__(self)\n        self.sandbox = None\n        if not init:\n            return\n\n        for name in _contexts:\n            context = _contexts[name]\n            instance = context['cls'](*context['args'], **context['kwargs'])\n            self[name] = instance\n\n    def push(self):\n        _context_stack.append(self)\n        for name, instance in self.items():\n            object.__setattr__(_contexts[name]['proxy'], '_obj', instance)\n\n    def pop(self):\n        # After poping context from stack. Update proxy's _obj with\n        # instances in current context\n        _context_stack.pop(-1)\n        for name, instance in get_current_context().items():\n            object.__setattr__(_contexts[name]['proxy'], '_obj', instance)\n\n\ndef register_context(name, cls, *args, **kwargs):\n    '''Register a new context.\n    '''\n    instance = cls(*args, **kwargs)\n    proxy = ProxyContext(instance)\n    _contexts[name] = {\n        'cls': cls,\n        'args': args,\n        'kwargs': kwargs,\n        'proxy': proxy}\n    _default_context[name] = instance\n    return proxy\n\n\ndef get_current_context():\n    '''Return the current context.\n    '''\n    if not _context_stack:\n        return _default_context\n    return _context_stack[-1]\n\n_default_context = Context(init=False)\n"
  },
  {
    "path": "tickeys/kivy/core/__init__.py",
    "content": "'''\nCore Abstraction\n================\n\nThis module defines the abstraction layers for our core providers and their\nimplementations. For further information, please refer to\n:ref:`architecture` and the :ref:`providers` section of the documentation.\n\nIn most cases, you shouldn't directly use a library that's already covered\nby the core abstraction. Always try to use our providers first.\nIn case we are missing a feature or method, please let us know by\nopening a new Bug report instead of relying on your library.\n\n.. warning::\n    These are **not** widgets! These are just abstractions of the respective\n    functionality. For example, you cannot add a core image to your window.\n    You have to use the image **widget** class instead. If you're really\n    looking for widgets, please refer to :mod:`kivy.uix` instead.\n'''\n\n\nimport os\nimport sys\nimport traceback\nimport kivy\nfrom kivy.logger import Logger\n\n\nclass CoreCriticalException(Exception):\n    pass\n\n\ndef core_select_lib(category, llist, create_instance=False, base='kivy.core'):\n    if 'KIVY_DOC' in os.environ:\n        return\n    category = category.lower()\n    libs_ignored = []\n    errs = []\n    for option, modulename, classname in llist:\n        try:\n            # module activated in config ?\n            try:\n                if option not in kivy.kivy_options[category]:\n                    libs_ignored.append(modulename)\n                    Logger.debug(\n                        '{0}: Provider <{1}> ignored by config'.format(\n                            category.capitalize(), option))\n                    continue\n            except KeyError:\n                pass\n\n            # import module\n            mod = __import__(name='{2}.{0}.{1}'.format(\n                category, modulename, base),\n                globals=globals(),\n                locals=locals(),\n                fromlist=[modulename], level=0)\n            cls = mod.__getattribute__(classname)\n\n            # ok !\n            Logger.info('{0}: Provider: {1}{2}'.format(\n                category.capitalize(), option,\n                '({0} ignored)'.format(libs_ignored) if libs_ignored else ''))\n            if create_instance:\n                cls = cls()\n            return cls\n\n        except ImportError as e:\n            errs.append((option, e, sys.exc_info()[2]))\n            libs_ignored.append(modulename)\n            Logger.debug('{0}: Ignored <{1}> (import error)'.format(\n                category.capitalize(), option))\n            Logger.trace('', exc_info=e)\n\n        except CoreCriticalException as e:\n            errs.append((option, e, sys.exc_info()[2]))\n            Logger.error('{0}: Unable to use {1}'.format(\n                category.capitalize(), option))\n            Logger.error(\n                '{0}: The module raised an important error: {1!r}'.format(\n                    category.capitalize(), e.message))\n            raise\n\n        except Exception as e:\n            errs.append((option, e, sys.exc_info()[2]))\n            libs_ignored.append(modulename)\n            Logger.trace('{0}: Unable to use {1}'.format(\n                category.capitalize(), option, category))\n            Logger.trace('', exc_info=e)\n\n    err = '\\n'.join(['{} - {}: {}\\n{}'.format(opt, e.__class__.__name__, e,\n                   ''.join(traceback.format_tb(tb))) for opt, e, tb in errs])\n    Logger.critical(\n        '{0}: Unable to find any valuable {0} provider at all!\\n{1}'.format(\n            category.capitalize(), err))\n\n\ndef core_register_libs(category, libs, base='kivy.core'):\n    if 'KIVY_DOC' in os.environ:\n        return\n    category = category.lower()\n    kivy_options = kivy.kivy_options[category]\n    libs_loadable = {}\n    libs_ignored = []\n\n    for option, lib in libs:\n        # module activated in config ?\n        if option not in kivy_options:\n            Logger.debug('{0}: option <{1}> ignored by config'.format(\n                category.capitalize(), option))\n            libs_ignored.append(lib)\n            continue\n        libs_loadable[option] = lib\n\n    libs_loaded = []\n    for item in kivy_options:\n        try:\n            # import module\n            try:\n                lib = libs_loadable[item]\n            except KeyError:\n                continue\n            __import__(name='{2}.{0}.{1}'.format(category, lib, base),\n                       globals=globals(),\n                       locals=locals(),\n                       fromlist=[lib],\n                       level=0)\n\n            libs_loaded.append(lib)\n\n        except Exception as e:\n            Logger.trace('{0}: Unable to use <{1}> as loader!'.format(\n                category.capitalize(), option))\n            Logger.trace('', exc_info=e)\n            libs_ignored.append(lib)\n\n    Logger.info('{0}: Providers: {1} {2}'.format(\n        category.capitalize(),\n        ', '.join(libs_loaded),\n        '({0} ignored)'.format(\n            ', '.join(libs_ignored)) if libs_ignored else ''))\n    return libs_loaded\n"
  },
  {
    "path": "tickeys/kivy/core/audio/__init__.py",
    "content": "'''\nAudio\n=====\n\nLoad an audio sound and play it with::\n\n    from kivy.core.audio import SoundLoader\n\n    sound = SoundLoader.load('mytest.wav')\n    if sound:\n        print(\"Sound found at %s\" % sound.source)\n        print(\"Sound is %.3f seconds\" % sound.length)\n        sound.play()\n\nYou should not use the Sound class directly. The class returned by\n**SoundLoader.load** will be the best sound provider for that particular file\ntype, so it might return different Sound classes depending the file type.\n\n.. versionchanged:: 1.8.0\n    There are now 2 distinct Gstreamer implementations: one using Gi/Gst working\n    for both Python 2+3 with Gstreamer 1.0, and one using PyGST working\n    only for Python 2 + Gstreamer 0.10.\n    If you have issue with GStreamer, have a look at\n    :ref:`gstreamer-compatibility`\n\n.. note::\n\n    The core audio library does not support recording audio. If you require\n    this functionality, please refer to the\n    `audiostream <https://github.com/kivy/audiostream>`_ extension.\n\n'''\n\n__all__ = ('Sound', 'SoundLoader')\n\nfrom kivy.logger import Logger\nfrom kivy.event import EventDispatcher\nfrom kivy.core import core_register_libs\nfrom kivy.compat import PY2\nfrom kivy.resources import resource_find\nfrom kivy.properties import StringProperty, NumericProperty, OptionProperty, \\\n    AliasProperty, BooleanProperty\nfrom kivy.setupconfig import USE_SDL2\n\n\nclass SoundLoader:\n    '''Load a sound, using the best loader for the given file type.\n    '''\n\n    _classes = []\n\n    @staticmethod\n    def register(classobj):\n        '''Register a new class to load the sound.'''\n        Logger.debug('Audio: register %s' % classobj.__name__)\n        SoundLoader._classes.append(classobj)\n\n    @staticmethod\n    def load(filename):\n        '''Load a sound, and return a Sound() instance.'''\n        rfn = resource_find(filename)\n        if rfn is not None:\n            filename = rfn\n        ext = filename.split('.')[-1].lower()\n        if '?' in ext:\n            ext = ext.split('?')[0]\n        for classobj in SoundLoader._classes:\n            if ext in classobj.extensions():\n                return classobj(source=filename)\n        Logger.warning('Audio: Unable to find a loader for <%s>' %\n                       filename)\n        return None\n\n\nclass Sound(EventDispatcher):\n    '''Represents a sound to play. This class is abstract, and cannot be used\n    directly.\n\n    Use SoundLoader to load a sound.\n\n    :Events:\n        `on_play` : None\n            Fired when the sound is played.\n        `on_stop` : None\n            Fired when the sound is stopped.\n    '''\n\n    source = StringProperty(None)\n    '''Filename / source of your audio file.\n\n    .. versionadded:: 1.3.0\n\n    :attr:`source` is a :class:`~kivy.properties.StringProperty` that defaults\n    to None and is read-only. Use the :meth:`SoundLoader.load` for loading\n    audio.\n    '''\n\n    volume = NumericProperty(1.)\n    '''Volume, in the range 0-1. 1 means full volume, 0 means mute.\n\n    .. versionadded:: 1.3.0\n\n    :attr:`volume` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 1.\n    '''\n\n    state = OptionProperty('stop', options=('stop', 'play'))\n    '''State of the sound, one of 'stop' or 'play'.\n\n    .. versionadded:: 1.3.0\n\n    :attr:`state` is a read-only :class:`~kivy.properties.OptionProperty`.'''\n\n    loop = BooleanProperty(False)\n    '''Set to True if the sound should automatically loop when it finishes.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`loop` is a :class:`~kivy.properties.BooleanProperty` and defaults to\n    False.'''\n\n    #\n    # deprecated\n    #\n    def _get_status(self):\n        return self.state\n    status = AliasProperty(_get_status, None, bind=('state', ))\n    '''\n    .. deprecated:: 1.3.0\n        Use :attr:`state` instead.\n    '''\n\n    def _get_filename(self):\n        return self.source\n    filename = AliasProperty(_get_filename, None, bind=('source', ))\n    '''\n    .. deprecated:: 1.3.0\n        Use :attr:`source` instead.\n    '''\n\n    __events__ = ('on_play', 'on_stop')\n\n    def on_source(self, instance, filename):\n        self.unload()\n        if filename is None:\n            return\n        self.load()\n\n    def get_pos(self):\n        '''\n        Returns the current position of the audio file.\n        Returns 0 if not playing.\n\n        .. versionadded:: 1.4.1\n        '''\n        return 0\n\n    def _get_length(self):\n        return 0\n\n    length = property(lambda self: self._get_length(),\n                      doc='Get length of the sound (in seconds).')\n\n    def load(self):\n        '''Load the file into memory.'''\n        pass\n\n    def unload(self):\n        '''Unload the file from memory.'''\n        pass\n\n    def play(self):\n        '''Play the file.'''\n        self.state = 'play'\n        self.dispatch('on_play')\n\n    def stop(self):\n        '''Stop playback.'''\n        self.state = 'stop'\n        self.dispatch('on_stop')\n\n    def seek(self, position):\n        '''Go to the <position> (in seconds).'''\n        pass\n\n    def on_play(self):\n        pass\n\n    def on_stop(self):\n        pass\n\n\n# Little trick here, don't activate gstreamer on window\n# seem to have lot of crackle or something...\naudio_libs = []\n\n# from now on, prefer our gstplayer instead of gi/pygst.\ntry:\n    from kivy.lib.gstplayer import GstPlayer  # NOQA\n    audio_libs += [('gstplayer', 'audio_gstplayer')]\nexcept ImportError:\n    #audio_libs += [('gi', 'audio_gi')]\n    if PY2:\n        audio_libs += [('pygst', 'audio_pygst')]\naudio_libs += [('ffpyplayer', 'audio_ffpyplayer')]\nif USE_SDL2:\n    audio_libs += [('sdl2', 'audio_sdl2')]\nelse:\n    audio_libs += [('pygame', 'audio_pygame')]\n\ncore_register_libs('audio', audio_libs)\n"
  },
  {
    "path": "tickeys/kivy/core/audio/audio_ffpyplayer.py",
    "content": "'''\nFFmpeg based audio player\n=========================\n\nTo use, you need to install ffpyplyaer and have a compiled ffmpeg shared\nlibrary.\n\n    https://github.com/matham/ffpyplayer\n\nThe docs there describe how to set this up. But briefly, first you need to\ncompile ffmpeg using the shared flags while disabling the static flags (you'll\nprobably have to set the fPIC flag, e.g. CFLAGS=-fPIC). Here's some\ninstructions: https://trac.ffmpeg.org/wiki/CompilationGuide. For Windows, you\ncan download compiled GPL binaries from http://ffmpeg.zeranoe.com/builds/.\nSimilarly, you should download SDL.\n\nNow, you should a ffmpeg and sdl directory. In each, you should have a include,\nbin, and lib directory, where e.g. for Windows, lib contains the .dll.a files,\nwhile bin contains the actual dlls. The include directory holds the headers.\nThe bin directory is only needed if the shared libraries are not already on\nthe path. In the environment define FFMPEG_ROOT and SDL_ROOT, each pointing to\nthe ffmpeg, and SDL directories, respectively. (If you're using SDL2,\nthe include directory will contain a directory called SDL2, which then holds\nthe headers).\n\nOnce defined, download the ffpyplayer git and run\n\n    python setup.py build_ext --inplace\n\nFinally, before running you need to ensure that ffpyplayer is in python's path.\n\n..Note::\n\n    When kivy exits by closing the window while the audio is playing,\n    it appears that the __del__method of SoundFFPy\n    is not called. Because of this the SoundFFPy object is not\n    properly deleted when kivy exits. The consequence is that because\n    MediaPlayer creates internal threads which do not have their daemon\n    flag set, when the main threads exists it'll hang and wait for the other\n    MediaPlayer threads to exit. But since __del__ is not called to delete the\n    MediaPlayer object, those threads will remain alive hanging kivy. What this\n    means is that you have to be sure to delete the MediaPlayer object before\n    kivy exits by setting it to None.\n'''\n\n__all__ = ('SoundFFPy', )\n\ntry:\n    import ffpyplayer\n    from ffpyplayer.player import MediaPlayer\n    from ffpyplayer.tools import set_log_callback, loglevels,\\\n        get_log_callback, formats_in\nexcept:\n    raise\n\n\nfrom kivy.clock import Clock\nfrom kivy.logger import Logger\nfrom kivy.core.audio import Sound, SoundLoader\nfrom kivy.weakmethod import WeakMethod\nimport time\n\nLogger.info('SoundFFPy: Using ffpyplayer {}'.format(ffpyplayer.version))\n\n\nlogger_func = {'quiet': Logger.critical, 'panic': Logger.critical,\n               'fatal': Logger.critical, 'error': Logger.error,\n               'warning': Logger.warning, 'info': Logger.info,\n               'verbose': Logger.debug, 'debug': Logger.debug}\n\n\ndef _log_callback(message, level):\n    message = message.strip()\n    if message:\n        logger_func[level]('ffpyplayer: {}'.format(message))\n\n\nclass SoundFFPy(Sound):\n\n    @staticmethod\n    def extensions():\n        return formats_in\n\n    def __init__(self, **kwargs):\n        self._ffplayer = None\n        self.quitted = False\n        self._log_callback_set = False\n        self._state = ''\n        self.state = 'stop'\n        self._callback_ref = WeakMethod(self._player_callback)\n\n        if not get_log_callback():\n            set_log_callback(_log_callback)\n            self._log_callback_set = True\n\n        super(SoundFFPy, self).__init__(**kwargs)\n\n    def __del__(self):\n        self.unload()\n        if self._log_callback_set:\n            set_log_callback(None)\n\n    def _player_callback(self, selector, value):\n        if self._ffplayer is None:\n            return\n        if selector == 'quit':\n            def close(*args):\n                self.quitted = True\n                self.unload()\n            Clock.schedule_once(close, 0)\n        elif selector == 'eof':\n            Clock.schedule_once(self._do_eos, 0)\n\n    def load(self):\n        self.unload()\n        ff_opts = {'vn': True, 'sn': True}  # only audio\n        self._ffplayer = MediaPlayer(self.source,\n                                     callback=self._callback_ref,\n                                     loglevel='info', ff_opts=ff_opts)\n        player = self._ffplayer\n        player.set_volume(self.volume)\n        player.toggle_pause()\n        self._state = 'paused'\n        # wait until loaded or failed, shouldn't take long, but just to make\n        # sure metadata is available.\n        s = time.clock()\n        while ((not player.get_metadata()['duration'])\n               and not self.quitted and time.clock() - s < 10.):\n            time.sleep(0.005)\n\n    def unload(self):\n        if self._ffplayer:\n            self._ffplayer = None\n        self._state = ''\n        self.state = 'stop'\n        self.quitted = False\n\n    def play(self):\n        if self._state == 'playing':\n            super(SoundFFPy, self).play()\n            return\n        if not self._ffplayer:\n            self.load()\n        self._ffplayer.toggle_pause()\n        self._state = 'playing'\n        self.state = 'play'\n        super(SoundFFPy, self).play()\n\n    def stop(self):\n        if self._ffplayer and self._state == 'playing':\n            self._ffplayer.toggle_pause()\n            self._state = 'paused'\n            self.state = 'stop'\n        super(SoundFFPy, self).stop()\n\n    def seek(self, position):\n        if self._ffplayer is None:\n            return\n        self._ffplayer.seek(position, relative=False)\n\n    def get_pos(self):\n        if self._ffplayer is not None:\n            return self._ffplayer.get_pts()\n        return 0\n\n    def on_volume(self, instance, volume):\n        if self._ffplayer is not None:\n            self._ffplayer.set_volume(volume)\n\n    def _get_length(self):\n        if self._ffplayer is None:\n            return super(SoundFFPy, self)._get_length()\n        return self._ffplayer.get_metadata()['duration']\n\n    def _do_eos(self, *args):\n        if not self.loop:\n            self.stop()\n        else:\n            self.seek(0.)\n\nSoundLoader.register(SoundFFPy)\n"
  },
  {
    "path": "tickeys/kivy/core/audio/audio_gi.py",
    "content": "'''\nAudio Gi\n========\n\nImplementation of Sound with Gi. Gi is both compatible with Python 2 and 3.\n'''\n\nfrom gi.repository import Gst\nfrom kivy.core.audio import Sound, SoundLoader\nfrom kivy.logger import Logger\nfrom kivy.support import install_gobject_iteration\nimport os\nimport sys\n\n# initialize the audio/gi. if the older version is used, don't use audio_gi.\nGst.init(None)\nversion = Gst.version()\nif version < (1, 0, 0, 0):\n    raise Exception('Cannot use audio_gi, Gstreamer < 1.0 is not supported.')\nLogger.info('AudioGi: Using Gstreamer {}'.format(\n    '.'.join(['{}'.format(x) for x in Gst.version()])))\ninstall_gobject_iteration()\n\n\nclass SoundGi(Sound):\n\n    @staticmethod\n    def extensions():\n        return ('wav', 'ogg', 'mp3', )\n\n    def __init__(self, **kwargs):\n        self._data = None\n        super(SoundGi, self).__init__(**kwargs)\n\n    def __del__(self):\n        if self._data is not None:\n            self._data.set_state(Gst.State.NULL)\n\n    def _on_gst_message(self, bus, message):\n        t = message.type\n        if t == Gst.MessageType.EOS:\n            self._data.set_state(Gst.State.NULL)\n            if self.loop:\n                self.play()\n            else:\n                self.stop()\n        elif t == Gst.MessageType.ERROR:\n            self._data.set_state(Gst.State.NULL)\n            err, debug = message.parse_error()\n            Logger.error('AudioGi: %s' % err)\n            Logger.debug(str(debug))\n            self.stop()\n\n    def play(self):\n        if not self._data:\n            return\n        self._data.props.volume = self.volume\n        self._data.set_state(Gst.State.PLAYING)\n        super(SoundGi, self).play()\n\n    def stop(self):\n        if not self._data:\n            return\n        self._data.set_state(Gst.State.NULL)\n        super(SoundGi, self).stop()\n\n    def load(self):\n        self.unload()\n        fn = self.filename\n        if fn is None:\n            return\n\n        slash = ''\n        if sys.platform in ('win32', 'cygwin'):\n            slash = '/'\n\n        if fn[0] == '/':\n            uri = 'file://' + slash + fn\n        else:\n            uri = 'file://' + slash + os.path.join(os.getcwd(), fn)\n\n        self._data = Gst.ElementFactory.make('playbin', '')\n        fakesink = Gst.ElementFactory.make('fakesink', '')\n        self._data.props.video_sink = fakesink\n        bus = self._data.get_bus()\n        bus.add_signal_watch()\n        bus.connect('message', self._on_gst_message)\n        self._data.props.uri = uri\n        self._data.set_state(Gst.State.READY)\n\n    def unload(self):\n        self.stop()\n        self._data = None\n\n    def seek(self, position):\n        if self._data is None:\n            return\n        self._data.seek_simple(\n            Gst.Format.TIME, Gst.SeekFlags.SKIP, position * Gst.SECOND)\n\n    def get_pos(self):\n        if self._data is not None:\n            if self._data.get_state()[1] == Gst.State.PLAYING:\n                try:\n                    ret, value = self._data.query_position(Gst.Format.TIME)\n                    if ret:\n                        return value / float(Gst.SECOND)\n                except:\n                    pass\n        return 0\n\n    def on_volume(self, instance, volume):\n        if self._data is not None:\n            self._data.set_property('volume', volume)\n\n    def _get_length(self):\n        if self._data is not None:\n            if self._data.get_state()[1] != Gst.State.PLAYING:\n                volume_before = self._data.get_property('volume')\n                self._data.set_property('volume', 0)\n                self._data.set_state(Gst.State.PLAYING)\n                try:\n                    self._data.get_state()\n                    ret, value = self._data.query_duration(Gst.Format.TIME)\n                    if ret:\n                        return value / float(Gst.SECOND)\n                finally:\n                    self._data.set_state(Gst.State.NULL)\n                    self._data.set_property('volume', volume_before)\n            else:\n                ret, value = self._data.query_duration(Gst.Format.TIME)\n                if ret:\n                    return value / float(Gst.SECOND)\n        return super(SoundGi, self)._get_length()\n\nSoundLoader.register(SoundGi)\n"
  },
  {
    "path": "tickeys/kivy/core/audio/audio_gstplayer.py",
    "content": "'''\nAudio Gstplayer\n===============\n\n.. versionadded:: 1.8.0\n\nImplementation of a VideoBase with Kivy :class:`~kivy.lib.gstplayer.GstPlayer`\nThis player is the prefered player, using Gstreamer 1.0, working on both Python\n2 and 3.\n'''\n\nfrom kivy.lib.gstplayer import GstPlayer, get_gst_version\nfrom kivy.core.audio import Sound, SoundLoader\nfrom kivy.logger import Logger\nfrom kivy.compat import PY2\nfrom kivy.clock import Clock\nfrom os.path import realpath\n\nif PY2:\n    from urllib import pathname2url\nelse:\n    from urllib.request import pathname2url\n\nLogger.info('AudioGstplayer: Using Gstreamer {}'.format(\n    '.'.join(map(str, get_gst_version()))))\n\n\ndef _on_gstplayer_message(mtype, message):\n    if mtype == 'error':\n        Logger.error('AudioGstplayer: {}'.format(message))\n    elif mtype == 'warning':\n        Logger.warning('AudioGstplayer: {}'.format(message))\n    elif mtype == 'info':\n        Logger.info('AudioGstplayer: {}'.format(message))\n\n\nclass SoundGstplayer(Sound):\n\n    @staticmethod\n    def extensions():\n        return ('wav', 'ogg', 'mp3', 'm4a')\n\n    def __init__(self, **kwargs):\n        self.player = None\n        super(SoundGstplayer, self).__init__(**kwargs)\n\n    def _on_gst_eos_sync(self):\n        Clock.schedule_once(self._on_gst_eos, 0)\n\n    def _on_gst_eos(self, *dt):\n        if self.loop:\n            self.player.stop()\n            self.player.play()\n        else:\n            self.stop()\n\n    def load(self):\n        self.unload()\n        uri = self._get_uri()\n        self.player = GstPlayer(uri, None, self._on_gst_eos_sync,\n                                _on_gstplayer_message)\n        self.player.load()\n\n    def play(self):\n        # we need to set the volume everytime, it seems that stopping + playing\n        # the sound reset the volume.\n        self.player.set_volume(self.volume)\n        self.player.play()\n        super(SoundGstplayer, self).play()\n\n    def stop(self):\n        self.player.stop()\n        super(SoundGstplayer, self).stop()\n\n    def unload(self):\n        if self.player:\n            self.player.unload()\n            self.player = None\n\n    def seek(self, position):\n        self.player.seek(position / self.length)\n\n    def get_pos(self):\n        return self.player.get_position()\n\n    def _get_length(self):\n        return self.player.get_duration()\n\n    def on_volume(self, instance, volume):\n        self.player.set_volume(volume)\n\n    def _get_uri(self):\n        uri = self.filename\n        if not uri:\n            return\n        if not '://' in uri:\n            uri = 'file:' + pathname2url(realpath(uri))\n        return uri\n\nSoundLoader.register(SoundGstplayer)\n"
  },
  {
    "path": "tickeys/kivy/core/audio/audio_pygame.py",
    "content": "'''\nAudioPygame: implementation of Sound with Pygame\n'''\n\n__all__ = ('SoundPygame', )\n\nfrom kivy.clock import Clock\nfrom kivy.utils import platform\nfrom kivy.core.audio import Sound, SoundLoader\n\n_platform = platform\ntry:\n    if _platform == 'android':\n        try:\n            import android.mixer as mixer\n        except ImportError:\n            # old python-for-android version\n            import android_mixer as mixer\n    else:\n        from pygame import mixer\nexcept:\n    raise\n\n# init pygame sound\nmixer.pre_init(44100, -16, 2, 1024)\nmixer.init()\nmixer.set_num_channels(32)\n\n\nclass SoundPygame(Sound):\n\n    # XXX we don't set __slots__ here, to automaticly add\n    # a dictionary. We need that to be able to use weakref for\n    # SoundPygame object. Otherwise, it failed with:\n    # TypeError: cannot create weak reference to 'SoundPygame' object\n    # We use our clock in play() method.\n    # __slots__ = ('_data', '_channel')\n    @staticmethod\n    def extensions():\n        if _platform == 'android':\n            return ('wav', 'ogg', 'mp3', 'm4a')\n        return ('wav', 'ogg')\n\n    def __init__(self, **kwargs):\n        self._data = None\n        self._channel = None\n        super(SoundPygame, self).__init__(**kwargs)\n\n    def _check_play(self, dt):\n        if self._channel is None:\n            return False\n        if self._channel.get_busy():\n            return\n        if self.loop:\n            def do_loop(dt):\n                self.play()\n            Clock.schedule_once(do_loop)\n        else:\n            self.stop()\n        return False\n\n    def play(self):\n        if not self._data:\n            return\n        self._data.set_volume(self.volume)\n        self._channel = self._data.play()\n        self.start_time = Clock.time()\n        # schedule event to check if the sound is still playing or not\n        Clock.schedule_interval(self._check_play, 0.1)\n        super(SoundPygame, self).play()\n\n    def stop(self):\n        if not self._data:\n            return\n        self._data.stop()\n        # ensure we don't have anymore the callback\n        Clock.unschedule(self._check_play)\n        self._channel = None\n        super(SoundPygame, self).stop()\n\n    def load(self):\n        self.unload()\n        if self.filename is None:\n            return\n        self._data = mixer.Sound(self.filename)\n\n    def unload(self):\n        self.stop()\n        self._data = None\n\n    def seek(self, position):\n        if not self._data:\n            return\n        if _platform == 'android' and self._channel:\n            self._channel.seek(position)\n\n    def get_pos(self):\n        if self._data is not None and self._channel:\n            if _platform == 'android':\n                return self._channel.get_pos()\n            return  Clock.time() - self.start_time\n        return 0\n\n    def on_volume(self, instance, volume):\n        if self._data is not None:\n            self._data.set_volume(volume)\n\n    def _get_length(self):\n        if _platform == 'android' and self._channel:\n            return self._channel.get_length()\n        if self._data is not None:\n            return self._data.get_length()\n        return super(SoundPygame, self)._get_length()\n\nSoundLoader.register(SoundPygame)\n"
  },
  {
    "path": "tickeys/kivy/core/audio/audio_pygst.py",
    "content": "'''\nAudio Gstreamer\n===============\n\nImplementation of Sound with GStreamer\n'''\n\ntry:\n    import gi  # NOQA\nexcept ImportError:\n    gi_found = False\nelse:\n    raise Exception('Avoiding PyGST, Gi is better.')\n\ntry:\n    import pygst\n    if not hasattr(pygst, '_gst_already_checked'):\n        pygst.require('0.10')\n        pygst._gst_already_checked = True\n    import gst\nexcept:\n    raise\n\nfrom kivy.core.audio import Sound, SoundLoader\nimport os\nimport sys\nfrom kivy.logger import Logger\n\n# install the gobject iteration\nfrom kivy.support import install_gobject_iteration\ninstall_gobject_iteration()\n\n\nclass SoundPyGst(Sound):\n\n    @staticmethod\n    def extensions():\n        return ('wav', 'ogg', 'mp3', )\n\n    def __init__(self, **kwargs):\n        self._data = None\n        super(SoundPyGst, self).__init__(**kwargs)\n\n    def __del__(self):\n        if self._data is not None:\n            self._data.set_state(gst.STATE_NULL)\n\n    def _on_gst_message(self, bus, message):\n        t = message.type\n        if t == gst.MESSAGE_EOS:\n            self._data.set_state(gst.STATE_NULL)\n            if self.loop:\n                self.play()\n            else:\n                self.stop()\n        elif t == gst.MESSAGE_ERROR:\n            self._data.set_state(gst.STATE_NULL)\n            err, debug = message.parse_error()\n            Logger.error('AudioPyGst: %s' % err)\n            Logger.debug(str(debug))\n            self.stop()\n\n    def play(self):\n        if not self._data:\n            return\n        self._data.set_property('volume', self.volume)\n        self._data.set_state(gst.STATE_PLAYING)\n        super(SoundPyGst, self).play()\n\n    def stop(self):\n        if not self._data:\n            return\n        self._data.set_state(gst.STATE_NULL)\n        super(SoundPyGst, self).stop()\n\n    def load(self):\n        self.unload()\n        fn = self.filename\n        if fn is None:\n            return\n\n        slash = ''\n        if sys.platform in ('win32', 'cygwin'):\n            slash = '/'\n\n        if fn[0] == '/':\n            filepath = 'file://' + slash + fn\n        else:\n            filepath = 'file://' + slash + os.path.join(os.getcwd(), fn)\n\n        self._data = gst.element_factory_make('playbin2', 'player')\n        fakesink = gst.element_factory_make('fakesink', 'fakesink')\n        self._data.set_property('video-sink', fakesink)\n        bus = self._data.get_bus()\n        bus.add_signal_watch()\n        bus.connect('message', self._on_gst_message)\n\n        self._data.set_property('uri', filepath)\n        self._data.set_state(gst.STATE_READY)\n\n    def unload(self):\n        self.stop()\n        self._data = None\n\n    def seek(self, position):\n        if self._data is None:\n            return\n        self._data.seek_simple(gst.FORMAT_TIME, gst.SEEK_FLAG_SKIP,\n                               position * 1000000000.)\n\n    def get_pos(self):\n        if self._data is not None:\n            if self._data.get_state()[1] == gst.STATE_PLAYING:\n                try:\n                    return self._data.query_position(\n                        gst.Format(gst.FORMAT_TIME))[0] / 1000000000.\n                except:\n                    pass\n        return 0\n\n    def on_volume(self, instance, volume):\n        if self._data is not None:\n            self._data.set_property('volume', volume)\n\n    def _get_length(self):\n        if self._data is not None:\n            if self._data.get_state()[1] != gst.STATE_PLAYING:\n                volume_before = self._data.get_property('volume')\n                self._data.set_property('volume', 0)\n                self._data.set_state(gst.STATE_PLAYING)\n                try:\n                    self._data.get_state()\n                    return self._data.query_duration(gst.Format(\n                        gst.FORMAT_TIME))[0] / 1000000000.\n                finally:\n                    self._data.set_state(gst.STATE_NULL)\n                    self._data.set_property('volume', volume_before)\n            else:\n                return self._data.query_duration(\n                    gst.Format(gst.FORMAT_TIME))[0] / 1000000000.\n        return super(SoundPyGst, self)._get_length()\n\nSoundLoader.register(SoundPyGst)\n"
  },
  {
    "path": "tickeys/kivy/core/camera/__init__.py",
    "content": "'''\nCamera\n======\n\nCore class for acquiring the camera and converting its input into a\n:class:`~kivy.graphics.texture.Texture`.\n\n.. versionchanged:: 1.8.0\n    There is now 2 distinct Gstreamer implementation: one using Gi/Gst\n    working for both Python 2+3 with Gstreamer 1.0, and one using PyGST\n    working only for Python 2 + Gstreamer 0.10.\n    If you have issue with GStreamer, have a look at\n    :ref:`gstreamer-compatibility`\n\n'''\n\n__all__ = ('CameraBase', 'Camera')\n\nimport sys\n\nfrom kivy.event import EventDispatcher\nfrom kivy.logger import Logger\nfrom kivy.core import core_select_lib\n\n\nclass CameraBase(EventDispatcher):\n    '''Abstract Camera Widget class.\n\n    Concrete camera classes must implement initialization and\n    frame capturing to a buffer that can be uploaded to the gpu.\n\n    :Parameters:\n        `index`: int\n            Source index of the camera.\n        `size` : tuple (int, int)\n            Size at which the image is drawn. If no size is specified,\n            it defaults to the resolution of the camera image.\n        `resolution` : tuple (int, int)\n            Resolution to try to request from the camera.\n            Used in the gstreamer pipeline by forcing the appsink caps\n            to this resolution. If the camera doesnt support the resolution,\n            a negotiation error might be thrown.\n\n    :Events:\n        `on_load`\n            Fired when the camera is loaded and the texture has become\n            available.\n        `on_frame`\n            Fired each time the camera texture is updated.\n    '''\n\n    __events__ = ('on_load', 'on_texture')\n\n    def __init__(self, **kwargs):\n        kwargs.setdefault('stopped', False)\n        kwargs.setdefault('resolution', (640, 480))\n        kwargs.setdefault('index', 0)\n\n        self.stopped = kwargs.get('stopped')\n        self._resolution = kwargs.get('resolution')\n        self._index = kwargs.get('index')\n        self._buffer = None\n        self._format = 'rgb'\n        self._texture = None\n        self.capture_device = None\n        kwargs.setdefault('size', self._resolution)\n\n        super(CameraBase, self).__init__()\n\n        self.init_camera()\n\n        if not self.stopped:\n            self.start()\n\n    def _set_resolution(self, res):\n        self._resolution = res\n        self.init_camera()\n\n    def _get_resolution(self):\n        return self._resolution\n\n    resolution = property(lambda self: self._get_resolution(),\n                          lambda self, x: self._set_resolution(x),\n                          doc='Resolution of camera capture (width, height)')\n\n    def _set_index(self, x):\n        if x == self._index:\n            return\n        self._index = x\n        self.init_camera()\n\n    def _get_index(self):\n        return self._x\n\n    index = property(lambda self: self._get_index(),\n                     lambda self, x: self._set_index(x),\n                     doc='Source index of the camera')\n\n    def _get_texture(self):\n        return self._texture\n    texture = property(lambda self: self._get_texture(),\n                       doc='Return the camera texture with the latest capture')\n\n    def init_camera(self):\n        '''Initialise the camera (internal)'''\n        pass\n\n    def start(self):\n        '''Start the camera acquire'''\n        self.stopped = False\n\n    def stop(self):\n        '''Release the camera'''\n        self.stopped = True\n\n    def _update(self, dt):\n        '''Update the camera (internal)'''\n        pass\n\n    def _copy_to_gpu(self):\n        '''Copy the the buffer into the texture'''\n        if self._texture is None:\n            Logger.debug('Camera: copy_to_gpu() failed, _texture is None !')\n            return\n        self._texture.blit_buffer(self._buffer, colorfmt=self._format)\n        self._buffer = None\n        self.dispatch('on_texture')\n\n    def on_texture(self):\n        pass\n\n    def on_load(self):\n        pass\n\n# Load the appropriate providers\nproviders = ()\n\nif sys.platform == 'win32':\n    providers += (('videocapture', 'camera_videocapture',\n                   'CameraVideoCapture'), )\nelif sys.platform == 'darwin':\n    providers += (('avfoundation', 'camera_avfoundation',\n                   'CameraAVFoundation'), )\nelse:\n    #providers += (('gi', 'camera_gi', 'CameraGi'), )\n    providers += (('pygst', 'camera_pygst', 'CameraPyGst'), )\n\nproviders += (('opencv', 'camera_opencv', 'CameraOpenCV'), )\n\n\nCamera = core_select_lib('camera', (providers))\n"
  },
  {
    "path": "tickeys/kivy/core/camera/camera_gi.py",
    "content": "'''\nGi Camera\n=========\n\nImplement CameraBase with Gi / Gstreamer, working on both Python 2 and 3\n'''\n\n__all__ = ('CameraGi', )\n\nfrom gi.repository import Gst\nfrom kivy.clock import Clock\nfrom kivy.graphics.texture import Texture\nfrom kivy.core.camera import CameraBase\nfrom kivy.support import install_gobject_iteration\nfrom kivy.logger import Logger\nfrom ctypes import Structure, c_void_p, c_int, string_at\nfrom weakref import ref\nimport atexit\n\n# initialize the camera/gi. if the older version is used, don't use camera_gi.\nGst.init(None)\nversion = Gst.version()\nif version < (1, 0, 0, 0):\n    raise Exception('Cannot use camera_gi, Gstreamer < 1.0 is not supported.')\nLogger.info('CameraGi: Using Gstreamer {}'.format(\n    '.'.join(['{}'.format(x) for x in Gst.version()])))\ninstall_gobject_iteration()\n\n\nclass _MapInfo(Structure):\n    _fields_ = [\n        ('memory', c_void_p),\n        ('flags', c_int),\n        ('data', c_void_p)]\n        # we don't care about the rest\n\n\ndef _on_cameragi_unref(obj):\n    if obj in CameraGi._instances:\n        CameraGi._instances.remove(obj)\n\n\nclass CameraGi(CameraBase):\n    '''Implementation of CameraBase using GStreamer\n\n    :Parameters:\n        `video_src` : str, default is 'v4l2src'\n            Other tested options are: 'dc1394src' for firewire\n            dc camera (e.g. firefly MV). Any gstreamer video source\n            should potentially work.\n            Theoretically a longer string using \"!\" can be used\n            describing the first part of a gstreamer pipeline.\n    '''\n\n    _instances = []\n\n    def __init__(self, **kwargs):\n        self._pipeline = None\n        self._camerasink = None\n        self._decodebin = None\n        self._texturesize = None\n        self._video_src = kwargs.get('video_src', 'v4l2src')\n        wk = ref(self, _on_cameragi_unref)\n        CameraGi._instances.append(wk)\n        super(CameraGi, self).__init__(**kwargs)\n\n    def init_camera(self):\n        # TODO: This doesn't work when camera resolution is resized at runtime.\n        # There must be some other way to release the camera?\n        if self._pipeline:\n            self._pipeline = None\n\n        video_src = self._video_src\n        if video_src == 'v4l2src':\n            video_src += ' device=/dev/video%d' % self._index\n        elif video_src == 'dc1394src':\n            video_src += ' camera-number=%d' % self._index\n\n        if Gst.version() < (1, 0, 0, 0):\n            caps = ('video/x-raw-rgb,red_mask=(int)0xff0000,'\n                    'green_mask=(int)0x00ff00,blue_mask=(int)0x0000ff')\n            pl = ('{} ! decodebin name=decoder ! ffmpegcolorspace ! '\n                  'appsink name=camerasink emit-signals=True caps={}')\n        else:\n            caps = 'video/x-raw,format=RGB'\n            pl = '{} ! decodebin name=decoder ! videoconvert ! appsink ' + \\\n                 'name=camerasink emit-signals=True caps={}'\n\n        self._pipeline = Gst.parse_launch(pl.format(video_src, caps))\n        self._camerasink = self._pipeline.get_by_name('camerasink')\n        self._camerasink.connect('new-sample', self._gst_new_sample)\n        self._decodebin = self._pipeline.get_by_name('decoder')\n\n        if self._camerasink and not self.stopped:\n            self.start()\n\n    def _gst_new_sample(self, *largs):\n        sample = self._camerasink.emit('pull-sample')\n        if sample is None:\n            return False\n\n        self._sample = sample\n\n        if self._texturesize is None:\n            # try to get the camera image size\n            for pad in self._decodebin.srcpads:\n                s = pad.get_current_caps().get_structure(0)\n                self._texturesize = (\n                    s.get_value('width'),\n                    s.get_value('height'))\n                Clock.schedule_once(self._update)\n                return False\n\n        Clock.schedule_once(self._update)\n        return False\n\n    def start(self):\n        super(CameraGi, self).start()\n        self._pipeline.set_state(Gst.State.PLAYING)\n\n    def stop(self):\n        super(CameraGi, self).stop()\n        self._pipeline.set_state(Gst.State.PAUSED)\n\n    def unload(self):\n        self._pipeline.set_state(Gst.State.NULL)\n\n    def _update(self, dt):\n        sample, self._sample = self._sample, None\n        if sample is None:\n            return\n\n        if self._texture is None and self._texturesize is not None:\n            self._texture = Texture.create(\n                size=self._texturesize, colorfmt='rgb')\n            self._texture.flip_vertical()\n            self.dispatch('on_load')\n\n        # decode sample\n        # read the data from the buffer memory\n        try:\n            buf = sample.get_buffer()\n            result, mapinfo = buf.map(Gst.MapFlags.READ)\n\n            # We cannot get the data out of mapinfo, using Gst 1.0.6 + Gi 3.8.0\n            # related bug report:\n            # https://bugzilla.gnome.org/show_bug.cgi?id=6t8663\n            # ie: mapinfo.data is normally a char*, but here, we have an int\n            # So right now, we use ctypes instead to read the mapinfo ourself.\n            addr = mapinfo.__hash__()\n            c_mapinfo = _MapInfo.from_address(addr)\n\n            # now get the memory\n            self._buffer = string_at(c_mapinfo.data, mapinfo.size)\n            self._copy_to_gpu()\n        finally:\n            if mapinfo is not None:\n                buf.unmap(mapinfo)\n\n\n@atexit.register\ndef camera_gi_clean():\n    # if we leave the python process with some video running, we can hit a\n    # segfault. This is forcing the stop/unload of all remaining videos before\n    # exiting the python process.\n    for weakcamera in CameraGi._instances:\n        camera = weakcamera()\n        if isinstance(camera, CameraGi):\n            camera.stop()\n            camera.unload()\n"
  },
  {
    "path": "tickeys/kivy/core/camera/camera_opencv.py",
    "content": "'''\nOpenCV Camera: Implement CameraBase with OpenCV\n'''\n\n#\n# TODO: make usage of thread or multiprocess\n#\n\n__all__ = ('CameraOpenCV')\n\nfrom kivy.logger import Logger\nfrom kivy.clock import Clock\nfrom kivy.graphics.texture import Texture\nfrom kivy.core.camera import CameraBase\n\ntry:\n    import opencv as cv\n    import opencv.highgui as hg\nexcept ImportError:\n    import cv\n\n    class Hg(object):\n        '''\n        On OSX, not only are the import names different, but the API also\n        differs. There is no module called 'highgui' but the names are directly\n        available in the 'cv' module. Some of them even have a different\n        names.\n\n        Therefore we use this proxy object.\n        '''\n\n        def __getattr__(self, attr):\n            if attr.startswith('cv'):\n                attr = attr[2:]\n            got = getattr(cv, attr)\n            return got\n\n    hg = Hg()\n\n\nclass CameraOpenCV(CameraBase):\n    '''Implementation of CameraBase using OpenCV\n    '''\n\n    def __init__(self, **kwargs):\n        self._device = None\n        super(CameraOpenCV, self).__init__(**kwargs)\n\n    def init_camera(self):\n        # create the device\n        self._device = hg.cvCreateCameraCapture(self._index)\n\n        # Set preferred resolution\n        cv.SetCaptureProperty(self._device, cv.CV_CAP_PROP_FRAME_WIDTH,\n                              self.resolution[0])\n        cv.SetCaptureProperty(self._device, cv.CV_CAP_PROP_FRAME_HEIGHT,\n                              self.resolution[1])\n\n        # and get frame to check if it's ok\n        frame = hg.cvQueryFrame(self._device)\n        # Just set the resolution to the frame we just got, but don't use\n        # self.resolution for that as that would cause an infinite recursion\n        # with self.init_camera (but slowly as we'd have to always get a\n        # frame).\n        self._resolution = (int(frame.width), int(frame.height))\n\n        #get fps\n        self.fps = cv.GetCaptureProperty(self._device, cv.CV_CAP_PROP_FPS)\n        if self.fps <= 0:\n            self.fps = 1 / 30.\n\n        if not self.stopped:\n            self.start()\n\n    def _update(self, dt):\n        if self.stopped:\n            return\n        if self._texture is None:\n            # Create the texture\n            self._texture = Texture.create(self._resolution)\n            self._texture.flip_vertical()\n            self.dispatch('on_load')\n        try:\n            frame = hg.cvQueryFrame(self._device)\n            self._format = 'bgr'\n            try:\n                self._buffer = frame.imageData\n            except AttributeError:\n                # On OSX there is no imageData attribute but a tostring()\n                # method.\n                self._buffer = frame.tostring()\n            self._copy_to_gpu()\n        except:\n            Logger.exception('OpenCV: Couldn\\'t get image from Camera')\n\n    def start(self):\n        super(CameraOpenCV, self).start()\n        Clock.unschedule(self._update)\n        Clock.schedule_interval(self._update, self.fps)\n\n    def stop(self):\n        super(CameraOpenCV, self).stop()\n        Clock.unschedule(self._update)\n"
  },
  {
    "path": "tickeys/kivy/core/camera/camera_pygst.py",
    "content": "'''\nGStreamer Camera\n================\n\nImplement CameraBase with GStreamer, based on PyGST\n'''\n\n__all__ = ('CameraPyGst', )\n\nfrom kivy.clock import Clock\nfrom kivy.graphics.texture import Texture\nfrom kivy.core.camera import CameraBase\n\ntry:\n    import pygst\n    if not hasattr(pygst, '_gst_already_checked'):\n        pygst.require('0.10')\n        pygst._gst_already_checked = True\n    import gst\nexcept:\n    raise\n\n# install the gobject iteration\nfrom kivy.support import install_gobject_iteration\ninstall_gobject_iteration()\n\n\nclass CameraPyGst(CameraBase):\n    '''Implementation of CameraBase using GStreamer\n\n    :Parameters:\n        `video_src` : str, default is 'v4l2src'\n            Other tested options are: 'dc1394src' for firewire\n            dc camera (e.g. firefly MV). Any gstreamer video source\n            should potentially work.\n            Theoretically a longer string using \"!\" can be used\n            describing the first part of a gstreamer pipeline.\n    '''\n\n    def __init__(self, **kwargs):\n        self._pipeline = None\n        self._camerasink = None\n        self._decodebin = None\n        self._texturesize = None\n        self._video_src = kwargs.get('video_src', 'v4l2src')\n        super(CameraPyGst, self).__init__(**kwargs)\n\n    def init_camera(self):\n        # TODO: This doesn't work when camera resolution is resized at runtime.\n        # There must be some other way to release the camera?\n        if self._pipeline:\n            self._pipeline = None\n\n        video_src = self._video_src\n        if video_src == 'v4l2src':\n            video_src += ' device=/dev/video%d' % self._index\n        elif video_src == 'dc1394src':\n            video_src += ' camera-number=%d' % self._index\n\n        GL_CAPS = 'video/x-raw-rgb,red_mask=(int)0xff0000,' + \\\n                  'green_mask=(int)0x00ff00,blue_mask=(int)0x0000ff'\n        pl = '%s ! decodebin name=decoder ! ffmpegcolorspace ! appsink ' + \\\n             'name=camerasink emit-signals=True caps=%s'\n        self._pipeline = gst.parse_launch(pl % (video_src, GL_CAPS))\n        self._camerasink = self._pipeline.get_by_name('camerasink')\n        self._camerasink.connect('new-buffer', self._gst_new_buffer)\n        self._decodebin = self._pipeline.get_by_name('decoder')\n\n        if self._camerasink and not self.stopped:\n            self.start()\n\n    def _gst_new_buffer(self, *largs):\n        self._format = 'rgb'\n        frame = self._camerasink.emit('pull-buffer')\n        if frame is None:\n            return\n        self._buffer = frame.data\n        if self._texturesize is None:\n            # try to get the camera image size\n            for x in self._decodebin.src_pads():\n                for cap in x.get_caps():\n                    self._texturesize = (cap['width'], cap['height'])\n                    Clock.schedule_once(self._update)\n                    return\n        Clock.schedule_once(self._update)\n\n    def start(self):\n        super(CameraPyGst, self).start()\n        self._pipeline.set_state(gst.STATE_PLAYING)\n\n    def stop(self):\n        super(CameraPyGst, self).stop()\n        self._pipeline.set_state(gst.STATE_PAUSED)\n\n    def _update(self, dt):\n        if self._buffer is None:\n            return\n        if self._texture is None and self._texturesize is not None:\n            self._texture = Texture.create(\n                size=self._texturesize, colorfmt='rgb')\n            self._texture.flip_vertical()\n            self.dispatch('on_load')\n        self._copy_to_gpu()\n"
  },
  {
    "path": "tickeys/kivy/core/camera/camera_videocapture.py",
    "content": "'''\nVideoCapture Camera: Implement CameraBase with VideoCapture\n'''\n\n#\n# TODO: make usage of thread or multiprocess\n#\n\n__all__ = ('CameraVideoCapture', )\n\nfrom kivy.core.camera import CameraBase\nfrom kivy.clock import Clock\n\ntry:\n    from VideoCapture import Device\nexcept:\n    raise\n\n\nclass CameraVideoCapture(CameraBase):\n    '''Implementation of CameraBase using VideoCapture\n    '''\n\n    def __init__(self, **kwargs):\n        self._device = None\n        super(CameraVideoCapture, self).__init__(**kwargs)\n        self._format = 'bgr'\n\n    def init_camera(self):\n        # create the device\n        self._device = Device(devnum=self._index, showVideoWindow=0)\n        # set resolution\n        try:\n            self._device.setResolution(self.resolution[0], self.resolution[1])\n        except:\n            raise Exception('VideoCapture: Resolution not supported')\n        self.fps = 1 / 30.\n\n    def _update(self, dt):\n        data, camera_width, camera_height = self._device.getBuffer()\n        if self._texture is None:\n            # first update, resize if necessary\n            self.size = camera_width, camera_height\n            # and create texture\n            from kivy.graphics.texture import Texture\n            self._texture = Texture.create(size=self.size, colorfmt='rgb')\n            self.dispatch('on_load')\n\n        # update buffer\n        self._buffer = data\n        self._copy_to_gpu()\n\n    def start(self):\n        super(CameraVideoCapture, self).start()\n        Clock.unschedule(self._update)\n        Clock.schedule_interval(self._update, self.fps)\n\n    def stop(self):\n        super(CameraVideoCapture, self).stop()\n        Clock.unschedule(self._update)\n"
  },
  {
    "path": "tickeys/kivy/core/clipboard/__init__.py",
    "content": "'''\nClipboard\n=========\n\nCore class for accessing the Clipboard. If we are not able to access the\nsystem clipboard, a fake one will be used.\n\nUsage example::\n\n    >>> from kivy.core.clipboard import Clipboard\n    >>> Clipboard.get_types()\n    ['TIMESTAMP', 'TARGETS', 'MULTIPLE', 'SAVE_TARGETS', 'UTF8_STRING',\n    'COMPOUND_TEXT', 'TEXT', 'STRING', 'text/plain;charset=utf-8',\n    'text/plain']\n    >>> Clipboard.get('TEXT')\n    'Hello World'\n    >>> Clipboard.put('Great', 'UTF8_STRING')\n    >>> Clipboard.get_types()\n    ['UTF8_STRING']\n    >>> Clipboard.get('UTF8_STRING')\n    'Great'\n\n.. note:: The main implementation relies on Pygame and works well with\n          text/strings. Anything else might not work the same on all platforms.\n'''\n\n__all__ = ('ClipboardBase', 'Clipboard')\n\nfrom kivy.core import core_select_lib\nfrom kivy.utils import platform\nfrom kivy.setupconfig import USE_SDL2\n\n\nclass ClipboardBase(object):\n\n    def get(self, mimetype):\n        '''Get the current data in clipboard, using the mimetype if possible.\n        You not use this method directly. Use :meth:`paste` instead.\n        '''\n        return None\n\n    def put(self, data, mimetype):\n        '''Put data on the clipboard, and attach a mimetype.\n        You should not use this method directly. Use :meth:`copy` instead.\n        '''\n        pass\n\n    def get_types(self):\n        '''Return a list of supported mimetypes\n        '''\n        return []\n\n    def _ensure_clipboard(self):\n        ''' Ensure that the clipboard has been properly initialised.\n        '''\n\n        if hasattr(self, '_clip_mime_type'):\n            return\n\n        if platform == 'win':\n            self._clip_mime_type = 'text/plain;charset=utf-8'\n            # windows clipboard uses a utf-16 little endian encoding\n            self._encoding = 'utf-16-le'\n        elif platform == 'linux':\n            self._clip_mime_type = 'text/plain;charset=utf-8'\n            self._encoding = 'utf-8'\n        else:\n            self._clip_mime_type = 'text/plain'\n            self._encoding = 'utf-8'\n\n    def copy(self, data=''):\n        ''' Copy the value provided in argument `data` into current clipboard.\n        If data is not of type string it will be converted to string.\n\n        .. versionadded:: 1.9.0\n\n        '''\n        if data:\n            self._copy(data)\n\n    def paste(self):\n        ''' Get text from the system clipboard and return it a usable string.\n\n        .. versionadded:: 1.9.0\n\n        '''\n        return self._paste()\n\n    def _copy(self, data):\n        # explicitly terminate strings with a null character\n        # so as to avoid putting spurious data after the end.\n        # MS windows issue.\n        self._ensure_clipboard()\n        if not isinstance(data, bytes):\n            data = data.encode(self._encoding)\n        if platform == 'win':\n            data += b'\\x00'\n        self.put(data, self._clip_mime_type)\n\n    def _paste(self):\n        self._ensure_clipboard()\n        _clip_types = Clipboard.get_types()\n\n        mime_type = self._clip_mime_type\n        if mime_type not in _clip_types:\n            mime_type = 'text/plain'\n\n        data = self.get(mime_type)\n        if data is not None:\n            # decode only if we don't have unicode\n            # we would still need to decode from utf-16 (windows)\n            # data is of type bytes in PY3\n            if isinstance(data, bytes):\n                data = data.decode(self._encoding, 'ignore')\n            # remove null strings mostly a windows issue\n            data = data.replace(u'\\x00', u'')\n            return data\n        return u''\n\n\n# load clipboard implementation\n_clipboards = []\nif platform == 'android':\n    _clipboards.append(\n        ('android', 'clipboard_android', 'ClipboardAndroid'))\nelif platform == 'macosx':\n    _clipboards.append(\n        ('nspaste', 'clipboard_nspaste', 'ClipboardNSPaste'))\nelif platform == 'win':\n    _clipboards.append(\n        ('winctypes', 'clipboard_winctypes', 'ClipboardWindows'))\nelif platform == 'linux':\n    _clipboards.append(\n        ('dbusklipper', 'clipboard_dbusklipper', 'ClipboardDbusKlipper'))\n    _clipboards.append(\n        ('gtk3', 'clipboard_gtk3', 'ClipboardGtk3'))\n    _clipboards.append(\n        ('xsel', 'clipboard_xsel', 'ClipboardXsel'))\n\nif USE_SDL2:\n    if platform != 'linux':\n        _clipboards.append(\n            ('sdl2', 'clipboard_sdl2', 'ClipboardSDL2'))\nelse:\n    _clipboards.append(\n        ('pygame', 'clipboard_pygame', 'ClipboardPygame'))\n\n_clipboards.append(\n    ('dummy', 'clipboard_dummy', 'ClipboardDummy'))\n\nClipboard = core_select_lib('clipboard', _clipboards, True)\n\n"
  },
  {
    "path": "tickeys/kivy/core/clipboard/clipboard_android.py",
    "content": "'''\nClipboard Android\n=================\n\nAndroid implementation of Clipboard provider, using Pyjnius.\n'''\n\n__all__ = ('ClipboardAndroid', )\n\nfrom kivy.core.clipboard import ClipboardBase\nfrom jnius import autoclass\nfrom android.runnable import run_on_ui_thread\n\nAndroidString = autoclass('java.lang.String')\nPythonActivity = autoclass('org.renpy.android.PythonActivity')\nContext = autoclass('android.content.Context')\nVER = autoclass('android.os.Build$VERSION')\nsdk = VER.SDK_INT\n\n\nclass ClipboardAndroid(ClipboardBase):\n\n    def __init__(self):\n        super(ClipboardAndroid, self).__init__()\n        self._clipboard = None\n        self._data = dict()\n        self._data['text/plain'] = None\n        self._data['application/data'] = None\n        PythonActivity._clipboard = None\n\n    def get(self, mimetype='text/plain'):\n        return self._get(mimetype)\n\n    def put(self, data, mimetype='text/plain'):\n        self._set(data, mimetype)\n\n    def get_types(self):\n        return list(self._data.keys())\n\n    @run_on_ui_thread\n    def _initialize_clipboard(self):\n        PythonActivity._clipboard = PythonActivity.getSystemService(\n            Context.CLIPBOARD_SERVICE)\n\n    def _get_clipboard(f):\n        def called(*args, **kargs):\n            self = args[0]\n            if not PythonActivity._clipboard:\n                self._initialize_clipboard()\n                import time\n                while not PythonActivity._clipboard:\n                    time.sleep(.01)\n            return f(*args, **kargs)\n        return called\n\n    @_get_clipboard\n    def _get(self, mimetype='text/plain'):\n        clippy = PythonActivity._clipboard\n        if sdk < 11:\n            data = clippy.getText()\n        else:\n            ClipDescription = autoclass('android.content.ClipDescription')\n            primary_clip = clippy.getPrimaryClip()\n            if primary_clip and clippy.getPrimaryClipDescription().hasMimeType(\n                    ClipDescription.MIMETYPE_TEXT_PLAIN):\n                data = primary_clip.getItemAt(0).getText().toString()\n            else:\n                # TODO: non text data types Not yet implemented\n                data = ''\n        return data\n\n    @_get_clipboard\n    def _set(self, data, mimetype):\n        clippy = PythonActivity._clipboard\n\n        if sdk < 11:\n            #versions previous to honeycomb\n            clippy.setText(AndroidString(data))\n        else:\n            ClipData = autoclass('android.content.ClipData')\n            new_clip = ClipData.newPlainText(AndroidString(\"\"),\n                                         AndroidString(data))\n            # put text data onto clipboard\n            clippy.setPrimaryClip(new_clip)\n"
  },
  {
    "path": "tickeys/kivy/core/clipboard/clipboard_dbusklipper.py",
    "content": "'''\nClipboard Dbus: an implementation of the Clipboard using dbus and klipper.\n'''\n\n__all__ = ('ClipboardDbusKlipper', )\n\nfrom kivy.utils import platform\nfrom kivy.core.clipboard import ClipboardBase\n\nif platform != 'linux':\n    raise SystemError('unsupported platform for dbus kde clipboard')\n\ntry:\n    import dbus\n    bus = dbus.SessionBus()\n    proxy = bus.get_object(\"org.kde.klipper\", \"/klipper\")\nexcept:\n    raise\n\n\nclass ClipboardDbusKlipper(ClipboardBase):\n\n    _is_init = False\n\n    def init(self):\n        if ClipboardDbusKlipper._is_init:\n            return\n        self.iface = dbus.Interface(proxy, \"org.kde.klipper.klipper\")\n        ClipboardDbusKlipper._is_init = True\n\n    def get(self, mimetype='text/plain'):\n        self.init()\n        return str(self.iface.getClipboardContents())\n\n    def put(self, data, mimetype='text/plain'):\n        self.init()\n        self.iface.setClipboardContents(data.replace('\\x00', ''))\n\n    def get_types(self):\n        self.init()\n        return [u'text/plain']\n"
  },
  {
    "path": "tickeys/kivy/core/clipboard/clipboard_dummy.py",
    "content": "'''\nClipboard Dummy: an internal implementation that does not use the system\nclipboard.\n'''\n\n__all__ = ('ClipboardDummy', )\n\nfrom kivy.core.clipboard import ClipboardBase\n\n\nclass ClipboardDummy(ClipboardBase):\n\n    def __init__(self):\n        super(ClipboardDummy, self).__init__()\n        self._data = dict()\n        self._data['text/plain'] = None\n        self._data['application/data'] = None\n\n    def get(self, mimetype='text/plain'):\n        return self._data.get(mimetype, None)\n\n    def put(self, data, mimetype='text/plain'):\n        self._data[mimetype] = data\n\n    def get_types(self):\n        return list(self._data.keys())\n"
  },
  {
    "path": "tickeys/kivy/core/clipboard/clipboard_gtk3.py",
    "content": "'''\nClipboard Gtk3: an implementation of the Clipboard using Gtk3.\n'''\n\n__all__ = ('ClipboardGtk3',)\n\nfrom kivy.utils import platform\nfrom kivy.support import install_gobject_iteration\nfrom kivy.core.clipboard import ClipboardBase\n\nif platform != 'linux':\n    raise SystemError('unsupported platform for gtk3 clipboard')\n\nfrom gi.repository import Gtk, Gdk\nclipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)\n\n\nclass ClipboardGtk3(ClipboardBase):\n\n    _is_init = False\n\n    def init(self):\n        if self._is_init:\n            return\n        install_gobject_iteration()\n        self._is_init = True\n\n    def get(self, mimetype='text/plain;charset=utf-8'):\n        self.init()\n        if mimetype == 'text/plain;charset=utf-8':\n            contents = clipboard.wait_for_text()\n            if contents:\n                return contents\n        return ''\n\n    def put(self, data, mimetype='text/plain;charset=utf-8'):\n        self.init()\n        if mimetype == 'text/plain;charset=utf-8':\n            text = data.decode(self._encoding)\n            clipboard.set_text(text, -1)\n\n    def get_types(self):\n        self.init()\n        return ['text/plain;charset=utf-8']\n"
  },
  {
    "path": "tickeys/kivy/core/clipboard/clipboard_nspaste.py",
    "content": "'''\nClipboard OsX: implementation of clipboard using Appkit\n'''\n\n__all__ = ('ClipboardNSPaste', )\n\nfrom kivy.core.clipboard import ClipboardBase\nfrom kivy.utils import platform\n\nif platform != 'macosx':\n    raise SystemError('Unsupported platform for appkit clipboard.')\ntry:\n    from pyobjus import autoclass\n    from pyobjus.dylib_manager import load_framework, INCLUDE\n    load_framework(INCLUDE.AppKit)\nexcept ImportError:\n    raise SystemError('Pyobjus not installed. Please run the following'\n        ' command to install it. `pip install --user pyobjus`')\n\nNSPasteboard = autoclass('NSPasteboard')\nNSString = autoclass('NSString')\n\n\nclass ClipboardNSPaste(ClipboardBase):\n\n    def __init__(self):\n        super(ClipboardNSPaste, self).__init__()\n        self._clipboard = NSPasteboard.generalPasteboard()\n\n    def get(self, mimetype='text/plain'):\n        pb = self._clipboard\n        data = pb.stringForType_('public.utf8-plain-text')\n        if not data:\n            return \"\"\n        return data.UTF8String()\n\n    def put(self, data, mimetype='text/plain'):\n        pb = self._clipboard\n        pb.clearContents()\n        pb.writeObjects_([data])\n\n    def get_types(self):\n        return list('text/plain',)\n"
  },
  {
    "path": "tickeys/kivy/core/clipboard/clipboard_pygame.py",
    "content": "'''\nClipboard Pygame: an implementation of the Clipboard using pygame.scrap.\n'''\n\n__all__ = ('ClipboardPygame', )\n\nfrom kivy.utils import platform\nfrom kivy.compat import PY2\nfrom kivy.core.clipboard import ClipboardBase\n\nif platform not in ('win', 'linux', 'macosx'):\n    raise SystemError('unsupported platform for pygame clipboard')\n\ntry:\n    import pygame\n    import pygame.scrap\nexcept:\n    raise\n\n\nclass ClipboardPygame(ClipboardBase):\n\n    _is_init = False\n    _types = None\n\n    _aliases = {\n        'text/plain;charset=utf-8': 'UTF8_STRING'\n    }\n\n    def init(self):\n        if ClipboardPygame._is_init:\n            return\n        pygame.scrap.init()\n        ClipboardPygame._is_init = True\n\n    def get(self, mimetype='text/plain'):\n        self.init()\n        mimetype = self._aliases.get(mimetype, mimetype)\n        text = pygame.scrap.get(mimetype)\n        return text\n\n    def put(self, data, mimetype='text/plain'):\n        self.init()\n        mimetype = self._aliases.get(mimetype, mimetype)\n        pygame.scrap.put(mimetype, data)\n\n    def get_types(self):\n        if not self._types:\n            self.init()\n            types = pygame.scrap.get_types()\n            for mime, pygtype in self._aliases.items()[:]:\n                if mime in types:\n                    del self._aliases[mime]\n                if pygtype in types:\n                    types.append(mime)\n            self._types = types\n        return self._types\n\n"
  },
  {
    "path": "tickeys/kivy/core/clipboard/clipboard_sdl2.py",
    "content": "'''\nClipboard SDL2: an implementation of the Clipboard using sdl2.\n'''\n\n__all__ = ('ClipboardSDL2', )\n\nfrom kivy.utils import platform\nfrom kivy.core.clipboard import ClipboardBase\n\nif platform not in ('win', 'linux', 'macosx', 'android', 'ios'):\n    raise SystemError('unsupported platform for sdl2 clipboard')\n\ntry:\n    from kivy.core.clipboard._clipboard_sdl2 import (\n        _get_text, _has_text, _set_text)\nexcept ImportError:\n    raise SystemError('extension not compiled?')\n\n\nclass ClipboardSDL2(ClipboardBase):\n\n    def get(self, mimetype):\n        return _get_text() if _has_text() else ''\n\n    def _ensure_clipboard(self):\n        super(ClipboardSDL2, self)._ensure_clipboard()\n        self._encoding = 'utf8'\n\n    def put(self, data=b'', mimetype='text/plain'):\n        _set_text(data)\n\n    def get_types(self):\n        return ['text/plain']\n"
  },
  {
    "path": "tickeys/kivy/core/clipboard/clipboard_winctypes.py",
    "content": "'''\nClipboard windows: an implementation of the Clipboard using ctypes.\n'''\n\n__all__ = ('ClipboardWindows', )\n\nfrom kivy.utils import platform\nfrom kivy.core.clipboard import ClipboardBase\n\nif platform != 'win':\n    raise SystemError('unsupported platform for Windows clipboard')\n\nimport ctypes\nuser32 = ctypes.windll.user32\nkernel32 = ctypes.windll.kernel32\nmsvcrt = ctypes.cdll.msvcrt\nc_char_p = ctypes.c_char_p\nc_wchar_p = ctypes.c_wchar_p\n\n\nclass ClipboardWindows(ClipboardBase):\n\n    def get(self, mimetype='text/plain'):\n        user32.OpenClipboard(0)\n        # 1 is CF_TEXT\n        pcontents = user32.GetClipboardData(13)\n        if not pcontents:\n            return ''\n        data = c_wchar_p(pcontents).value.encode(self._encoding)\n        #ctypes.windll.kernel32.GlobalUnlock(pcontents)\n        user32.CloseClipboard()\n        return data\n\n    def put(self, text, mimetype='text/plain'):\n        GMEM_DDESHARE = 0x2000\n        CF_UNICODETEXT = 13\n        user32.OpenClipboard(None)\n        user32.EmptyClipboard()\n        hCd = kernel32.GlobalAlloc(GMEM_DDESHARE, len(text) + 2)\n        pchData = kernel32.GlobalLock(hCd)\n        msvcrt.wcscpy(c_wchar_p(pchData), text)\n        kernel32.GlobalUnlock(hCd)\n        user32.SetClipboardData(CF_UNICODETEXT, hCd)\n        user32.CloseClipboard()\n\n    def get_types(self):\n        return list('text/plain',)\n"
  },
  {
    "path": "tickeys/kivy/core/clipboard/clipboard_xsel.py",
    "content": "'''\nClipboard xsel: an implementation of the Clipboard using xsel command line tool.\n'''\n\n__all__ = ('ClipboardXsel', )\n\nfrom kivy.utils import platform\nfrom kivy.core.clipboard import ClipboardBase\n\nif platform != 'linux':\n    raise SystemError('unsupported platform for xsel clipboard')\n\ntry:\n    import subprocess\n    p = subprocess.Popen(['xsel'], stdout=subprocess.PIPE)\n    p.communicate()\nexcept:\n    raise\n\n\nclass ClipboardXsel(ClipboardBase):\n\n    def get(self, mimetype='text/plain'):\n        p = subprocess.Popen(['xsel', '-bo'], stdout=subprocess.PIPE)\n        data, _ = p.communicate()\n        return data\n\n    def put(self, data, mimetype='text/plain'):\n        p = subprocess.Popen(['xsel', '-bi'], stdin=subprocess.PIPE)\n        p.communicate(data)\n\n    def get_types(self):\n        return [u'text/plain']\n"
  },
  {
    "path": "tickeys/kivy/core/gl/__init__.py",
    "content": "# pylint: disable=W0611\n'''\nOpenGL\n======\n\nSelect and use the best OpenGL library available. Depending on your system, the\ncore provider can select an OpenGL ES or a 'classic' desktop OpenGL library.\n'''\n\nfrom os import environ\nfrom sys import platform as sysplatform, exit\n\n\nMIN_REQUIRED_GL_VERSION = (2, 0)\n\n\ndef msgbox(message):\n    if sysplatform == 'win32':\n        import ctypes\n        ctypes.windll.user32.MessageBoxW(\n                None, message, u\"Kivy Fatal Error\", 0)\n        exit(1)\n\nif 'KIVY_DOC' not in environ:\n\n    from kivy.logger import Logger\n    from kivy.graphics import gl_init_resources\n    from kivy.graphics.opengl_utils import gl_get_version\n    from kivy.graphics.opengl import GL_VERSION, GL_VENDOR, GL_RENDERER, \\\n        GL_MAX_TEXTURE_IMAGE_UNITS, GL_MAX_TEXTURE_SIZE, \\\n        GL_SHADING_LANGUAGE_VERSION,\\\n        glGetString, glGetIntegerv, gl_init_symbols\n    from kivy.utils import platform\n\n    def init_gl():\n        gl_init_symbols()\n        print_gl_version()\n        gl_init_resources()\n\n    def print_gl_version():\n        version = glGetString(GL_VERSION)\n        vendor = glGetString(GL_VENDOR)\n        renderer = glGetString(GL_RENDERER)\n        Logger.info('GL: OpenGL version <{0}>'.format(version))\n        Logger.info('GL: OpenGL vendor <{0}>'.format(vendor))\n        Logger.info('GL: OpenGL renderer <{0}>'.format(renderer))\n\n        # Let the user know if his graphics hardware/drivers are too old\n        major, minor = gl_get_version()\n        Logger.info('GL: OpenGL parsed version: %d, %d' % (major, minor))\n        if (major, minor) < MIN_REQUIRED_GL_VERSION:\n            msg = (\n                'GL: Minimum required OpenGL version (2.0) NOT found!\\n\\n'\n                'OpenGL version detected: {0}.{1}\\n\\n'\n                'Version: {2}\\nVendor: {3}\\nRenderer: {4}\\n\\n'\n                'Try upgrading your graphics drivers and/or your '\n                'graphics hardware in case of problems.\\n\\n'\n                'The application will leave now.').format(\n                    major, minor, version, vendor, renderer)\n            Logger.critical(msg)\n            msgbox(msg)\n\n        if platform != 'android':\n            # XXX in the android emulator (latest version at 22 march 2013),\n            # this call was segfaulting the gl stack.\n            Logger.info('GL: Shading version <{0}>'.format(\n                glGetString(GL_SHADING_LANGUAGE_VERSION)))\n        Logger.info('GL: Texture max size <{0}>'.format(\n            glGetIntegerv(GL_MAX_TEXTURE_SIZE)[0]))\n        Logger.info('GL: Texture max units <{0}>'.format(\n            glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS)[0]))\n\n    # To be able to use our GL provider, we must have a window\n    # Automaticly import window auto to ensure the default window creation\n    import kivy.core.window  # NOQA\n"
  },
  {
    "path": "tickeys/kivy/core/image/__init__.py",
    "content": "'''\nImage\n=====\n\nCore classes for loading images and converting them to a\n:class:`~kivy.graphics.texture.Texture`. The raw image data can be keep in\nmemory for further access.\n\nIn-memory image loading\n-----------------------\n\n.. versionadded:: 1.9.0\n\n    Official support for in-memory loading. Not all the providers supports it,\n    but at the moment, pygame, pil and imageio works.\n\nTo load an image with a filename, you usually do::\n\n    from kivy.core.image import Image as CoreImage\n    im = CoreImage(\"image.png\")\n\nNow you can load from memory block. Instead of passing the filename, you'll need\nto pass the data as a BytesIO object + an \"ext\" parameters. Both are mandatory::\n\n    import io\n    from kivy.core.image import Image as CoreImage\n    data = io.BytesIO(open(\"image.png\", \"rb\").read())\n    im = CoreImage(data, ext=\"png\")\n\nBy default, the image will not be cached, as our internal cache require a\nfilename. If you want caching, add a filename that represent your file (it will\nbe used only for caching)::\n\n    import io\n    from kivy.core.image import Image as CoreImage\n    data = io.BytesIO(open(\"image.png\", \"rb\").read())\n    im = CoreImage(data, ext=\"png\", filename=\"image.png\")\n\n'''\n\n__all__ = ('Image', 'ImageLoader', 'ImageData')\n\nfrom kivy.event import EventDispatcher\nfrom kivy.core import core_register_libs\nfrom kivy.logger import Logger\nfrom kivy.cache import Cache\nfrom kivy.clock import Clock\nfrom kivy.atlas import Atlas\nfrom kivy.resources import resource_find\nfrom kivy.utils import platform\nfrom kivy.compat import string_types\nfrom kivy.setupconfig import USE_SDL2\nimport zipfile\nfrom io import BytesIO\n\n\n# late binding\nTexture = TextureRegion = None\n\n\n# register image caching only for keep_data=True\nCache.register('kv.image', timeout=60)\nCache.register('kv.atlas')\n\n\nclass ImageData(object):\n    '''Container for images and mipmap images.\n    The container will always have at least the mipmap level 0.\n    '''\n\n    __slots__ = ('fmt', 'mipmaps', 'source', 'flip_vertical', 'source_image')\n    _supported_fmts = ('rgb', 'rgba', 'bgr', 'bgra', 's3tc_dxt1', 's3tc_dxt3',\n                       's3tc_dxt5', 'pvrtc_rgb2', 'pvrtc_rgb4', 'pvrtc_rgba2',\n                       'pvrtc_rgba4', 'etc1_rgb8')\n\n    def __init__(self, width, height, fmt, data, source=None,\n                 flip_vertical=True, source_image=None,\n                 rowlength=0):\n        assert fmt in ImageData._supported_fmts\n\n        #: Decoded image format, one of a available texture format\n        self.fmt = fmt\n\n        #: Data for each mipmap.\n        self.mipmaps = {}\n        self.add_mipmap(0, width, height, data, rowlength)\n\n        #: Image source, if available\n        self.source = source\n\n        #: Indicate if the texture will need to be vertically flipped\n        self.flip_vertical = flip_vertical\n\n        # the original image, which we might need to save if it is a memoryview\n        self.source_image = source_image\n\n    def release_data(self):\n        mm = self.mipmaps\n        for item in mm.values():\n            item[2] = None\n            self.source_image = None\n\n    @property\n    def width(self):\n        '''Image width in pixels.\n        (If the image is mipmapped, it will use the level 0)\n        '''\n        return self.mipmaps[0][0]\n\n    @property\n    def height(self):\n        '''Image height in pixels.\n        (If the image is mipmapped, it will use the level 0)\n        '''\n        return self.mipmaps[0][1]\n\n    @property\n    def data(self):\n        '''Image data.\n        (If the image is mipmapped, it will use the level 0)\n        '''\n        return self.mipmaps[0][2]\n\n    @property\n    def rowlength(self):\n        '''Image rowlength.\n        (If the image is mipmapped, it will use the level 0)\n\n        .. versionadded:: 1.9.0\n        '''\n        return self.mipmaps[0][3]\n\n    @property\n    def size(self):\n        '''Image (width, height) in pixels.\n        (If the image is mipmapped, it will use the level 0)\n        '''\n        mm = self.mipmaps[0]\n        return mm[0], mm[1]\n\n    @property\n    def have_mipmap(self):\n        return len(self.mipmaps) > 1\n\n    def __repr__(self):\n        return ('<ImageData width=%d height=%d fmt=%s '\n                'source=%r with %d images>' % (\n                    self.width, self.height, self.fmt,\n                    self.source, len(self.mipmaps)))\n\n    def add_mipmap(self, level, width, height, data, rowlength):\n        '''Add a image for a specific mipmap level.\n\n        .. versionadded:: 1.0.7\n        '''\n        self.mipmaps[level] = [int(width), int(height), data, rowlength]\n\n    def get_mipmap(self, level):\n        '''Get the mipmap image at a specific level if it exists\n\n        .. versionadded:: 1.0.7\n        '''\n        if level == 0:\n            return (self.width, self.height, self.data, self.rowlength)\n        assert(level < len(self.mipmaps))\n        return self.mipmaps[level]\n\n    def iterate_mipmaps(self):\n        '''Iterate over all mipmap images available.\n\n        .. versionadded:: 1.0.7\n        '''\n        mm = self.mipmaps\n        for x in range(len(mm)):\n            item = mm.get(x, None)\n            if item is None:\n                raise Exception('Invalid mipmap level, found empty one')\n            yield x, item[0], item[1], item[2], item[3]\n\n\nclass ImageLoaderBase(object):\n    '''Base to implement an image loader.'''\n\n    __slots__ = ('_texture', '_data', 'filename', 'keep_data',\n                 '_mipmap', '_nocache', '_ext', '_inline')\n\n    def __init__(self, filename, **kwargs):\n        self._mipmap = kwargs.get('mipmap', False)\n        self.keep_data = kwargs.get('keep_data', False)\n        self._nocache = kwargs.get('nocache', False)\n        self._ext = kwargs.get('ext')\n        self._inline = kwargs.get('inline')\n        self.filename = filename\n        if self._inline:\n            self._data = self.load(kwargs.get('rawdata'))\n        else:\n            self._data = self.load(filename)\n        self._textures = None\n\n    def load(self, filename):\n        '''Load an image'''\n        return None\n\n    @staticmethod\n    def can_save():\n        '''Indicate if the loader can save the Image object\n        '''\n        return False\n\n    @staticmethod\n    def can_load_memory():\n        '''Indicate if the loader can load an image by passing data\n        '''\n        return False\n\n    @staticmethod\n    def save():\n        raise NotImplementedError()\n\n    def populate(self):\n        self._textures = []\n        fname = self.filename\n        if __debug__:\n            Logger.trace('Image: %r, populate to textures (%d)' %\n                         (fname, len(self._data)))\n\n        for count in range(len(self._data)):\n\n            # first, check if a texture with the same name already exist in the\n            # cache\n            chr = type(fname)\n            uid = chr(u'%s|%d|%d') % (fname, self._mipmap, count)\n            texture = Cache.get('kv.texture', uid)\n\n            # if not create it and append to the cache\n            if texture is None:\n                imagedata = self._data[count]\n                source = '{}{}|'.format(\n                    'zip|' if fname.endswith('.zip') else '',\n                    self._nocache)\n                imagedata.source = chr(source) + uid\n                texture = Texture.create_from_data(\n                    imagedata, mipmap=self._mipmap)\n                if not self._nocache:\n                    Cache.append('kv.texture', uid, texture)\n                if imagedata.flip_vertical:\n                    texture.flip_vertical()\n\n            # set as our current texture\n            self._textures.append(texture)\n\n            # release data if ask\n            if not self.keep_data:\n                self._data[count].release_data()\n\n    @property\n    def width(self):\n        '''Image width\n        '''\n        return self._data[0].width\n\n    @property\n    def height(self):\n        '''Image height\n        '''\n        return self._data[0].height\n\n    @property\n    def size(self):\n        '''Image size (width, height)\n        '''\n        return (self._data[0].width, self._data[0].height)\n\n    @property\n    def texture(self):\n        '''Get the image texture (created on the first call)\n        '''\n        if self._textures is None:\n            self.populate()\n        if self._textures is None:\n            return None\n        return self._textures[0]\n\n    @property\n    def textures(self):\n        '''Get the textures list (for mipmapped image or animated image)\n\n        .. versionadded:: 1.0.8\n        '''\n        if self._textures is None:\n            self.populate()\n        return self._textures\n\n    @property\n    def nocache(self):\n        '''Indicate if the texture will not be stored in the cache\n\n        .. versionadded:: 1.6.0\n        '''\n        return self._nocache\n\n\nclass ImageLoader(object):\n\n    loaders = []\n\n    @staticmethod\n    def zip_loader(filename, **kwargs):\n        '''Read images from an zip file.\n\n        .. versionadded:: 1.0.8\n\n        Returns an Image with a list of type ImageData stored in Image._data\n        '''\n        # read zip in menory for faster access\n        _file = BytesIO(open(filename, 'rb').read())\n        # read all images inside the zip\n        z = zipfile.ZipFile(_file)\n        image_data = []\n        # sort filename list\n        znamelist = z.namelist()\n        znamelist.sort()\n        image = None\n        for zfilename in znamelist:\n            try:\n                #read file and store it in mem with fileIO struct around it\n                tmpfile = BytesIO(z.read(zfilename))\n                ext = zfilename.split('.')[-1].lower()\n                im = None\n                for loader in ImageLoader.loaders:\n                    if (ext not in loader.extensions()\n                        or not loader.can_load_memory()):\n                        continue\n                    Logger.debug('Image%s: Load <%s> from <%s>' %\n                                 (loader.__name__[11:], zfilename, filename))\n                    try:\n                        im = loader(zfilename, ext=ext, rawdata=tmpfile,\n                                    inline=True, **kwargs)\n                    except:\n                        # Loader failed, continue trying.\n                        continue\n                    break\n                if im is not None:\n                    # append ImageData to local variable before it's\n                    # overwritten\n                    image_data.append(im._data[0])\n                    image = im\n                #else: if not image file skip to next\n            except:\n                Logger.warning('Image: Unable to load image'\n                               '<%s> in zip <%s> trying to continue...'\n                               % (zfilename, filename))\n        z.close()\n        if len(image_data) == 0:\n            raise Exception('no images in zip <%s>' % filename)\n        # replace Image.Data with the array of all the images in the zip\n        image._data = image_data\n        image.filename = filename\n        return image\n\n    @staticmethod\n    def register(defcls):\n        ImageLoader.loaders.append(defcls)\n\n    @staticmethod\n    def load(filename, **kwargs):\n\n        # atlas ?\n        if filename[:8] == 'atlas://':\n            # remove the url\n            rfn = filename[8:]\n            # last field is the ID\n            try:\n                rfn, uid = rfn.rsplit('/', 1)\n            except ValueError:\n                raise ValueError(\n                    'Image: Invalid %s name for atlas' % filename)\n\n            # search if we already got the atlas loaded\n            atlas = Cache.get('kv.atlas', rfn)\n\n            # atlas already loaded, so reupload the missing texture in cache,\n            # because when it's not in use, the texture can be removed from the\n            # kv.texture cache.\n            if atlas:\n                texture = atlas[uid]\n                fn = 'atlas://%s/%s' % (rfn, uid)\n                cid = '{}|{:d}|{:d}'.format(fn, False, 0)\n                Cache.append('kv.texture', cid, texture)\n                return Image(texture)\n\n            # search with resource\n            afn = rfn\n            if not afn.endswith('.atlas'):\n                afn += '.atlas'\n            afn = resource_find(afn)\n            if not afn:\n                raise Exception('Unable to found %r atlas' % afn)\n            atlas = Atlas(afn)\n            Cache.append('kv.atlas', rfn, atlas)\n            # first time, fill our texture cache.\n            for nid, texture in atlas.textures.items():\n                fn = 'atlas://%s/%s' % (rfn, nid)\n                cid = '{}|{:d}|{:d}'.format(fn, False, 0)\n                Cache.append('kv.texture', cid, texture)\n            return Image(atlas[uid])\n\n        # extract extensions\n        ext = filename.split('.')[-1].lower()\n\n        # prevent url querystrings\n        if filename.startswith((('http://', 'https://'))):\n            ext = ext.split('?')[0]\n\n        filename = resource_find(filename)\n\n        # special case. When we are trying to load a \"zip\" file with image, we\n        # will use the special zip_loader in ImageLoader. This might return a\n        # sequence of images contained in the zip.\n        if ext == 'zip':\n            return ImageLoader.zip_loader(filename)\n        else:\n            im = None\n            for loader in ImageLoader.loaders:\n                if ext not in loader.extensions():\n                    continue\n                Logger.debug('Image%s: Load <%s>' %\n                             (loader.__name__[11:], filename))\n                im = loader(filename, **kwargs)\n                break\n            if im is None:\n                raise Exception('Unknown <%s> type, no loader found.' % ext)\n            return im\n\n\nclass Image(EventDispatcher):\n    '''Load an image and store the size and texture.\n\n    .. versionchanged:: 1.0.7\n\n        `mipmap` attribute has been added. The `texture_mipmap` and\n        `texture_rectangle` have been deleted.\n\n    .. versionchanged:: 1.0.8\n\n        An Image widget can change its texture. A new event 'on_texture' has\n        been introduced. New methods for handling sequenced animation have been\n        added.\n\n    :Parameters:\n        `arg` : can be a string (str), Texture or Image object.\n            A string is interpreted as a path to the image to be loaded.\n            You can also provide a texture object or an already existing\n            image object. In the latter case, a real copy of the given\n            image object will be returned.\n        `keep_data` : bool, defaults to False.\n            Keep the image data when the texture is created.\n        `scale` : float, defaults to 1.0\n            Scale of the image.\n        `mipmap` : bool, defaults to False\n            Create mipmap for the texture.\n        `anim_delay`: float, defaults to .25\n            Delay in seconds between each animation frame. Lower values means\n            faster animation.\n    '''\n\n    copy_attributes = ('_size', '_filename', '_texture', '_image',\n                       '_mipmap', '_nocache')\n\n    def __init__(self, arg, **kwargs):\n        # this event should be fired on animation of sequenced img's\n        self.register_event_type('on_texture')\n\n        super(Image, self).__init__()\n\n        self._mipmap = kwargs.get('mipmap', False)\n        self._keep_data = kwargs.get('keep_data', False)\n        self._nocache = kwargs.get('nocache', False)\n        self._size = [0, 0]\n        self._image = None\n        self._filename = None\n        self._texture = None\n        self._anim_available = False\n        self._anim_index = 0\n        self._anim_delay = 0\n        self.anim_delay = kwargs.get('anim_delay', .25)\n        # indicator of images having been loded in cache\n        self._iteration_done = False\n\n        if isinstance(arg, Image):\n            for attr in Image.copy_attributes:\n                self.__setattr__(attr, arg.__getattribute__(attr))\n        elif type(arg) in (Texture, TextureRegion):\n            if not hasattr(self, 'textures'):\n                self.textures = []\n                self.textures.append(arg)\n            self._texture = arg\n            self._size = self.texture.size\n        elif isinstance(arg, ImageLoaderBase):\n            self.image = arg\n        elif isinstance(arg, BytesIO):\n            ext = kwargs.get('ext', None)\n            if not ext:\n                raise Exception('Inline loading require \"ext\" parameter')\n            filename = kwargs.get('filename')\n            if not filename:\n                self._nocache = True\n                filename = '__inline__'\n            self.load_memory(arg, ext, filename)\n        elif isinstance(arg, string_types):\n            self.filename = arg\n        else:\n            raise Exception('Unable to load image type {0!r}'.format(arg))\n\n    def remove_from_cache(self):\n        '''Remove the Image from cache. This facilitates re-loading of\n        images from disk in case the image content has changed.\n\n        .. versionadded:: 1.3.0\n\n        Usage::\n\n            im = CoreImage('1.jpg')\n            # -- do something --\n            im.remove_from_cache()\n            im = CoreImage('1.jpg')\n            # this time image will be re-loaded from disk\n\n        '''\n        count = 0\n        f = self.filename\n        pat = type(f)(u'%s|%d|%d')\n        uid = pat % (f, self._mipmap, count)\n        Cache.remove(\"kv.image\", uid)\n        while Cache.get(\"kv.texture\", uid):\n            Cache.remove(\"kv.texture\", uid)\n            count += 1\n            uid = pat % (f, self._mipmap, count)\n\n    def _anim(self, *largs):\n        if not self._image:\n            return\n        textures = self.image.textures\n        if self._anim_index >= len(textures):\n            self._anim_index = 0\n        self._texture = self.image.textures[self._anim_index]\n        self.dispatch('on_texture')\n        self._anim_index += 1\n        self._anim_index %= len(self._image.textures)\n\n    def anim_reset(self, allow_anim):\n        '''Reset an animation if available.\n\n        .. versionadded:: 1.0.8\n\n        :Parameters:\n            `allow_anim`: bool\n                Indicate whether the animation should restart playing or not.\n\n        Usage::\n\n            # start/reset animation\n            image.anim_reset(True)\n\n            # or stop the animation\n            image.anim_reset(False)\n\n        You can change the animation speed whilst it is playing::\n\n            # Set to 20 FPS\n            image.anim_delay = 1 / 20.\n\n        '''\n        # stop animation\n        Clock.unschedule(self._anim)\n        if allow_anim and self._anim_available:\n            Clock.schedule_interval(self._anim, self.anim_delay)\n            self._anim()\n\n    def _get_anim_delay(self):\n        return self._anim_delay\n\n    def _set_anim_delay(self, x):\n        if self._anim_delay == x:\n            return\n        self._anim_delay = x\n        if self._anim_available:\n            Clock.unschedule(self._anim)\n            if self._anim_delay >= 0:\n                Clock.schedule_interval(self._anim, self._anim_delay)\n\n    anim_delay = property(_get_anim_delay, _set_anim_delay)\n    '''Delay between each animation frame. A lower value means faster\n    animation.\n\n    .. versionadded:: 1.0.8\n    '''\n\n    @property\n    def anim_available(self):\n        '''Return True if this Image instance has animation available.\n\n        .. versionadded:: 1.0.8\n        '''\n        return self._anim_available\n\n    @property\n    def anim_index(self):\n        '''Return the index number of the image currently in the texture.\n\n        .. versionadded:: 1.0.8\n        '''\n        return self._anim_index\n\n    def _img_iterate(self, *largs):\n        if not self.image or self._iteration_done:\n            return\n        self._iteration_done = True\n        imgcount = len(self.image.textures)\n        if imgcount > 1:\n            self._anim_available = True\n            self.anim_reset(True)\n        self._texture = self.image.textures[0]\n\n    def on_texture(self, *largs):\n        '''This event is fired when the texture reference or content has\n           changed. It is normally used for sequenced images.\n\n        .. versionadded:: 1.0.8\n        '''\n        pass\n\n    @staticmethod\n    def load(filename, **kwargs):\n        '''Load an image\n\n        :Parameters:\n            `filename` : str\n                Filename of the image.\n            `keep_data` : bool, defaults to False\n                Keep the image data when the texture is created.\n        '''\n        kwargs.setdefault('keep_data', False)\n        return Image(filename, **kwargs)\n\n    def _get_image(self):\n        return self._image\n\n    def _set_image(self, image):\n        self._image = image\n        if hasattr(image, 'filename'):\n            self._filename = image.filename\n        if image:\n            self._size = (self.image.width, self.image.height)\n\n    image = property(_get_image, _set_image,\n                     doc='Get/set the data image object')\n\n    def _get_filename(self):\n        return self._filename\n\n    def _set_filename(self, value):\n        if value is None or value == self._filename:\n            return\n        self._filename = value\n\n        # construct uid as a key for Cache\n        f = self.filename\n        uid = type(f)(u'%s|%d|%d') % (f, self._mipmap, 0)\n\n        # in case of Image have been asked with keep_data\n        # check the kv.image cache instead of texture.\n        image = Cache.get('kv.image', uid)\n        if image:\n            # we found an image, yeah ! but reset the texture now.\n            self.image = image\n            # if image.__class__ is core image then it's a texture\n            # from atlas or other sources and has no data so skip\n            if (image.__class__ != self.__class__ and\n                    not image.keep_data and self._keep_data):\n                self.remove_from_cache()\n                self._filename = ''\n                self._set_filename(value)\n            else:\n                self._texture = None\n                self._img_iterate()\n            return\n        else:\n            # if we already got a texture, it will be automatically reloaded.\n            _texture = Cache.get('kv.texture', uid)\n            if _texture:\n                self._texture = _texture\n                return\n\n        # if image not already in cache then load\n        tmpfilename = self._filename\n        image = ImageLoader.load(\n            self._filename, keep_data=self._keep_data,\n            mipmap=self._mipmap, nocache=self._nocache)\n        self._filename = tmpfilename\n        # put the image into the cache if needed\n        if isinstance(image, Texture):\n            self._texture = image\n            self._size = image.size\n        else:\n            self.image = image\n            if not self._nocache:\n                Cache.append('kv.image', uid, self.image)\n\n    filename = property(_get_filename, _set_filename,\n                        doc='Get/set the filename of image')\n\n    def load_memory(self, data, ext, filename='__inline__'):\n        '''(internal) Method to load an image from raw data.\n        '''\n        self._filename = filename\n\n        # see if there is a available loader for it\n        loaders = [loader for loader in ImageLoader.loaders if\n                   loader.can_load_memory() and\n                   ext in loader.extensions()]\n        if not loaders:\n            raise Exception('No inline loader found to load {}'.format(ext))\n        image = loaders[0](filename, ext=ext, rawdata=data, inline=True,\n                nocache=self._nocache, mipmap=self._mipmap,\n                keep_data=self._keep_data)\n        if isinstance(image, Texture):\n            self._texture = image\n            self._size = image.size\n        else:\n            self.image = image\n\n    @property\n    def size(self):\n        '''Image size (width, height)\n        '''\n        return self._size\n\n    @property\n    def width(self):\n        '''Image width\n        '''\n        return self._size[0]\n\n    @property\n    def height(self):\n        '''Image height\n        '''\n        return self._size[1]\n\n    @property\n    def texture(self):\n        '''Texture of the image'''\n        if self.image:\n            if not self._iteration_done:\n                self._img_iterate()\n        return self._texture\n\n    @property\n    def nocache(self):\n        '''Indicate whether the texture will not be stored in the cache or not.\n\n        .. versionadded:: 1.6.0\n        '''\n        return self._nocache\n\n    def save(self, filename, flipped=False):\n        '''Save image texture to file.\n\n        The filename should have the '.png' extension because the texture data\n        read from the GPU is in the RGBA format. '.jpg' might work but has not\n        been heavilly tested so some providers might break when using it.\n        Any other extensions are not officially supported.\n\n        The flipped parameter flips the saved image vertically, and\n        defaults to True.\n\n        Example::\n\n            # Save an core image object\n            from kivy.core.image import Image\n            img = Image('hello.png')\n            img.save('hello2.png')\n\n            # Save a texture\n            texture = Texture.create(...)\n            img = Image(texture)\n            img.save('hello3.png')\n\n        .. versionadded:: 1.7.0\n\n        .. versionchanged:: 1.8.0\n            Parameter `flipped` added to flip the image before saving, default\n            to False.\n\n        '''\n        pixels = None\n        size = None\n        loaders = [x for x in ImageLoader.loaders if x.can_save()]\n        if not loaders:\n            return False\n        loader = loaders[0]\n\n        if self.image:\n            # we might have a ImageData object to use\n            data = self.image._data[0]\n            if data.data is not None:\n                if data.fmt not in ('rgba', 'rgb'):\n                    # fast path, use the \"raw\" data when keep_data is used\n                    size = data.width, data.height\n                    pixels = data.data\n\n                else:\n                    # the format is not rgba, we need to convert it.\n                    # use texture for that.\n                    self.populate()\n\n        if pixels is None and self._texture:\n            # use the texture pixels\n            size = self._texture.size\n            pixels = self._texture.pixels\n\n        if pixels is None:\n            return False\n\n        l_pixels = len(pixels)\n        if l_pixels == size[0] * size[1] * 3:\n            fmt = 'rgb'\n        elif l_pixels == size[0] * size[1] * 4:\n            fmt = 'rgba'\n        else:\n            raise Exception('Unable to determine the format of the pixels')\n        return loader.save(filename, size[0], size[1], fmt, pixels, flipped)\n\n    def read_pixel(self, x, y):\n        '''For a given local x/y position, return the pixel color at that\n        position.\n\n        .. warning::\n            This function can only be used with images loaded with the\n            keep_data=True keyword. For example::\n\n                m = Image.load('image.png', keep_data=True)\n                color = m.read_pixel(150, 150)\n\n        :Parameters:\n            `x` : int\n                Local x coordinate of the pixel in question.\n            `y` : int\n                Local y coordinate of the pixel in question.\n        '''\n        data = self.image._data[0]\n\n        # can't use this fonction without ImageData\n        if data.data is None:\n            raise EOFError('Image data is missing, make sure that image is'\n                           'loaded with keep_data=True keyword.')\n\n        # check bounds\n        x, y = int(x), int(y)\n        if not (0 <= x < data.width and 0 <= y < data.height):\n            raise IndexError('Position (%d, %d) is out of range.' % (x, y))\n\n        assert data.fmt in ImageData._supported_fmts\n        size = 3 if data.fmt in ('rgb', 'bgr') else 4\n        index = y * data.width * size + x * size\n        raw = bytearray(data.data[index:index + size])\n        color = [c / 255.0 for c in raw]\n\n        # conversion for BGR->RGB, BGR->RGBA format\n        if data.fmt in ('bgr', 'bgra'):\n            color[0], color[2] = color[2], color[0]\n\n        return color\n\n\ndef load(filename):\n    '''Load an image'''\n    return Image.load(filename)\n\n\n# load image loaders\nimage_libs = []\n\nif platform in ('macosx', 'ios'):\n    image_libs += [('imageio', 'img_imageio')]\n\nimage_libs += [\n    ('tex', 'img_tex'),\n    ('dds', 'img_dds')]\nif USE_SDL2:\n    image_libs += [('sdl2', 'img_sdl2')]\nelse:\n    image_libs += [('pygame', 'img_pygame')]\nimage_libs += [\n    ('ffpy', 'img_ffpyplayer'),\n    ('pil', 'img_pil'),\n    ('gif', 'img_gif')]\n\nlibs_loaded = core_register_libs('image', image_libs)\n\nfrom os import environ\nif not 'KIVY_DOC' in environ and not libs_loaded:\n    import sys\n\n    Logger.critical('App: Unable to get any Image provider, abort.')\n    sys.exit(1)\n\n# resolve binding.\nfrom kivy.graphics.texture import Texture, TextureRegion\n"
  },
  {
    "path": "tickeys/kivy/core/image/img_dds.py",
    "content": "'''\nDDS: DDS image loader\n'''\n\n__all__ = ('ImageLoaderDDS', )\n\nfrom kivy.lib.ddsfile import DDSFile\nfrom kivy.logger import Logger\nfrom kivy.core.image import ImageLoaderBase, ImageData, ImageLoader\n\n\nclass ImageLoaderDDS(ImageLoaderBase):\n\n    @staticmethod\n    def extensions():\n        return ('dds', )\n\n    def load(self, filename):\n        try:\n            dds = DDSFile(filename=filename)\n        except:\n            Logger.warning('Image: Unable to load image <%s>' % filename)\n            raise\n\n        self.filename = filename\n        width, height = dds.size\n        im = ImageData(width, height, dds.dxt, dds.images[0], source=filename,\n                       flip_vertical=False)\n        if len(dds.images) > 1:\n            images = dds.images\n            images_size = dds.images_size\n            for index in range(1, len(dds.images)):\n                w, h = images_size[index]\n                data = images[index]\n                im.add_mipmap(index, w, h, data)\n        return [im]\n\n# register\nImageLoader.register(ImageLoaderDDS)\n"
  },
  {
    "path": "tickeys/kivy/core/image/img_ffpyplayer.py",
    "content": "'''\nFFPyPlayer: FFmpeg based image loader\n'''\n\n__all__ = ('ImageLoaderFFPy', )\n\nimport ffpyplayer\nfrom ffpyplayer.pic import ImageLoader as ffImageLoader, SWScale\nfrom ffpyplayer.tools import set_log_callback, loglevels, get_log_callback\n\nfrom kivy.logger import Logger\nfrom kivy.core.image import ImageLoaderBase, ImageData, ImageLoader\n\n\nLogger.info('ImageLoaderFFPy: Using ffpyplayer {}'.format(ffpyplayer.version))\n\n\nlogger_func = {'quiet': Logger.critical, 'panic': Logger.critical,\n               'fatal': Logger.critical, 'error': Logger.error,\n               'warning': Logger.warning, 'info': Logger.info,\n               'verbose': Logger.debug, 'debug': Logger.debug}\n\n\ndef _log_callback(message, level):\n    message = message.strip()\n    if message:\n        logger_func[level]('ffpyplayer: {}'.format(message))\n\nif not get_log_callback():\n    set_log_callback(_log_callback)\n\n\nclass ImageLoaderFFPy(ImageLoaderBase):\n    '''Image loader based on the ffpyplayer library.\n\n    .. versionadded:: 1.9.0\n\n    .. note:\n        This provider may support more formats than what is listed in\n        :meth:`extensions`.\n    '''\n\n    @staticmethod\n    def extensions():\n        '''Return accepted extensions for this loader'''\n        # See https://www.ffmpeg.org/general.html#Image-Formats\n        return ('bmp', 'dpx', 'exr', 'gif', 'ico', 'jpeg', 'jpg2000', 'jpg',\n                'jls', 'pam', 'pbm', 'pcx', 'pgm', 'pgmyuv', 'pic', 'png',\n                'ppm', 'ptx', 'sgi', 'ras', 'tga', 'tiff', 'webp', 'xbm',\n                'xface', 'xwd')\n\n    def load(self, filename):\n        try:\n            loader = ffImageLoader(filename)\n        except:\n            Logger.warning('Image: Unable to load image <%s>' % filename)\n            raise\n\n        # update internals\n        self.filename = filename\n        images = []\n\n        while True:\n            frame, t = loader.next_frame()\n            if frame is None:\n                break\n            images.append(frame)\n        if not len(images):\n            raise Exception('No image found in {}'.format(filename))\n\n        w, h = images[0].get_size()\n        ifmt = images[0].get_pixel_format()\n        if ifmt != 'rgba' and ifmt != 'rgb24':\n            fmt = 'rgba'\n            sws = SWScale(w, h, ifmt, ofmt=fmt)\n            for i, image in enumerate(images):\n                images[i] = sws.scale(image)\n        else:\n            fmt = ifmt if ifmt == 'rgba' else 'rgb'\n\n        return [ImageData(w, h, fmt, img.to_memoryview()[0], source_image=img)\n                for img in images]\n\n\n# register\nImageLoader.register(ImageLoaderFFPy)\n"
  },
  {
    "path": "tickeys/kivy/core/image/img_gif.py",
    "content": "#-*- coding: utf-8 -*-\n#\n#    this program is free software; you can redistribute it and/or modify\n#    it under the terms of the GNU General Public License as published by\n#    the Free Software Foundation; either version 2 of the License, or\n#    (at your option) any later version.\n#\n#    this program is distributed in the hope that it will be useful,\n#    but WITHOUT ANY WARRANTY; without even the implied warranty of\n#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n#    GNU General Public License for more details.\n#\n#    You should have received a copy of the GNU General Public License\n#    if not, write to the Free Software\n#    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n#\n#   The Graphics Interchange Format(c) is the Copyright property of\n#   CompuServe Incorporated. GIF(sm) is a Service Mark property of\n#   CompuServe Incorporated.\n#\n# The unisys/lzw patent has expired, yes. If anyone puts another patent\n# over this code, you must *burn* this file.\n\n'''pygif: gif implementation in python\n\nhttp://www.java2s.com/Open-Source/Python/Network/\\\n        emesene/emesene-1.6.2/pygif/pygif.py.htm'''\n\n\n#TODO issues to fix\n#optimize for speed  #partially done#  a lot of room for improvement\nimport struct\nfrom array import array\n\nKNOWN_FORMATS = ('GIF87a', 'GIF89a')\n\nfrom kivy.compat import PY2\nfrom kivy.logger import Logger\nfrom kivy.core.image import ImageLoaderBase, ImageData, ImageLoader\n\nDebug = False\n\n\nclass ImageLoaderGIF(ImageLoaderBase):\n    '''Image loader for gif'''\n\n    @staticmethod\n    def extensions():\n        '''Return accepted extension for this loader'''\n        return ('gif', )\n\n    def load(self, filename):\n        try:\n            try:\n                im = GifDecoder(open(filename, 'rb').read())\n            except UnicodeEncodeError:\n                if PY2:\n                    im = GifDecoder(open(filename.encode('utf8'), 'rb').read())\n        except:\n            Logger.warning('Image: Unable to load Image <%s>' % filename)\n            raise\n\n        if Debug:\n            print(im.print_info())\n        img_data = []\n        ls_width = im.ls_width\n        ls_height = im.ls_height\n        im_images = im.images\n        im_palette = im.palette\n        pixel_map = array('B', [0] * (ls_width * ls_height * 4))\n        for img in im_images:\n            palette = img.palette if img.local_color_table_flag\\\n                else im_palette\n            have_transparent_color = img.has_transparent_color\n            transparent_color = img.transparent_color\n            #draw_method_restore_previous =  1 \\\n            #    if img.draw_method == 'restore previous' else 0\n            draw_method_replace = 1 \\\n                if ((img.draw_method == 'replace') or\n                    (img.draw_method == 'restore background')) else 0\n            pixels = img.pixels\n            img_height = img.height\n            img_width = img.width\n            left = img.left\n            top = img.top\n            if img_height > ls_height or img_width > ls_width or\\\n                top > ls_height or left > ls_width:\n                Logger.warning('Image_GIF: decoding error on frame <%s>' %\n                        len(img_data))\n                img_height = ls_height\n                img_width = ls_width\n                left = top = 0\n            #reverse top to bottom and left to right\n            tmp_top = (ls_height - (img_height + top))\n            img_width_plus_left = (img_width + left)\n            ls_width_multiply_4 = ls_width * 4\n            left_multiply_4 = left * 4\n            img_data_append = img_data.append\n            while img_height > 0:\n                i = left\n                img_height -= 1\n                x = (img_height * img_width) - left\n                rgba_pos = (tmp_top * ls_width_multiply_4) + (left_multiply_4)\n                tmp_top += 1\n                while i < img_width_plus_left:\n                    #this should now display corrupted gif's\n                    #instead of crashing on gif's not decoded properly\n                    try:\n                        (r, g, b) = palette[pixels[x + i]]\n                    except:\n                        rgba_pos += 4\n                        i += 1\n                        continue\n                    # when not magic pink\n                    if (r, g, b) != (255, 0, 255):\n                        if have_transparent_color:\n                            if transparent_color == pixels[x + i]:\n                                if draw_method_replace:\n                                    #transparent pixel draw method replace\n                                    pixel_map[rgba_pos + 3] = 0\n                                    rgba_pos += 4\n                                    i += 1\n                                    continue\n                                #transparent pixel draw method combine\n                                rgba_pos += 4\n                                i += 1\n                                continue\n                           # this pixel isn't transparent\n                        #doesn't have transparent color\n                        (pixel_map[rgba_pos], pixel_map[rgba_pos + 1],\n                                pixel_map[rgba_pos + 2]) = (r, g, b)\n                        pixel_map[rgba_pos + 3] = 255\n                    # if magic pink move to next pixel\n                    rgba_pos += 4\n                    i += 1\n\n            img_data_append(ImageData(ls_width, ls_height,\n                'rgba', pixel_map.tostring(), flip_vertical=False))\n            if draw_method_replace:\n                pixel_map = array('B', [0] * (ls_width * ls_height * 4))\n\n        self.filename = filename\n\n        return img_data\n\n\nclass Gif(object):\n    '''Base class to decoder'''\n\n    # struct format strings\n\n    #17,18:\n    FMT_HEADER = '<6sHHBBB'\n    #20:\n    FMT_IMGDESC = '<HHHHB'\n\n    IMAGE_SEPARATOR = 0x2C\n    EXTENSION_INTRODUCER = 0x21\n    GIF_TRAILER = 0x3b\n\n    LABEL_GRAPHIC_CONTROL = 0xF9\n    LABEL_COMMENT = 0xFE\n    LABEL_PLAINTEXT = 0x01\n\n    FMT_EXT_GRAPHIC_CONTROL = '<BBHB'  # 89a\n\n    def __init__(self, data, debug):\n        self.data = data\n        self.pointer = 0\n\n        # default data for an empty file\n        self.header = 'GIF87a'\n        self.ls_width = 0\n        self.ls_height = 0\n        self.flags = 0\n        self.color_resolution = 0\n        self.sort_flag = 0\n        self.color_table_flag = 0\n        self.global_color_table_size = 0\n        self.background_color = 0\n        self.aspect_ratio = 0\n        # greyscale palette by default\n        self.palette = [(x, x, x) for x in range(0, 256)]\n        self.images = []\n\n        self.debug_enabled = False\n        return\n\n    def pop(self, data, length=1):\n        '''gets the next $len chars from the data stack import\n        and increment the pointer'''\n\n        start = self.pointer\n        end = self.pointer + length\n        self.pointer += length\n\n        return data[start:end]\n\n    def pops(self, format, data):\n        '''pop struct: get size, pop(), unpack()'''\n        size = struct.calcsize(format)\n        return struct.unpack(format, self.pop(data, size))\n\n    def print_info(self):\n        '''prints out some useful info (..debug?)'''\n\n        print(\"Version: %s\" % self.header)\n        print(\"Logical screen width: %d\" % self.ls_width)\n        print(\"Logical screen height: %d\" % self.ls_height)\n        print(\"Flags: %s\" % repr(self.flags))\n        print(\" \" * 6, \"Color resolution: %d\" % self.color_resolution)\n        print(\" \" * 6, \"Sort flag: %r\" % self.sort_flag)\n        print(\" \" * 6, \"Global color table flag: %r\" % self.color_table_flag)\n        print(\" \" * 22, \"...size: %d (%d bytes)\" %\n              (self.global_color_table_size, self.global_color_table_size * 3))\n        print(\"Background color: %d\" % self.background_color)\n        print(\"Aspect ratio info: %d\" % self.aspect_ratio)\n\n    def new_image(self, header=None):\n        '''adds a new image descriptor'''\n        image = ImageDescriptor(self, header)\n        self.images.append(image)\n        return image\n\n\nclass ImageDescriptor(object):\n    '''A class that represents a single image'''\n\n    def __init__(self, parent, header=None):\n\n        self.parent = parent\n        # this will be set when needed\n        self.codesize = 0\n\n        # compressed output codes\n        self.lzwcode = ''\n\n        # uncompressed pixels (decoded)\n        self.pixels = []\n\n        # we assume a \"fullscreen\" image\n        self.left = self.top = 0\n        self.width = parent.ls_width\n        self.height = parent.ls_height\n\n        # yes, these default flags work...\n        self.flags = [False for x in range(8)]\n        self.local_color_table_flag = False\n        self.interlace_flag = False\n        self.sort_flag = False\n        self.local_color_table_size = 0\n        self.draw_method = 'replace'\n        self.transparent_color = -1\n        self.has_transparent_color = 0\n        self.palette = []\n\n        if header:\n            self.setup_header(header)\n\n    def setup_header(self, header):\n        '''takes a header tuple and fills the attributes'''\n\n        self.left = header[0]\n        self.top = header[1]\n        self.width = header[2]\n        self.height = header[3]\n\n        self.flags = get_bits(header[4])\n        self.local_color_table_flag = self.flags[7]\n        self.interlace_flag = self.flags[6]\n        self.sort_flag = self.flags[5]\n        #-- flags 4 and 3 are reserved\n        self.local_color_table_size = 2 ** (pack_bits(self.flags[:3]) + 1)\n        if self.local_color_table_flag:\n            if Debug:\n                print('local color table true')\n            self.palette = self.parent.get_color_table(\n                self.local_color_table_size * 3)\n\n    def get_header(self):\n        '''builds a header dynamically'''\n        flags = [False for x in range(8)]\n        flags[7] = self.local_color_table_flag\n        flags[6] = self.interlace_flag\n        flags[5] = self.sort_flag\n\n        # useless!\n        flags[2], flags[1], flags[0] = get_bits(len(self.palette), bits=3)\n\n        return (self.left, self.top, self.width, self.height, pack_bits(flags))\n\n    header = property(fget=get_header)\n\n\nclass GifDecoder(Gif):\n    '''decodes a gif file into.. something.. else..'''\n\n    def __init__(self, data, debug=False):\n        Gif.__init__(self, data, debug)\n        self.fill()\n\n    def fill(self):\n        '''reads the data and fills each field of the file'''\n\n        # start reading from the beggining of the file\n        self.pointer = 0\n\n        #17. Header.\n        #18. Logical Screen Descriptor.\n        data = self.pops(Gif.FMT_HEADER, self.data)\n\n        self.header = data[0]\n        self.ls_width = data[1]\n        self.ls_height = data[2]\n        self.background_color = data[4]\n        self.aspect_ratio = data[5]\n\n        # flags field\n        self.flags = get_bits(data[3])\n        #1 bit\n        self.color_table_flag = self.flags[7]\n        self.sort_flag = self.flags[3]\n        #3 bit\n        self.color_resolution = pack_bits(self.flags[4:7])  # 7 not included\n        #3 bit\n        self.global_color_table_size = 2 ** (pack_bits(self.flags[:3]) + 1)\n\n        #19. Global Color Table.\n        if self.color_table_flag:\n            size = (self.global_color_table_size) * 3\n            self.palette = self.get_color_table(size)\n        else:\n            # generate a greyscale palette\n            self.palette = [(x, x, x) for x in range(256)]\n\n        # blocks\n        image = None\n        self_data = self.data\n        self_pops = self.pops\n        Gif_IMAGE_SEPARATOR = Gif.IMAGE_SEPARATOR\n        Gif_FMT_IMGDESC = Gif.FMT_IMGDESC\n        self_new_image = self.new_image\n        self_pop = self.pop\n        self_debug_enabled = self.debug_enabled\n        self_lzw_decode = self.lzw_decode\n        Gif_EXTENSION_INTRODUCER = Gif.EXTENSION_INTRODUCER\n        Gif_GIF_TRAILER = Gif.GIF_TRAILER\n        Gif_LABEL_GRAPHIC_CONTROL = Gif.LABEL_GRAPHIC_CONTROL\n        trans_color = 0\n        has_transparent_color = 0\n        drw_method = 'replace'\n        while True:\n            try:\n                nextbyte = self_pops('<B', self_data)[0]\n            except:\n                nextbyte = 0x3b  # force end\n\n            #20. Image Descriptor\n            if nextbyte == Gif_IMAGE_SEPARATOR:\n                descriptor = self_pops(Gif_FMT_IMGDESC, self_data)\n                image = self_new_image(descriptor)\n                image.transparent_color = trans_color\n                image.has_transparent_color = has_transparent_color\n                image.draw_method = drw_method\n                image.codesize = self_pops('<B', self_data)[0]\n                image.lzwcode = b''\n                image_lzwcode = image.lzwcode\n                ###TODO too many corner casses for gifs:(\n                table_size = image.local_color_table_size\\\n                    if image.local_color_table_flag and \\\n                    self.global_color_table_size < image.local_color_table_size\\\n                    else self.global_color_table_size\n\n                while True:\n                    try:\n                        blocksize = self_pops('<B', self_data)[0]\n                    except:\n                        break\n                    if blocksize == 0:\n                        break   # no more image data\n                    lzwdata = self_pop(self_data, blocksize)\n                    image_lzwcode = b''.join((image_lzwcode, lzwdata))\n\n                if self_debug_enabled:\n                    print('LZW length:', len(image_lzwcode))\n\n                image.lzwcode = image_lzwcode\n                image.pixels = self_lzw_decode(image.lzwcode, image.codesize,\n                        table_size)\n\n            # Extensions\n            elif nextbyte == Gif_EXTENSION_INTRODUCER:\n                pass\n            # Gif trailer\n            elif nextbyte == Gif_GIF_TRAILER:\n                return\n            elif nextbyte == Gif_LABEL_GRAPHIC_CONTROL:\n                nextbyte = self_pops('<B', self_data)[0]\n                drw_bits = (get_bits(self_pops('<B', self_data)[0]))\n                has_transparent_color = drw_bits[0]\n                if drw_bits[2:5] == array('B', [0, 0, 1]):\n                    drw_method = 'replace'\n                elif (drw_bits[2:5]) == array('B', [0, 1, 0]):\n                    drw_method = 'restore background'\n                else:\n                    drw_method = 'restore previous'\n                nextbyte = self_pops('<B', self_data)[0]\n                nextbyte = self_pops('<B', self_data)[0]\n                nextbyte = self_pops('<B', self_data)[0]\n                trans_color = nextbyte\n                pass\n            # \"No Idea What Is This\"\n            else:\n                pass\n\n    def string_to_bits(self, string):\n        '''high level string unpacker'''\n        ordarray = array('B', string)\n        bits = array('B')\n        bits_append = bits.append\n        _get_bits = get_bits\n        for byte in ordarray:\n            list(map(bits_append, _get_bits(byte)))\n        return bits\n\n    def readable(bool_list):\n        '''Converts a list of booleans to a readable list of ints\n        Useful for debug only'''\n        return [int(x) for x in bool_list]\n\n    def bits_to_int(self, bits):\n        '''high level bit list packer'''\n        c = 1\n        i = 0\n        for bit in bits:\n            if bit:\n                i += 2 ** (c - 1)\n            c += 1\n        return i\n\n    def get_color_table(self, size):\n        '''Returns a color table in the format [(r,g,b),(r,g,b), ...]'''\n\n        raw_color_table = self.pops(\"<%dB\" % size, self.data)\n        pos = 0\n        palette = []\n        palette_append = palette.append\n\n        while pos + 3 < (size + 1):\n            red = raw_color_table[pos]\n            green = raw_color_table[pos + 1]\n            blue = raw_color_table[pos + 2]\n            palette_append((red, green, blue))\n            pos += 3\n        return palette\n\n    def lzw_decode(self, input, initial_codesize, color_table_size):\n        '''Decodes a lzw stream from input import\n        Returns list of ints (pixel values)'''\n        string_table = {}\n        output = array('B')\n        output_append = output.append\n        output_extend = output.extend\n        old = ''\n        index = 0\n\n        bits = self.string_to_bits(input)\n        self.bitpointer = 0\n\n        codesize = initial_codesize + 1\n        clearcode, end_of_info = color_table_size, color_table_size + 1\n\n        if Debug:\n            print('codesize: %d' % codesize)\n            print('clearcode %d, end_of_info: %d' % (clearcode, end_of_info))\n\n        def pop(size, _bits):\n            ''' return bits '''\n            start = self.bitpointer\n            end = self.bitpointer = start + size\n            return _bits[start: end]\n\n        def clear():\n            '''Called on clear code'''\n            string_table.clear()\n            for index in range(color_table_size):\n                string_table[index] = chr(index)\n            index = end_of_info + 1\n            return index\n\n        index = clear()\n        # skip first (clear)code\n        bits = bits[codesize:]\n        # read first code, append to output\n        self_bits_to_int = self.bits_to_int\n\n        code = self_bits_to_int(pop(codesize, bits))\n        if code in string_table:\n            output_append(ord(string_table[code]))\n        else:\n            Logger.warning('Image_GIF: decoding error on code '\n                '<%d> aode size <%d>' % (code, codesize))\n            string_table[code] = string_table[0]\n            output_append(ord(string_table[code]))\n        old = string_table[code]\n        bitlen = len(bits)\n\n        while self.bitpointer < bitlen:\n            # read next code\n            code = self_bits_to_int(pop(codesize, bits))\n\n            # special code?\n            if code == clearcode:\n                index = clear()\n                codesize = initial_codesize + 1\n                code = self_bits_to_int(pop(codesize, bits))\n                if code in string_table:\n                    output_append(ord(string_table[code]))\n                else:\n                    Logger.warning('Image_GIF: decoding error on code '\n                        '<%d> aode size <%d>' % (code, codesize))\n                    string_table[code] = string_table[0]\n                    output_append(ord(string_table[code]))\n                old = string_table[code]\n                continue\n\n            elif code == end_of_info:\n                break\n\n            # code in stringtable?\n            if code in string_table:\n                c = string_table[code]\n                string_table[index] = ''.join((old, c[0]))\n            else:\n                c = ''.join((old, old[0]))\n                string_table[code] = c\n\n            index += 1\n            old = c\n            output_extend(list(map(ord, c)))\n\n            if index == 2 ** codesize:\n                codesize += 1\n                if codesize == 13:\n                    codesize = 12\n\n        if self.debug_enabled:\n            print('Output stream len: %d' % len(output))\n        return output\n\n\ndef get_bits(flags, reverse=False, bits=8):\n    '''return a list with $bits items, one for each enabled bit'''\n\n    mybits = (1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048)[:bits]\n\n    rev_num = 1\n    if reverse:\n        rev_num = -1\n    ret = array('B')\n    ret_append = ret.append\n    for bit in mybits[::rev_num]:\n        ret_append(flags & bit != 0)\n    return ret\n\n\ndef pack_bits(bits):\n    '''convert a bit (bool or int) tuple into a int'''\n    packed = 0\n    level = 0\n    for bit in bits:\n        if bit:\n            packed += 2 ** level\n        level += 1\n    return packed\n\n# register\nImageLoader.register(ImageLoaderGIF)\n"
  },
  {
    "path": "tickeys/kivy/core/image/img_pil.py",
    "content": "'''\nPIL: PIL image loader\n'''\n\n__all__ = ('ImageLoaderPIL', )\n\ntry:\n    from PIL import Image as PILImage\nexcept:\n    import Image as PILImage\n\nfrom kivy.logger import Logger\nfrom kivy.core.image import ImageLoaderBase, ImageData, ImageLoader\n\n\nclass ImageLoaderPIL(ImageLoaderBase):\n    '''Image loader based on the PIL library.\n\n    .. versionadded:: 1.0.8\n\n    Support for GIF animation added.\n\n    Gif animation has a lot of issues(transparency/color depths... etc).\n    In order to keep it simple, what is implimented here is what is\n    natively supported by the PIL library.\n\n    As a general rule, try to use gifs that have no transparency.\n    Gif's with transparency will work but be prepared for some\n    artifacts until transparency support is improved.\n\n    '''\n\n    @staticmethod\n    def can_save():\n        return True\n\n    @staticmethod\n    def can_load_memory():\n        return True\n\n    @staticmethod\n    def extensions():\n        '''Return accepted extensions for this loader'''\n        # See http://www.pythonware.com/library/pil/handbook/index.htm\n        return ('bmp', 'bufr', 'cur', 'dcx', 'fits', 'fl', 'fpx', 'gbr',\n                'gd', 'gif', 'grib', 'hdf5', 'ico', 'im', 'imt', 'iptc',\n                'jpeg', 'jpg', 'jpe', 'mcidas', 'mic', 'mpeg', 'msp',\n                'pcd', 'pcx', 'pixar', 'png', 'ppm', 'psd', 'sgi',\n                'spider', 'tga', 'tiff', 'wal', 'wmf', 'xbm', 'xpm',\n                'xv')\n\n    def _img_correct(self, _img_tmp):\n        '''Convert image to the correct format and orientation.\n        '''\n        # image loader work only with rgb/rgba image\n        if _img_tmp.mode.lower() not in ('rgb', 'rgba'):\n            try:\n                imc = _img_tmp.convert('RGBA')\n            except:\n                Logger.warning(\n                    'Image: Unable to convert image to rgba (was %s)' %\n                    (_img_tmp.mode.lower()))\n                raise\n            _img_tmp = imc\n\n        return _img_tmp\n\n    def _img_read(self, im):\n        '''Read images from an animated file.\n        '''\n        im.seek(0)\n\n        # Read all images inside\n        try:\n            img_ol = None\n            while True:\n                img_tmp = im\n                img_tmp = self._img_correct(img_tmp)\n                if img_ol and (hasattr(im, 'dispose') and not im.dispose):\n                    # paste new frame over old so as to handle\n                    # transparency properly\n                    img_ol.paste(img_tmp, (0, 0), img_tmp)\n                    img_tmp = img_ol\n                img_ol = img_tmp\n                yield ImageData(img_tmp.size[0], img_tmp.size[1],\n                                img_tmp.mode.lower(), img_tmp.tostring())\n                im.seek(im.tell() + 1)\n        except EOFError:\n            pass\n\n    def load(self, filename):\n        try:\n            im = PILImage.open(filename)\n        except:\n            Logger.warning('Image: Unable to load image <%s>' % filename)\n            raise\n        # update internals\n        if not self._inline:\n            self.filename = filename\n        # returns an array of type ImageData len 1 if not a sequence image\n        return list(self._img_read(im))\n\n    @staticmethod\n    def save(filename, width, height, fmt, pixels, flipped=False):\n        image = PILImage.fromstring(fmt.upper(), (width, height), pixels)\n        if flipped:\n            image = image.transpose(PILImage.FLIP_TOP_BOTTOM)\n        image.save(filename)\n        return True\n\n\n# register\nImageLoader.register(ImageLoaderPIL)\n"
  },
  {
    "path": "tickeys/kivy/core/image/img_pygame.py",
    "content": "'''\nPygame: Pygame image loader\n'''\n\n__all__ = ('ImageLoaderPygame', )\n\nfrom kivy.compat import PY2\nfrom kivy.logger import Logger\nfrom kivy.core.image import ImageLoaderBase, ImageData, ImageLoader\nfrom os.path import isfile\n\ntry:\n    import pygame\nexcept:\n    raise\n\n\nclass ImageLoaderPygame(ImageLoaderBase):\n    '''Image loader based on the PIL library'''\n\n    @staticmethod\n    def extensions():\n        '''Return accepted extensions for this loader'''\n        # under macosx, i got with \"pygame.error: File is not a Windows BMP\n        # file\". documentation said: The image module is a required dependency\n        # of Pygame, but it only optionally supports any extended file formats.\n        # By default it can only load uncompressed BMP image\n        if pygame.image.get_extended() == 0:\n            return ('bmp', )\n        return ('jpg', 'jpeg', 'jpe', 'png', 'bmp', 'pcx', 'tga', 'tiff',\n                'tif', 'lbm', 'pbm', 'ppm', 'xpm')\n\n    @staticmethod\n    def can_save():\n        return True\n\n    @staticmethod\n    def can_load_memory():\n        return True\n\n    def load(self, filename):\n        if not filename:\n            import traceback\n            traceback.print_stack()\n            return\n        try:\n            im = None\n            if self._inline:\n                im = pygame.image.load(filename, 'x.{}'.format(self._ext))\n            elif isfile(filename):\n                with open(filename, 'rb') as fd:\n                    im = pygame.image.load(fd)\n            elif isinstance(filename, bytes):\n                try:\n                    fname = filename.decode()\n                    if isfile(fname):\n                        with open(fname, 'rb') as fd:\n                            im = pygame.image.load(fd)\n                except UnicodeDecodeError:\n                    pass\n            if im is None:\n                im = pygame.image.load(filename)\n        except:\n            #Logger.warning(type(filename)('Image: Unable to load image <%s>')\n            #               % filename)\n            raise\n\n        fmt = ''\n        if im.get_bytesize() == 3:\n            fmt = 'rgb'\n        elif im.get_bytesize() == 4:\n            fmt = 'rgba'\n\n        # image loader work only with rgb/rgba image\n        if fmt not in ('rgb', 'rgba'):\n            try:\n                imc = im.convert(32)\n                fmt = 'rgba'\n            except:\n                try:\n                    imc = im.convert_alpha()\n                    fmt = 'rgba'\n                except:\n                    Logger.warning(\n                        'Image: Unable to convert image %r to rgba (was %r)' %\n                        (filename, im.fmt))\n                    raise\n            im = imc\n\n        # update internals\n        if not self._inline:\n            self.filename = filename\n        data = pygame.image.tostring(im, fmt.upper())\n        return [ImageData(im.get_width(), im.get_height(),\n                fmt, data, source=filename)]\n\n    @staticmethod\n    def save(filename, width, height, fmt, pixels, flipped):\n        surface = pygame.image.fromstring(\n            pixels, (width, height), fmt.upper(), flipped)\n        pygame.image.save(surface, filename)\n        return True\n\n\n# register\nImageLoader.register(ImageLoaderPygame)\n"
  },
  {
    "path": "tickeys/kivy/core/image/img_sdl2.py",
    "content": "'''\nSDL2 image loader\n=================\n'''\n\n__all__ = ('ImageLoaderSDL2', )\n\nfrom kivy.compat import PY2\nfrom kivy.logger import Logger\nfrom kivy.core.image import ImageLoaderBase, ImageData, ImageLoader\nfrom kivy.core.image import _img_sdl2\n\n\nclass ImageLoaderSDL2(ImageLoaderBase):\n    '''Image loader based on the PIL library'''\n\n    def _ensure_ext(self):\n        _img_sdl2.init()\n\n    @staticmethod\n    def extensions():\n        '''Return accepted extensions for this loader'''\n        return ('bmp', 'jpg', 'jpeg', 'lbm', 'pcx', 'png', 'pnm', 'tga', 'tiff',\n                'webp', 'xcf', 'xpm', 'xv')\n\n    @staticmethod\n    def can_save():\n        return True\n\n    @staticmethod\n    def can_load_memory():\n        return True\n\n    def load(self, filename):\n        if self._inline:\n            data = filename.read()\n            info = _img_sdl2.load_from_memory(data)\n        else:\n            info = _img_sdl2.load_from_filename(filename)\n        if not info:\n            Logger.warning('Image: Unable to load image <%s>' % filename)\n            raise Exception('SDL2: Unable to load image')\n\n        w, h, fmt, pixels, rowlength = info\n\n        # update internals\n        if not self._inline:\n            self.filename = filename\n        return [ImageData(\n            w, h, fmt, pixels, source=filename,\n            rowlength=rowlength)]\n\n    @staticmethod\n    def save(filename, width, height, fmt, pixels, flipped):\n        _img_sdl2.save(filename, width, height, fmt, pixels, flipped)\n        return True\n\n\n# register\nImageLoader.register(ImageLoaderSDL2)\n"
  },
  {
    "path": "tickeys/kivy/core/image/img_tex.py",
    "content": "'''\nTex: Compressed texture\n'''\n\n__all__ = ('ImageLoaderTex', )\n\nimport json\nfrom struct import unpack\nfrom kivy.logger import Logger\nfrom kivy.core.image import ImageLoaderBase, ImageData, ImageLoader\n\n\nclass ImageLoaderTex(ImageLoaderBase):\n\n    @staticmethod\n    def extensions():\n        return ('tex', )\n\n    def load(self, filename):\n        try:\n            fd = open(filename, 'rb')\n            if fd.read(4) != 'KTEX':\n                raise Exception('Invalid tex identifier')\n\n            headersize = unpack('I', fd.read(4))[0]\n            header = fd.read(headersize)\n            if len(header) != headersize:\n                raise Exception('Truncated tex header')\n\n            info = json.loads(header)\n            data = fd.read()\n            if len(data) != info['datalen']:\n                raise Exception('Truncated tex data')\n\n        except:\n            Logger.warning('Image: Image <%s> is corrupted' % filename)\n            raise\n\n        width, height = info['image_size']\n        tw, th = info['texture_size']\n\n        images = [data]\n        im = ImageData(width, height, str(info['format']), images[0],\n                       source=filename)\n        '''\n        if len(dds.images) > 1:\n            images = dds.images\n            images_size = dds.images_size\n            for index in range(1, len(dds.images)):\n                w, h = images_size[index]\n                data = images[index]\n                im.add_mipmap(index, w, h, data)\n        '''\n        return [im]\n\n# register\nImageLoader.register(ImageLoaderTex)\n"
  },
  {
    "path": "tickeys/kivy/core/spelling/__init__.py",
    "content": "'''\nSpelling\n========\n\nProvides abstracted access to a range of spellchecking backends as well as\nword suggestions. The API is inspired by enchant but other backends can be\nadded that implement the same API.\n\nSpelling currently requires `python-enchant` for all platforms except\nOSX, where a native implementation exists.\n\n::\n\n    >>> from kivy.core.spelling import Spelling\n    >>> s = Spelling()\n    >>> s.list_languages()\n    ['en', 'en_CA', 'en_GB', 'en_US']\n    >>> s.select_language('en_US')\n    >>> s.suggest('helo')\n    [u'hole', u'help', u'helot', u'hello', u'halo', u'hero', u'hell', u'held',\n     u'helm', u'he-lo']\n\n'''\n\n__all__ = ('Spelling', 'SpellingBase', 'NoSuchLangError',\n           'NoLanguageSelectedError')\n\nimport sys\nfrom kivy.core import core_select_lib\n\n\nclass NoSuchLangError(Exception):\n    '''\n    Exception to be raised when a specific language could not be found.\n    '''\n    pass\n\n\nclass NoLanguageSelectedError(Exception):\n    '''\n    Exception to be raised when a language-using method is called but no\n    language was selected prior to the call.\n    '''\n    pass\n\n\nclass SpellingBase(object):\n    '''\n    Base class for all spelling providers.\n    Supports some abstract methods for checking words and getting suggestions.\n    '''\n\n    def __init__(self, language=None):\n        '''\n        If a `language` identifier (such as 'en_US') is provided and a matching\n        language exists, it is selected. If an identifier is provided and no\n        matching language exists, a NoSuchLangError exception is raised by\n        self.select_language().\n        If no `language` identifier is provided, we just fall back to the first\n        one that is available.\n\n        :Parameters:\n            `language` : str, defaults to None\n                If provided, indicates the language to be used. This needs\n                to be a language identifier understood by select_language(),\n                i.e. one of the options returned by list_languages().\n                If nothing is provided, the first available language is used.\n                If no language is available, NoLanguageSelectedError is raised.\n        '''\n        langs = self.list_languages()\n        try:\n            # If no language was specified, we just use the first one\n            # that is available.\n            fallback_lang = langs[0]\n        except IndexError:\n            raise NoLanguageSelectedError(\"No languages available!\")\n        self.select_language(language or fallback_lang)\n\n    def select_language(self, language):\n        '''\n        From the set of registered languages, select the first language\n        for `language`.\n\n        :Parameters:\n            `language` : str\n                Language identifier. Needs to be one of the options returned by\n                list_languages(). Sets the language used for spell checking and\n                word suggestions.\n        '''\n        raise NotImplementedError('select_language() method not implemented '\n                                  'by abstract spelling base class!')\n\n    def list_languages(self):\n        '''\n        Return a list of all supported languages.\n        E.g. ['en', 'en_GB', 'en_US', 'de', ...]\n        '''\n        raise NotImplementedError('list_languages() is not implemented '\n                                  'by abstract spelling base class!')\n\n    def check(self, word):\n        '''\n        If `word` is a valid word in `self._language` (the currently active\n        language), returns True. If the word shouldn't be checked, returns\n        None (e.g. for ''). If it is not a valid word in `self._language`,\n        return False.\n\n        :Parameters:\n            `word` : str\n                The word to check.\n        '''\n        raise NotImplementedError('check() not implemented by abstract ' +\n                                  'spelling base class!')\n\n    def suggest(self, fragment):\n        '''\n        For a given `fragment` (i.e. part of a word or a word by itself),\n        provide corrections (`fragment` may be misspelled) or completions\n        as a list of strings.\n\n        :Parameters:\n            `fragment` : str\n                The word fragment to get suggestions/corrections for.\n                E.g. 'foo' might become 'of', 'food' or 'foot'.\n\n        '''\n        raise NotImplementedError('suggest() not implemented by abstract ' +\n                                  'spelling base class!')\n\n\n_libs = (('enchant', 'spelling_enchant', 'SpellingEnchant'), )\nif sys.platform == 'darwin':\n    _libs += (('osxappkit', 'spelling_osxappkit', 'SpellingOSXAppKit'), )\n\nSpelling = core_select_lib('spelling', _libs)\n"
  },
  {
    "path": "tickeys/kivy/core/spelling/spelling_enchant.py",
    "content": "'''\nEnchant Spelling: Implements spelling backend based on enchant.\n'''\n\n\nimport enchant\n\nfrom kivy.core.spelling import SpellingBase, NoSuchLangError\nfrom kivy.compat import PY2\n\n\nclass SpellingEnchant(SpellingBase):\n    '''\n    Spelling backend based on the enchant library.\n    '''\n\n    def __init__(self, language=None):\n        self._language = None\n        super(SpellingEnchant, self).__init__(language)\n\n    def select_language(self, language):\n        try:\n            self._language = enchant.Dict(language)\n        except enchant.DictNotFoundError:\n            err = 'Enchant Backend: No language for \"%s\"' % (language, )\n            raise NoSuchLangError(err)\n\n    def list_languages(self):\n        # Note: We do NOT return enchant.list_dicts because that also returns\n        #       the enchant dict objects and not only the language identifiers.\n        return enchant.list_languages()\n\n    def check(self, word):\n        if not word:\n            return None\n        return self._language.check(word)\n\n    def suggest(self, fragment):\n        suggestions = self._language.suggest(fragment)\n        # Don't show suggestions that are invalid\n        suggestions = [s for s in suggestions if self.check(s)]\n        if PY2:\n            suggestions = [s.decode('utf-8') for s in suggestions]\n        return suggestions\n"
  },
  {
    "path": "tickeys/kivy/core/spelling/spelling_osxappkit.py",
    "content": "'''\nAppKit Spelling: Implements spelling backend based on OSX's spellchecking\n                 features provided by the ApplicationKit.\n\n                 NOTE:\n                    Requires pyobjc and setuptools to be installed!\n                    `sudo easy_install pyobjc setuptools`\n\n                 Developers should read:\n                    http://developer.apple.com/mac/library/documentation/\n                        Cocoa/Conceptual/SpellCheck/SpellCheck.html\n                    http://developer.apple.com/cocoa/pyobjc.html\n'''\n\n\nfrom AppKit import NSSpellChecker, NSMakeRange\n\nfrom kivy.core.spelling import SpellingBase, NoSuchLangError\n\n\nclass SpellingOSXAppKit(SpellingBase):\n    '''\n    Spelling backend based on OSX's spelling features provided by AppKit.\n    '''\n\n    def __init__(self, language=None):\n        self._language = NSSpellChecker.alloc().init()\n        super(SpellingOSXAppKit, self).__init__(language)\n\n    def select_language(self, language):\n        success = self._language.setLanguage_(language)\n        if not success:\n            err = 'AppKit Backend: No language \"%s\" ' % (language, )\n            raise NoSuchLangError(err)\n\n    def list_languages(self):\n        return list(self._language.availableLanguages())\n\n    def check(self, word):\n        # TODO Implement this!\n        #      NSSpellChecker provides several functions that look like what we\n        #      need, but they're a) slooow and b) return a strange result.\n        #      Might be a snow leopard bug. Have to test further.\n        #      See: http://paste.pocoo.org/show/217968/\n        if not word:\n            return None\n        err = 'check() not currently supported by the OSX AppKit backend'\n        raise NotImplementedError(err)\n\n    def suggest(self, fragment):\n        l = self._language\n        # XXX Both ways below work on OSX 10.6. It has not been tested on any\n        #     other version, but it should work.\n        try:\n            # This is deprecated as of OSX 10.6, hence the try-except\n            return list(l.guessesForWord_(fragment))\n        except AttributeError:\n            # From 10.6 onwards you're supposed to do it like this:\n            checkrange = NSMakeRange(0, len(fragment))\n            g = l.guessesForWordRange_inString_language_inSpellDocumentWithTag_(\n                checkrange, fragment, l.language(), 0)\n            # Right, this was much easier, Apple! :-)\n            return list(g)\n"
  },
  {
    "path": "tickeys/kivy/core/text/__init__.py",
    "content": "'''\nText\n====\n\nAn abstraction of text creation. Depending of the selected backend, the\naccuracy of text rendering may vary.\n\n.. versionchanged:: 1.5.0\n    :attr:`LabelBase.line_height` added.\n\n.. versionchanged:: 1.0.7\n    The :class:`LabelBase` does not generate any texture if the text has a\n    width <= 1.\n\nThis is the backend layer for getting text out of different text providers,\nyou should only be using this directly if your needs aren't fulfilled by the\n:class:`~kivy.uix.label.Label`.\n\nUsage example::\n\n    from kivy.core.label import Label as CoreLabel\n\n    ...\n    ...\n    my_label = CoreLabel()\n    my_label.text = 'hello'\n    # the label is usually not drawn until needed, so force it to draw.\n    my_label.refresh()\n    # Now access the texture of the label and use it wherever and\n    # however you may please.\n    hello_texture = my_label.texture\n\n'''\n\n__all__ = ('LabelBase', 'Label')\n\nimport re\nimport os\nfrom functools import partial\nfrom copy import copy\nfrom kivy import kivy_data_dir\nfrom kivy.utils import platform\nfrom kivy.graphics.texture import Texture\nfrom kivy.core import core_select_lib\nfrom kivy.core.text.text_layout import layout_text, LayoutWord\nfrom kivy.resources import resource_find, resource_add_path\nfrom kivy.compat import PY2\nfrom kivy.setupconfig import USE_SDL2\n\nDEFAULT_FONT = 'DroidSans'\n\nFONT_REGULAR = 0\nFONT_ITALIC = 1\nFONT_BOLD = 2\nFONT_BOLDITALIC = 3\n\n\nclass LabelBase(object):\n    '''Core text label.\n    This is the abstract class used by different backends to render text.\n\n    .. warning::\n        The core text label can't be changed at runtime. You must recreate one.\n\n    :Parameters:\n        `font_size`: int, defaults to 12\n            Font size of the text\n        `font_name`: str, defaults to DEFAULT_FONT\n            Font name of the text\n        `bold`: bool, defaults to False\n            Activate \"bold\" text style\n        `italic`: bool, defaults to False\n            Activate \"italic\" text style\n        `text_size`: tuple, defaults to (None, None)\n            Add constraint to render the text (inside a bounding box).\n            If no size is given, the label size will be set to the text size.\n        `padding`: float, defaults to None\n            If it's a float, it will set padding_x and padding_y\n        `padding_x`: float, defaults to 0.0\n            Left/right padding\n        `padding_y`: float, defaults to 0.0\n            Top/bottom padding\n        `halign`: str, defaults to \"left\"\n            Horizontal text alignment inside the bounding box\n        `valign`: str, defaults to \"bottom\"\n            Vertical text alignment inside the bounding box\n        `shorten`: bool, defaults to False\n            Indicate whether the label should attempt to shorten its textual\n            contents as much as possible if a `size` is given.\n            Setting this to True without an appropriately set size will lead to\n            unexpected results.\n        `shorten_from`: str, defaults to `center`\n            The side from which we should shorten the text from, can be left,\n            right, or center. E.g. if left, the ellipsis will appear towards\n            the left side and it will display as much text starting from the\n            right as possible.\n        `split_str`: string, defaults to `' '` (space)\n            The string to use to split the words by when shortening. If empty,\n            we can split after every character filling up the line as much as\n            possible.\n        `max_lines`: int, defaults to 0 (unlimited)\n            If set, this indicate how maximum line are allowed to render the\n            text. Works only if a limitation on text_size is set.\n        `mipmap` : bool, defaults to False\n            Create a mipmap for the texture\n        `strip` : bool, defaults to False\n            Whether each row of text has its leading and trailing spaces\n            stripped. If `halign` is `justify` it is implicitly True.\n        `strip_reflow` : bool, defaults to True\n            Whether text that has been reflowed into a second line should\n            be striped, even if `strip` is False. This is only in effect when\n            `size_hint_x` is not None, because otherwise lines are never\n            split.\n        `unicode_errors` : str, defaults to `'replace'`\n            How to handle unicode decode errors. Can be `'strict'`, `'replace'`\n            or `'ignore'`.\n\n    .. versionchanged:: 1.9.0\n        `strip`, `strip_reflow`, `shorten_from`, `split_str`, and\n        `unicode_errors` were added.\n\n    .. versionchanged:: 1.9.0\n        `padding_x` and `padding_y` has been fixed to work as expected.\n        In the past, the text was padded by the negative of their values.\n\n    .. versionchanged:: 1.8.0\n        `max_lines` parameters has been added.\n\n    .. versionchanged:: 1.0.8\n        `size` have been deprecated and replaced with `text_size`.\n\n    .. versionchanged:: 1.0.7\n        The `valign` is now respected. This wasn't the case previously\n        so you might have an issue in your application if you have not\n        considered this.\n\n    '''\n\n    __slots__ = ('options', 'texture', '_label', '_text_size')\n\n    _cached_lines = []\n\n    _fonts = {}\n\n    _fonts_cache = {}\n\n    _fonts_dirs = []\n\n    _texture_1px = None\n\n    def __init__(\n        self, text='', font_size=12, font_name=DEFAULT_FONT, bold=False,\n        italic=False, halign='left', valign='bottom', shorten=False,\n        text_size=None, mipmap=False, color=None, line_height=1.0, strip=False,\n        strip_reflow=True, shorten_from='center', split_str=' ',\n        unicode_errors='replace', **kwargs):\n\n        # Include system fonts_dir in resource paths.\n        # This allows us to specify a font from those dirs.\n        LabelBase.get_system_fonts_dir()\n\n        options = {'text': text, 'font_size': font_size,\n                   'font_name': font_name, 'bold': bold, 'italic': italic,\n                   'halign': halign, 'valign': valign, 'shorten': shorten,\n                   'mipmap': mipmap, 'line_height': line_height,\n                   'strip': strip, 'strip_reflow': strip_reflow,\n                   'shorten_from': shorten_from, 'split_str': split_str,\n                   'unicode_errors': unicode_errors}\n\n        options['color'] = color or (1, 1, 1, 1)\n        options['padding'] = kwargs.get('padding', (0, 0))\n        if not isinstance(options['padding'], (list, tuple)):\n            options['padding'] = (options['padding'], options['padding'])\n        options['padding_x'] = kwargs.get('padding_x', options['padding'][0])\n        options['padding_y'] = kwargs.get('padding_y', options['padding'][1])\n\n        if 'size' in kwargs:\n            options['text_size'] = kwargs['size']\n        else:\n            if text_size is None:\n                options['text_size'] = (None, None)\n            else:\n                options['text_size'] = text_size\n\n        self._text_size = options['text_size']\n        self._text = options['text']\n        self._internal_size = 0, 0  # the real computed text size (inclds pad)\n        self._cached_lines = []\n\n        self.options = options\n        self.texture = None\n        self.resolve_font_name()\n\n    @staticmethod\n    def register(name, fn_regular, fn_italic=None, fn_bold=None,\n                 fn_bolditalic=None):\n        '''Register an alias for a Font.\n\n        .. versionadded:: 1.1.0\n\n        If you're using a ttf directly, you might not be able to use the\n        bold/italic properties of\n        the ttf version. If the font is delivered in multiple files\n        (one regular, one italic and one bold), then you need to register these\n        files and use the alias instead.\n\n        All the fn_regular/fn_italic/fn_bold parameters are resolved with\n        :func:`kivy.resources.resource_find`. If fn_italic/fn_bold are None,\n        fn_regular will be used instead.\n        '''\n\n        fonts = []\n\n        for font_type in fn_regular, fn_italic, fn_bold, fn_bolditalic:\n            if font_type is not None:\n                font = resource_find(font_type)\n\n                if font is None:\n                    raise IOError('File {0}s not found'.format(font_type))\n                else:\n                    fonts.append(font)\n            else:\n                fonts.append(fonts[-1])  # add regular font to list again\n\n        LabelBase._fonts[name] = tuple(fonts)\n\n    def resolve_font_name(self):\n        options = self.options\n        fontname = options['font_name']\n        fonts = self._fonts\n        fontscache = self._fonts_cache\n\n        # is the font is registered ?\n        if fontname in fonts:\n            # return the prefered font for the current bold/italic combinaison\n            italic = int(options['italic'])\n            if options['bold']:\n                bold = FONT_BOLD\n            else:\n                bold = FONT_REGULAR\n\n            options['font_name_r'] = fonts[fontname][italic | bold]\n\n        elif fontname in fontscache:\n            options['font_name_r'] = fontscache[fontname]\n        else:\n            filename = resource_find(fontname)\n            if not filename:\n                fontname = fontname + \\\n                    ('' if fontname.endswith('.ttf') else '.ttf')\n                filename = resource_find(fontname)\n\n            if filename is None:\n                # XXX for compatibility, check directly in the data dir\n                filename = os.path.join(kivy_data_dir, fontname)\n                if not os.path.exists(filename):\n                    raise IOError('Label: File %r not found' % fontname)\n            fontscache[fontname] = filename\n            options['font_name_r'] = filename\n\n    @staticmethod\n    def get_system_fonts_dir():\n        '''Return the Directory used by the system for fonts.\n        '''\n        if LabelBase._fonts_dirs:\n            return LabelBase._fonts_dirs\n\n        fdirs = []\n        if platform == 'linux':\n            fdirs = [\n                '/usr/share/fonts/truetype', '/usr/local/share/fonts',\n                os.path.expanduser('~/.fonts'),\n                os.path.expanduser('~/.local/share/fonts')]\n        elif platform == 'macosx':\n            fdirs = ['/Library/Fonts', '/System/Library/Fonts',\n                os.path.expanduser('~/Library/Fonts')]\n        elif platform == 'win':\n            fdirs = [os.environ['SYSTEMROOT'] + os.sep + 'Fonts']\n        elif platform == 'ios':\n            fdirs = ['/System/Library/Fonts']\n        elif platform == 'android':\n            fdirs = ['/system/fonts']\n\n        if fdirs:\n            fdirs.append(kivy_data_dir + os.sep + 'fonts')\n            # let's register the font dirs\n            rdirs = []\n            for _dir in fdirs:\n                if os.path.exists(_dir):\n                    resource_add_path(_dir)\n                    rdirs.append(_dir)\n            LabelBase._fonts_dirs = rdirs\n            return rdirs\n        raise Exception(\"Unknown Platform {}\".format(platform))\n\n    def get_extents(self, text):\n        '''Return a tuple (width, height) indicating the size of the specified\n        text'''\n        return (0, 0)\n\n    def get_cached_extents(self):\n        '''Returns a cached version of the :meth:`get_extents` function.\n\n        ::\n\n            >>> func = self._get_cached_extents()\n            >>> func\n            <built-in method size of pygame.font.Font object at 0x01E45650>\n            >>> func('a line')\n            (36, 18)\n\n        .. warning::\n\n            This method returns a size measuring function that is valid\n            for the font settings used at the time :meth:`get_cached_extents`\n            was called. Any change in the font settings will render the\n            returned function incorrect. You should only use this if you know\n            what you're doing.\n\n        .. versionadded:: 1.9.0\n        '''\n        return self.get_extents\n\n    def _render_begin(self):\n        pass\n\n    def _render_text(self, text, x, y):\n        pass\n\n    def _render_end(self):\n        pass\n\n    def shorten(self, text, margin=2):\n        ''' Shortens the text to fit into a single line by the width specified\n        by :attr:`text_size` [0]. If :attr:`text_size` [0] is None, it returns\n        text text unchanged.\n\n        :attr:`split_str` and :attr:`shorten_from` determines how the text is\n        shortened.\n\n        :params:\n\n            `text` str, the text to be shortened.\n            `margin` int, the amount of space to leave between the margins\n            and the text. This is in addition to :attr:`padding_x`.\n\n        :retruns:\n            the text shortened to fit into a single line.\n        '''\n        textwidth = self.get_cached_extents()\n        uw = self.text_size[0]\n        if uw is None or not text:\n            return text\n\n        opts = self.options\n        uw = max(0, int(uw - opts['padding_x'] * 2 - margin))\n        # if larger, it won't fit so don't even try extents\n        chr = type(text)\n        text = text.replace(chr('\\n'), chr(' '))\n        if len(text) <= uw and textwidth(text)[0] <= uw:\n            return text\n        c = opts['split_str']\n        offset = 0 if len(c) else 1\n        dir = opts['shorten_from'][0]\n        elps = textwidth('...')[0]\n        if elps > uw:\n            if textwidth('..')[0] <= uw:\n                return '..'\n            else:\n                return '.'\n        uw -= elps\n\n        f = partial(text.find, c)\n        f_rev = partial(text.rfind, c)\n        # now find the first and last word\n        e1, s2 = f(), f_rev()\n\n        if dir != 'l':  # center or right\n            # no split, or the first word doesn't even fit\n            if e1 != -1:\n                l1 = textwidth(text[:e1])[0]\n                l2 = textwidth(text[s2 + 1:])[0]\n            if e1 == -1 or l1 + l2 > uw:\n                if len(c):\n                    opts['split_str'] = ''\n                    res = self.shorten(text, margin)\n                    opts['split_str'] = c\n                    return res\n                # at this point we do char by char so e1 must be zero\n                if l1 <= uw:\n                    return chr('{0}...').format(text[:e1])\n                return chr('...')\n\n            # both word fits, and there's at least on split_str\n            if s2 == e1:  # there's only on split_str\n                return chr('{0}...{1}').format(text[:e1], text[s2 + 1:])\n\n            # both the first and last word fits, and they start/end at diff pos\n            if dir == 'r':\n                ee1 = f(e1 + 1)\n                while l2 + textwidth(text[:ee1])[0] <= uw:\n                    e1 = ee1\n                    if e1 == s2:\n                        break\n                    ee1 = f(e1 + 1)\n            else:\n                while True:\n                    if l1 <= l2:\n                        ee1 = f(e1 + 1)\n                        l1 = textwidth(text[:ee1])[0]\n                        if l2 + l1 > uw:\n                            break\n                        e1 = ee1\n                        if e1 == s2:\n                            break\n                    else:\n                        ss2 = f_rev(0, s2 - offset)\n                        l2 = textwidth(text[ss2 + 1:])[0]\n                        if l2 + l1 > uw:\n                            break\n                        s2 = ss2\n                        if e1 == s2:\n                            break\n        else:  # left\n            # no split, or the last word doesn't even fit\n            if s2 != -1:\n                l2 = textwidth(text[s2 + (1 if len(c) else -1):])[0]\n                l1 = textwidth(text[:max(0, e1)])[0]\n            # if split_str\n            if s2 == -1 or l2 + l1 > uw:\n                if len(c):\n                    opts['split_str'] = ''\n                    res = self.shorten(text, margin)\n                    opts['split_str'] = c\n                    return res\n\n                return chr('...')\n\n            # both word fits, and there's at least on split_str\n            if s2 == e1:  # there's only on split_str\n                return chr('{0}...{1}').format(text[:e1], text[s2 + 1:])\n\n            # both the first and last word fits, and they start/end at diff pos\n            ss2 = f_rev(0, s2 - offset)\n            while l1 + textwidth(text[ss2 + 1:])[0] <= uw:\n                s2 = ss2\n                if s2 == e1:\n                    break\n                ss2 = f_rev(0, s2 - offset)\n\n        return chr('{0}...{1}').format(text[:e1], text[s2 + 1:])\n\n    def _render_real(self):\n        lines = self._cached_lines\n        options = None\n        for line in lines:\n            if len(line.words):  # get opts from first line, first word\n                options = line.words[0].options\n                break\n        if not options:  # there was no text to render\n            self._render_begin()\n            data = self._render_end()\n            assert(data)\n            if data is not None and data.width > 1:\n                self.texture.blit_data(data)\n            return\n\n        render_text = self._render_text\n        get_extents = self.get_cached_extents()\n        uw, uh = options['text_size']\n        xpad, ypad = options['padding_x'], options['padding_y']\n        x, y = xpad, ypad   # pos in the texture\n        iw, ih = self._internal_size  # the real size of text, not texture\n        if uw is not None:\n            uww = uw - 2 * xpad  # real width of just text\n        w, h = self.size\n        sw = options['space_width']\n        halign = options['halign']\n        valign = options['valign']\n        split = re.split\n        pat = re.compile('( +)')\n        self._render_begin()\n\n        if valign == 'bottom':\n            y = h - ih + ypad\n        elif valign == 'middle':\n            y = int((h - ih) / 2 + ypad)\n\n        for layout_line in lines:  # for plain label each line has only one str\n            lw, lh = layout_line.w, layout_line.h\n            line = ''\n            assert len(layout_line.words) < 2\n            if len(layout_line.words):\n                last_word = layout_line.words[0]\n                line = last_word.text\n            x = xpad\n            if halign[0] == 'c':  # center\n                x = int((w - lw) / 2.)\n            elif halign[0] == 'r':  # right\n                x = max(0, int(w - lw - xpad))\n\n            # right left justify\n            # divide left over space between `spaces`\n            # TODO implement a better method of stretching glyphs?\n            if (uw is not None and halign[-1] == 'y' and line and not\n                layout_line.is_last_line):\n                # number spaces needed to fill, and remainder\n                n, rem = divmod(max(uww - lw, 0), sw)\n                n = int(n)\n                words = None\n                if n or rem:\n                    # there's no trailing space when justify is selected\n                    words = split(pat, line)\n                if words is not None and len(words) > 1:\n                    space = type(line)(' ')\n                    # words: every even index is spaces, just add ltr n spaces\n                    for i in range(n):\n                        idx = (2 * i + 1) % (len(words) - 1)\n                        words[idx] = words[idx] + space\n                    if rem:\n                        # render the last word at the edge, also add it to line\n                        ext = get_extents(words[-1])\n                        word = LayoutWord(last_word.options, ext[0], ext[1],\n                                          words[-1])\n                        layout_line.words.append(word)\n                        last_word.lw = uww - ext[0]  # word was stretched\n                        render_text(words[-1], x + last_word.lw, y)\n                        last_word.text = line = ''.join(words[:-2])\n                    else:\n                        last_word.lw = uww  # word was stretched\n                        last_word.text = line = ''.join(words)\n                    layout_line.w = uww  # the line occupies full width\n\n            if len(line):\n                layout_line.x = x\n                layout_line.y = y\n                render_text(line, x, y)\n            y += lh\n\n        # get data from provider\n        data = self._render_end()\n        assert(data)\n\n        # If the text is 1px width, usually, the data is black.\n        # Don't blit that kind of data, otherwise, you have a little black bar.\n        if data is not None and data.width > 1:\n            self.texture.blit_data(data)\n\n    def render(self, real=False):\n        '''Return a tuple (width, height) to create the image\n        with the user constraints. (width, height) includes the padding.\n        '''\n        if real:\n            return self._render_real()\n\n        options = copy(self.options)\n        options['space_width'] = self.get_extents(' ')[0]\n        options['strip'] = strip = (options['strip'] or\n                                    options['halign'][-1] == 'y')\n        uw, uh = options['text_size'] = self._text_size\n        text = self.text\n        if strip:\n            text = text.strip()\n        if uw is not None and options['shorten']:\n            text = self.shorten(text)\n        self._cached_lines = lines = []\n        if not text:\n            return 0, 0\n\n        if uh is not None and options['valign'][-1] == 'e':  # middle\n            center = -1  # pos of newline\n            if len(text) > 1:\n                middle = int(len(text) // 2)\n                l, r = text.rfind('\\n', 0, middle), text.find('\\n', middle)\n                if l != -1 and r != -1:\n                    center = l if center - l <= r - center else r\n                elif l != -1:\n                    center = l\n                elif r != -1:\n                    center = r\n            # if a newline split text, render from center down and up til uh\n            if center != -1:\n                # layout from center down until half uh\n                w, h, clipped = layout_text(text[center + 1:], lines, (0, 0),\n                (uw, uh / 2), options, self.get_cached_extents(), True, True)\n                # now layout from center upwards until uh is reached\n                w, h, clipped = layout_text(text[:center + 1], lines, (w, h),\n                (uw, uh), options, self.get_cached_extents(), False, True)\n            else:  # if there's no new line, layout everything\n                w, h, clipped = layout_text(text, lines, (0, 0), (uw, None),\n                options, self.get_cached_extents(), True, True)\n        else:  # top or bottom\n            w, h, clipped = layout_text(text, lines, (0, 0), (uw, uh), options,\n                self.get_cached_extents(), options['valign'][-1] == 'p', True)\n        self._internal_size = w, h\n        if uw:\n            w = uw\n        if uh:\n            h = uh\n        if h > 1 and w < 2:\n            w = 2\n        return int(w), int(h)\n\n    def _texture_refresh(self, *l):\n        self.refresh()\n\n    def _texture_fill(self, texture):\n        # second pass, render for real\n        self.render(real=True)\n\n    def refresh(self):\n        '''Force re-rendering of the text\n        '''\n        self.resolve_font_name()\n\n        # first pass, calculating width/height\n        sz = self.render()\n        self._size_texture = sz\n        self._size = (sz[0], sz[1])\n\n        # if no text are rendered, return nothing.\n        width, height = self._size\n        if width <= 1 or height <= 1:\n            self.texture = self.texture_1px\n            return\n\n        # create a delayed texture\n        texture = self.texture\n        if texture is None or \\\n                width != texture.width or \\\n                height != texture.height:\n            texture = Texture.create(size=(width, height),\n                                     mipmap=self.options['mipmap'],\n                                     callback=self._texture_fill)\n            texture.flip_vertical()\n            texture.add_reload_observer(self._texture_refresh)\n            self.texture = texture\n        else:\n            texture.ask_update(self._texture_fill)\n\n    def _get_text(self):\n        if PY2:\n            try:\n                if isinstance(self._text, unicode):\n                    return self._text\n                return self._text.decode('utf8')\n            except AttributeError:\n                # python 3 support\n                return str(self._text)\n            except UnicodeDecodeError:\n                return self._text\n        else:\n            return self._text\n\n    def _set_text(self, text):\n        if text != self._text:\n            self._text = text\n\n    text = property(_get_text, _set_text, doc='Get/Set the text')\n    label = property(_get_text, _set_text, doc='Get/Set the text')\n\n    @property\n    def texture_1px(self):\n        if LabelBase._texture_1px is None:\n            tex = Texture.create(size=(1, 1), colorfmt='rgba')\n            tex.blit_buffer(b'\\x00\\x00\\x00\\x00', colorfmt='rgba')\n            LabelBase._texture_1px = tex\n        return LabelBase._texture_1px\n\n    @property\n    def size(self):\n        return self._size\n\n    @property\n    def width(self):\n        return self._size[0]\n\n    @property\n    def height(self):\n        return self._size[1]\n\n    @property\n    def content_width(self):\n        '''Return the content width; i.e. the width of the text without\n        any padding.'''\n        if self.texture is None:\n            return 0\n        return self.texture.width - 2 * self.options['padding_x']\n\n    @property\n    def content_height(self):\n        '''Return the content height; i.e. the height of the text without\n        any padding.'''\n        if self.texture is None:\n            return 0\n        return self.texture.height - 2 * self.options['padding_y']\n\n    @property\n    def content_size(self):\n        '''Return the content size (width, height)'''\n        if self.texture is None:\n            return (0, 0)\n        return (self.content_width, self.content_height)\n\n    @property\n    def fontid(self):\n        '''Return a unique id for all font parameters'''\n        return str([self.options[x] for x in (\n            'font_size', 'font_name_r', 'bold', 'italic')])\n\n    def _get_text_size(self):\n        return self._text_size\n\n    def _set_text_size(self, x):\n        self._text_size = x\n\n    text_size = property(_get_text_size, _set_text_size,\n                         doc='''Get/set the (width, height) of the '\n                         'contrained rendering box''')\n\n    usersize = property(_get_text_size, _set_text_size,\n                        doc='''(deprecated) Use text_size instead.''')\n\n# Load the appropriate provider\nlabel_libs = []\nif USE_SDL2:\n    label_libs += [('sdl2', 'text_sdl2', 'LabelSDL2')]\nelse:\n    label_libs += [('pygame', 'text_pygame', 'LabelPygame')]\nlabel_libs += [\n    ('pil', 'text_pil', 'LabelPIL')]\nLabel = core_select_lib('text', label_libs)\n\nif 'KIVY_DOC' not in os.environ:\n    if not Label:\n        from kivy.logger import Logger\n        import sys\n        Logger.critical('App: Unable to get a Text provider, abort.')\n        sys.exit(1)\n\n# For the first initalization, register the default font\n    Label.register('DroidSans',\n                   'data/fonts/DroidSans.ttf',\n                   'data/fonts/DroidSans-Italic.ttf',\n                   'data/fonts/DroidSans-Bold.ttf',\n                   'data/fonts/DroidSans-BoldItalic.ttf')\n\n"
  },
  {
    "path": "tickeys/kivy/core/text/markup.py",
    "content": "'''\nText Markup\n===========\n\n.. versionadded:: 1.1.0\n\nWe provide a simple text-markup for inline text styling. The syntax look the\nsame as the `BBCode <http://en.wikipedia.org/wiki/BBCode>`_.\n\nA tag is defined as ``[tag]``, and might have a closed tag associated:\n``[/tag]``. Example of a markup text::\n\n    [b]Hello [color=ff0000]world[/b][/color]\n\nThe following tags are availables:\n\n``[b][/b]``\n    Activate bold text\n``[i][/i]``\n    Activate italic text\n``[font=<str>][/font]``\n    Change the font\n``[size=<integer>][/size]``\n    Change the font size\n``[color=#<color>][/color]``\n    Change the text color\n``[ref=<str>][/ref]``\n    Add an interactive zone. The reference + all the word box inside the\n    reference will be available in :attr:`MarkupLabel.refs`\n``[anchor=<str>]``\n    Put an anchor in the text. You can get the position of your anchor within\n    the text with :attr:`MarkupLabel.anchors`\n``[sub][/sub]``\n    Display the text at a subscript position relative to the text before it.\n``[sup][/sup]``\n    Display the text at a superscript position relative to the text before it.\n\nIf you need to escape the markup from the current text, use\n:func:`kivy.utils.escape_markup`.\n'''\n\n__all__ = ('MarkupLabel', )\n\nimport re\nfrom kivy.properties import dpi2px\nfrom kivy.parser import parse_color\nfrom kivy.logger import Logger\nfrom kivy.core.text import Label, LabelBase\nfrom kivy.core.text.text_layout import layout_text, LayoutWord, LayoutLine\nfrom copy import copy\nfrom math import ceil\nfrom functools import partial\n\n# We need to do this trick when documentation is generated\nMarkupLabelBase = Label\nif Label is None:\n    MarkupLabelBase = LabelBase\n\n\nclass MarkupLabel(MarkupLabelBase):\n    '''Markup text label.\n\n    See module documentation for more informations.\n    '''\n\n    def __init__(self, *largs, **kwargs):\n        self._style_stack = {}\n        self._refs = {}\n        self._anchors = {}\n        super(MarkupLabel, self).__init__(*largs, **kwargs)\n        self._internal_size = 0, 0\n        self._cached_lines = []\n\n    @property\n    def refs(self):\n        '''Get the bounding box of all the ``[ref=...]``::\n\n            { 'refA': ((x1, y1, x2, y2), (x1, y1, x2, y2)), ... }\n        '''\n        return self._refs\n\n    @property\n    def anchors(self):\n        '''Get the position of all the ``[anchor=...]``::\n\n            { 'anchorA': (x, y), 'anchorB': (x, y), ... }\n        '''\n        return self._anchors\n\n    @property\n    def markup(self):\n        '''Return the text with all the markup splitted::\n\n            >>> MarkupLabel('[b]Hello world[/b]').markup\n            >>> ('[b]', 'Hello world', '[/b]')\n\n        '''\n        s = re.split('(\\[.*?\\])', self.label)\n        s = [x for x in s if x != '']\n        return s\n\n    def _push_style(self, k):\n        if not k in self._style_stack:\n            self._style_stack[k] = []\n        self._style_stack[k].append(self.options[k])\n\n    def _pop_style(self, k):\n        if k not in self._style_stack or len(self._style_stack[k]) == 0:\n            Logger.warning('Label: pop style stack without push')\n            return\n        v = self._style_stack[k].pop()\n        self.options[k] = v\n\n    def render(self, real=False):\n        options = copy(self.options)\n        if not real:\n            ret = self._pre_render()\n        else:\n            ret = self._real_render()\n        self.options = options\n        return ret\n\n    def _pre_render(self):\n        # split markup, words, and lines\n        # result: list of word with position and width/height\n        # during the first pass, we don't care about h/valign\n        self._cached_lines = lines = []\n        self._refs = {}\n        self._anchors = {}\n        clipped = False\n        w = h = 0\n        uw, uh = self.text_size\n        spush = self._push_style\n        spop = self._pop_style\n        opts = options = self.options\n        options['_ref'] = None\n        options['_anchor'] = None\n        options['script'] = 'normal'\n        shorten = options['shorten']\n        # if shorten, then don't split lines to fit uw, because it will be\n        # flattened later when shortening and broken up lines if broken\n        # mid-word will have space mid-word when lines are joined\n        uw_temp = None if shorten else uw\n        xpad = options['padding_x']\n        uhh = (None if uh is not None and options['valign'][-1] != 'p' or\n               options['shorten'] else uh)\n        options['strip'] = options['strip'] or options['halign'][-1] == 'y'\n        for item in self.markup:\n            if item == '[b]':\n                spush('bold')\n                options['bold'] = True\n                self.resolve_font_name()\n            elif item == '[/b]':\n                spop('bold')\n                self.resolve_font_name()\n            elif item == '[i]':\n                spush('italic')\n                options['italic'] = True\n                self.resolve_font_name()\n            elif item == '[/i]':\n                spop('italic')\n                self.resolve_font_name()\n            elif item[:6] == '[size=':\n                item = item[6:-1]\n                try:\n                    if item[-2:] in ('px', 'pt', 'in', 'cm', 'mm', 'dp', 'sp'):\n                        size = dpi2px(item[:-2], item[-2:])\n                    else:\n                        size = int(item)\n                except ValueError:\n                    raise\n                    size = options['font_size']\n                spush('font_size')\n                options['font_size'] = size\n            elif item == '[/size]':\n                spop('font_size')\n            elif item[:7] == '[color=':\n                color = parse_color(item[7:-1])\n                spush('color')\n                options['color'] = color\n            elif item == '[/color]':\n                spop('color')\n            elif item[:6] == '[font=':\n                fontname = item[6:-1]\n                spush('font_name')\n                options['font_name'] = fontname\n                self.resolve_font_name()\n            elif item == '[/font]':\n                spop('font_name')\n                self.resolve_font_name()\n            elif item[:5] == '[sub]':\n                spush('font_size')\n                spush('script')\n                options['font_size'] = options['font_size'] * .5\n                options['script'] = 'subscript'\n            elif item == '[/sub]':\n                spop('font_size')\n                spop('script')\n            elif item[:5] == '[sup]':\n                spush('font_size')\n                spush('script')\n                options['font_size'] = options['font_size'] * .5\n                options['script'] = 'superscript'\n            elif item == '[/sup]':\n                spop('font_size')\n                spop('script')\n            elif item[:5] == '[ref=':\n                ref = item[5:-1]\n                spush('_ref')\n                options['_ref'] = ref\n            elif item == '[/ref]':\n                spop('_ref')\n            elif not clipped and item[:8] == '[anchor=':\n                options['_anchor'] = item[8:-1]\n            elif not clipped:\n                item = item.replace('&bl;', '[').replace(\n                    '&br;', ']').replace('&amp;', '&')\n                opts = copy(options)\n                extents = self.get_cached_extents()\n                opts['space_width'] = extents(' ')[0]\n                w, h, clipped = layout_text(item, lines, (w, h),\n                    (uw_temp, uhh), opts, extents, True, False)\n\n        if len(lines):  # remove any trailing spaces from the last line\n            old_opts = self.options\n            self.options = copy(opts)\n            w, h, clipped = layout_text('', lines, (w, h), (uw_temp, uhh),\n                self.options, self.get_cached_extents(), True, True)\n            self.options = old_opts\n\n        if shorten:\n            options['_ref'] = None  # no refs for you!\n            options['_anchor'] = None\n            w, h, lines = self.shorten_post(lines, w, h)\n            self._cached_lines = lines\n        # when valign is not top, for markup we layout everything (text_size[1]\n        # is temporarily set to None) and after layout cut to size if too tall\n        elif uh != uhh and h > uh and len(lines) > 1:\n            if options['valign'][-1] == 'm':  # bottom\n                i = 0\n                while i < len(lines) - 1 and h > uh:\n                    h -= lines[i].h\n                    i += 1\n                del lines[:i]\n            else:  # middle\n                i = 0\n                top = int(h / 2. + uh / 2.)  # remove extra top portion\n                while i < len(lines) - 1 and h > top:\n                    h -= lines[i].h\n                    i += 1\n                del lines[:i]\n                i = len(lines) - 1  # remove remaining bottom portion\n                while i and h > uh:\n                    h -= lines[i].h\n                    i -= 1\n                del lines[i + 1:]\n\n        # now justify the text\n        if options['halign'][-1] == 'y' and uw is not None:\n            # XXX: update refs to justified pos\n            # when justify, each line shouldv'e been stripped already\n            split = partial(re.split, re.compile('( +)'))\n            uww = uw - 2 * xpad\n            chr = type(self.text)\n            space = chr(' ')\n            empty = chr('')\n\n            for i in range(len(lines)):\n                line = lines[i]\n                words = line.words\n                # if there's nothing to justify, we're done\n                if (not line.w or int(uww - line.w) <= 0 or not len(words) or\n                    line.is_last_line):\n                    continue\n\n                done = False\n                parts = [None, ] * len(words)  # contains words split by space\n                idxs = [None, ] * len(words)  # indices of the space in parts\n                # break each word into spaces and add spaces until it's full\n                # do first round of split in case we don't need to split all\n                for w in range(len(words)):\n                    word = words[w]\n                    sw = word.options['space_width']\n                    p = parts[w] = split(word.text)\n                    idxs[w] = [v for v in range(len(p)) if\n                               p[v].startswith(' ')]\n                    # now we have the indices of the spaces in split list\n                    for k in idxs[w]:\n                        # try to add single space at each space\n                        if line.w + sw > uww:\n                            done = True\n                            break\n                        line.w += sw\n                        word.lw += sw\n                        p[k] += space\n                    if done:\n                        break\n\n                # there's not a single space in the line?\n                if not any(idxs):\n                    continue\n\n                # now keep adding spaces to already split words until done\n                while not done:\n                    for w in range(len(words)):\n                        if not idxs[w]:\n                            continue\n                        word = words[w]\n                        sw = word.options['space_width']\n                        p = parts[w]\n                        for k in idxs[w]:\n                            # try to add single space at each space\n                            if line.w + sw > uww:\n                                done = True\n                                break\n                            line.w += sw\n                            word.lw += sw\n                            p[k] += space\n                        if done:\n                            break\n\n                # if not completely full, push last words to right edge\n                diff = int(uww - line.w)\n                if diff > 0:\n                    # find the last word that had a space\n                    for w in range(len(words) - 1, -1, -1):\n                        if not idxs[w]:\n                            continue\n                        break\n                    old_opts = self.options\n                    self.options = word.options\n                    word = words[w]\n                    # split that word into left/right and push right till uww\n                    l_text = empty.join(parts[w][:idxs[w][-1]])\n                    r_text = empty.join(parts[w][idxs[w][-1]:])\n                    left = LayoutWord(word.options,\n                        self.get_extents(l_text)[0], word.lh, l_text)\n                    right = LayoutWord(word.options,\n                        self.get_extents(r_text)[0], word.lh, r_text)\n                    left.lw = max(left.lw, word.lw + diff - right.lw)\n                    self.options = old_opts\n\n                    # now put words back together with right/left inserted\n                    for k in range(len(words)):\n                        if idxs[k]:\n                            words[k].text = empty.join(parts[k])\n                    words[w] = right\n                    words.insert(w, left)\n                else:\n                    for k in range(len(words)):\n                        if idxs[k]:\n                            words[k].text = empty.join(parts[k])\n                line.w = uww\n                w = max(w, uww)\n\n        self._internal_size = w, h\n        if uw:\n            w = uw\n        if uh:\n            h = uh\n        if h > 1 and w < 2:\n            w = 2\n        if w < 1:\n            w = 1\n        if h < 1:\n            h = 1\n        return int(w), int(h)\n\n    def _real_render(self):\n        lines = self._cached_lines\n        options = None\n        for line in lines:\n            if len(line.words):  # get opts from first line, first word\n                options = line.words[0].options\n                break\n        if not options:  # there was no text to render\n            self._render_begin()\n            data = self._render_end()\n            assert(data)\n            if data is not None and data.width > 1:\n                self.texture.blit_data(data)\n            return\n\n        old_opts = self.options\n        render_text = self._render_text\n        xpad, ypad = options['padding_x'], options['padding_y']\n        x, y = xpad, ypad   # pos in the texture\n        iw, ih = self._internal_size  # the real size of text, not texture\n        w, h = self.size\n        halign = options['halign']\n        valign = options['valign']\n        refs = self._refs\n        anchors = self._anchors\n        self._render_begin()\n\n        if valign == 'bottom':\n            y = h - ih + ypad\n        elif valign == 'middle':\n            y = int((h - ih) / 2 + ypad)\n\n        for layout_line in lines:  # for plain label each line has only one str\n            lw, lh = layout_line.w, layout_line.h\n            x = xpad\n            if halign[0] == 'c':  # center\n                x = int((w - lw) / 2.)\n            elif halign[0] == 'r':  # right\n                x = max(0, int(w - lw - xpad))\n            layout_line.x = x\n            layout_line.y = y\n            psp = pph = 0\n            for word in layout_line.words:\n                options = self.options = word.options\n                # the word height is not scaled by line_height, only lh was\n                wh = options['line_height'] * word.lh\n                # calculate sub/super script pos\n                if options['script'] == 'superscript':\n                    script_pos = max(0, psp if psp else self.get_descent())\n                    psp = script_pos\n                    pph = wh\n                elif options['script'] == 'subscript':\n                    script_pos = min(lh - wh, ((psp + pph) - wh)\n                                     if pph else (lh - wh))\n                    pph = wh\n                    psp = script_pos\n                else:\n                    script_pos = (lh - wh) / 1.25\n                    psp = pph = 0\n                if len(word.text):\n                    render_text(word.text, x, y + script_pos)\n\n                # should we record refs ?\n                ref = options['_ref']\n                if ref is not None:\n                    if not ref in refs:\n                        refs[ref] = []\n                    refs[ref].append((x, y, x + word.lw, y + wh))\n\n                # Should we record anchors?\n                anchor = options['_anchor']\n                if anchor is not None:\n                    if not anchor in anchors:\n                        anchors[anchor] = (x, y)\n                x += word.lw\n            y += lh\n\n        self.options = old_opts\n        # get data from provider\n        data = self._render_end()\n        assert(data)\n\n        # If the text is 1px width, usually, the data is black.\n        # Don't blit that kind of data, otherwise, you have a little black bar.\n        if data is not None and data.width > 1:\n            self.texture.blit_data(data)\n\n    def shorten_post(self, lines, w, h, margin=2):\n        ''' Shortens the text to a single line according to the label options.\n\n        This function operates on a text that has already been laid out because\n        for markup, parts of text can have different size and options.\n\n        If :attr:`text_size` [0] is None, the lines are returned unchanged.\n        Otherwise, the lines are converted to a single line fitting within the\n        constrained width, :attr:`text_size` [0].\n\n        :params:\n\n            `lines`: list of `LayoutLine` instances describing the text.\n            `w`: int, the width of the text in lines, including padding.\n            `h`: int, the height of the text in lines, including padding.\n            `margin` int, the additional space left on the sides. This is in\n            addition to :attr:`padding_x`.\n\n        :returns:\n            3-tuple of (xw, h, lines), where w, and h is similar to the input\n            and contains the resulting width / height of the text, including\n            padding. lines, is a list containing a single `LayoutLine`, which\n            contains the words for the line.\n        '''\n\n        def n(line, c):\n            ''' A function similar to text.find, except it's an iterator that\n            returns successive occurrences of string c in list line. line is\n            not a string, but a list of LayoutWord instances that we walk\n            from left to right returning the indices of c in the words as we\n            encounter them. Note that the options can be different among the\n            words.\n\n            :returns:\n                3-tuple: the index of the word in line, the index of the\n                occurrence in word, and the extents (width) of the combined\n                words until this occurrence, not including the occurrence char.\n                If no more are found it returns (-1, -1, total_w) where total_w\n                is the full width of all the words.\n            '''\n            total_w = 0\n            for w in range(len(line)):\n                word = line[w]\n                if not word.lw:\n                    continue\n                f = partial(word.text.find, c)\n                i = f()\n                while i != -1:\n                    self.options = word.options\n                    yield w, i, total_w + self.get_extents(word.text[:i])[0]\n                    i = f(i + 1)\n                self.options = word.options\n                total_w += self.get_extents(word.text)[0]\n            yield -1, -1, total_w  # this should never be reached, really\n\n        def p(line, c):\n            ''' Similar to the `n` function, except it returns occurrences of c\n            from right to left in the list, line, similar to rfind.\n            '''\n            total_w = 0\n            offset = 0 if len(c) else 1\n            for w in range(len(line) - 1, -1, -1):\n                word = line[w]\n                if not word.lw:\n                    continue\n                f = partial(word.text.rfind, c)\n                i = f()\n                while i != -1:\n                    self.options = word.options\n                    yield (w, i, total_w +\n                           self.get_extents(word.text[i + 1:])[0])\n                    if i:\n                        i = f(0, i - offset)\n                    else:\n                        if not c:\n                            self.options = word.options\n                            yield (w, -1, total_w +\n                                   self.get_extents(word.text)[0])\n                        break\n                self.options = word.options\n                total_w += self.get_extents(word.text)[0]\n            yield -1, -1, total_w  # this should never be reached, really\n\n        def n_restricted(line, uw, c):\n            ''' Similar to the function `n`, except it only returns the first\n            occurrence and it's not an iterator. Furthermore, if the first\n            occurrence doesn't fit within width uw, it returns the index of\n            whatever amount of text will still fit in uw.\n\n            :returns:\n                similar to the function `n`, except it's a 4-tuple, with the\n                last element a boolean, indicating if we had to clip the text\n                to fit in uw (True) or if the whole text until the first\n                occurrence fitted in uw (False).\n            '''\n            total_w = 0\n            if not len(line):\n                return 0, 0, 0\n            for w in range(len(line)):\n                word = line[w]\n                f = partial(word.text.find, c)\n                self.options = word.options\n                extents = self.get_cached_extents()\n                i = f()\n                if i != -1:\n                    ww = extents(word.text[:i])[0]\n\n                if i != -1 and total_w + ww <= uw:  # found and it fits\n                    return w, i, total_w + ww, False\n                elif i == -1:\n                    ww = extents(word.text)[0]\n                    if total_w + ww <= uw:  # wasn't found and all fits\n                        total_w += ww\n                        continue\n                    i = len(word.text)\n\n                # now just find whatever amount of the word does fit\n                e = 0\n                while e != i and total_w + extents(word.text[:e])[0] <= uw:\n                    e += 1\n                e = max(0, e - 1)\n                return w, e, total_w + extents(word.text[:e])[0], True\n\n            return -1, -1, total_w, False\n\n        def p_restricted(line, uw, c):\n            ''' Similar to `n_restricted`, except it returns the first\n            occurrence starting from the right, like `p`.\n            '''\n            total_w = 0\n            if not len(line):\n                return 0, 0, 0\n            for w in range(len(line) - 1, -1, -1):\n                word = line[w]\n                f = partial(word.text.rfind, c)\n                self.options = word.options\n                extents = self.get_cached_extents()\n                i = f()\n                if i != -1:\n                    ww = extents(word.text[i + 1:])[0]\n\n                if i != -1 and total_w + ww <= uw:  # found and it fits\n                    return w, i, total_w + ww, False\n                elif i == -1:\n                    ww = extents(word.text)[0]\n                    if total_w + ww <= uw:  # wasn't found and all fits\n                        total_w += ww\n                        continue\n\n                # now just find whatever amount of the word does fit\n                s = len(word.text) - 1\n                while s >= 0 and total_w + extents(word.text[s:])[0] <= uw:\n                    s -= 1\n                return w, s, total_w + extents(word.text[s + 1:])[0], True\n\n            return -1, -1, total_w, False\n\n        textwidth = self.get_cached_extents()\n        uw = self.text_size[0]\n        if uw is None:\n            return w, h, lines\n        old_opts = copy(self.options)\n        uw = max(0, int(uw - old_opts['padding_x'] * 2 - margin))\n        chr = type(self.text)\n        ssize = textwidth(' ')\n        c = old_opts['split_str']\n        line_height = old_opts['line_height']\n        xpad, ypad = old_opts['padding_x'], old_opts['padding_y']\n        dir = old_opts['shorten_from'][0]\n\n        # flatten lines into single line\n        line = []\n        last_w = 0\n        for l in range(len(lines)):\n            # concatenate (non-empty) inside lines with a space\n            this_line = lines[l]\n            if last_w and this_line.w and not this_line.line_wrap:\n                line.append(LayoutWord(old_opts, ssize[0], ssize[1], chr(' ')))\n            last_w = this_line.w or last_w\n            for word in this_line.words:\n                if word.lw:\n                    line.append(word)\n\n        # if that fits, just return the flattened line\n        lw = sum([word.lw for word in line])\n        if lw <= uw:\n            lh = max([word.lh for word in line] + [0]) * line_height\n            return lw + 2 * xpad, lh + 2 * ypad, [LayoutLine(0, 0,\n            lw, lh, 1, 0, line)]\n\n        # find the size of ellipsis that'll fit\n        elps_s = textwidth('...')\n        if elps_s[0] > uw:  # even ellipsis didn't fit...\n            s = textwidth('..')\n            if s[0] <= uw:\n                return (s[0] + 2 * xpad, s[1] * line_height + 2 * ypad,\n                    [LayoutLine(0, 0, s[0], s[1], 1, 0, [LayoutWord(old_opts,\n                    s[0], s[1], '..')])])\n            else:\n                s = textwidth('.')\n                return (s[0] + 2 * xpad, s[1] * line_height + 2 * ypad,\n                    [LayoutLine(0, 0, s[0], s[1], 1, 0, [LayoutWord(old_opts,\n                    s[0], s[1], '.')])])\n        elps = LayoutWord(old_opts, elps_s[0], elps_s[1], '...')\n        uw -= elps_s[0]\n\n        # now find the first left and right words that fit\n        w1, e1, l1, clipped1 = n_restricted(line, uw, c)\n        w2, s2, l2, clipped2 = p_restricted(line, uw, c)\n\n        if dir != 'l':  # center or right\n            line1 = None\n            if clipped1 or clipped2 or l1 + l2 > uw:\n                # if either was clipped or both don't fit, just take first\n                if len(c):\n                    self.options = old_opts\n                    old_opts['split_str'] = ''\n                    res = self.shorten_post(lines, w, h, margin)\n                    self.options['split_str'] = c\n                    return res\n                line1 = line[:w1]\n                last_word = line[w1]\n                last_text = last_word.text[:e1]\n                self.options = last_word.options\n                s = self.get_extents(last_text)\n                line1.append(LayoutWord(last_word.options, s[0], s[1],\n                                        last_text))\n            elif (w1, e1) == (-1, -1):  # this shouldn't occur\n                line1 = line\n            if line1:\n                line1.append(elps)\n                lw = sum([word.lw for word in line1])\n                lh = max([word.lh for word in line1]) * line_height\n                self.options = old_opts\n                return lw + 2 * xpad, lh + 2 * ypad, [LayoutLine(0, 0,\n                    lw, lh, 1, 0, line1)]\n\n            # now we know that both the first and last word fit, and that\n            # there's at least one instances of the split_str in the line\n            if (w1, e1) != (w2, s2):  # more than one split_str\n                if dir == 'r':\n                    f = n(line, c)  # iterator\n                    assert next(f)[:-1] == (w1, e1)  # first word should match\n                    ww1, ee1, l1 = next(f)\n                    while l2 + l1 <= uw:\n                        w1, e1 = ww1, ee1\n                        ww1, ee1, l1 = next(f)\n                        if (w1, e1) == (w2, s2):\n                            break\n                else:   # center\n                    f = n(line, c)  # iterator\n                    f_inv = p(line, c)  # iterator\n                    assert next(f)[:-1] == (w1, e1)\n                    assert next(f_inv)[:-1] == (w2, s2)\n                    while True:\n                        if l1 <= l2:\n                            ww1, ee1, l1 = next(f)  # hypothesize that next fit\n                            if l2 + l1 > uw:\n                                break\n                            w1, e1 = ww1, ee1\n                            if (w1, e1) == (w2, s2):\n                                break\n                        else:\n                            ww2, ss2, l2 = next(f_inv)\n                            if l2 + l1 > uw:\n                                break\n                            w2, s2 = ww2, ss2\n                            if (w1, e1) == (w2, s2):\n                                break\n        else:  # left\n            line1 = [elps]\n            if clipped1 or clipped2 or l1 + l2 > uw:\n                # if either was clipped or both don't fit, just take last\n                if len(c):\n                    self.options = old_opts\n                    old_opts['split_str'] = ''\n                    res = self.shorten_post(lines, w, h, margin)\n                    self.options['split_str'] = c\n                    return res\n                first_word = line[w2]\n                first_text = first_word.text[s2 + 1:]\n                self.options = first_word.options\n                s = self.get_extents(first_text)\n                line1.append(LayoutWord(first_word.options, s[0], s[1],\n                                        first_text))\n                line1.extend(line[w2 + 1:])\n            elif (w1, e1) == (-1, -1):  # this shouldn't occur\n                line1 = line\n            if len(line1) != 1:\n                lw = sum([word.lw for word in line1])\n                lh = max([word.lh for word in line1]) * line_height\n                self.options = old_opts\n                return lw + 2 * xpad, lh + 2 * ypad, [LayoutLine(0, 0,\n                    lw, lh, 1, 0, line1)]\n\n            # now we know that both the first and last word fit, and that\n            # there's at least one instances of the split_str in the line\n            if (w1, e1) != (w2, s2):  # more than one split_str\n                f_inv = p(line, c)  # iterator\n                assert next(f_inv)[:-1] == (w2, s2)  # last word should match\n                ww2, ss2, l2 = next(f_inv)\n                while l2 + l1 <= uw:\n                    w2, s2 = ww2, ss2\n                    ww2, ss2, l2 = next(f_inv)\n                    if (w1, e1) == (w2, s2):\n                        break\n\n        # now add back the left half\n        line1 = line[:w1]\n        last_word = line[w1]\n        last_text = last_word.text[:e1]\n        self.options = last_word.options\n        s = self.get_extents(last_text)\n        if len(last_text):\n            line1.append(LayoutWord(last_word.options, s[0], s[1], last_text))\n        line1.append(elps)\n\n        # now add back the right half\n        first_word = line[w2]\n        first_text = first_word.text[s2 + 1:]\n        self.options = first_word.options\n        s = self.get_extents(first_text)\n        if len(first_text):\n            line1.append(LayoutWord(first_word.options, s[0], s[1],\n                                    first_text))\n        line1.extend(line[w2 + 1:])\n\n        lw = sum([word.lw for word in line1])\n        lh = max([word.lh for word in line1]) * line_height\n        self.options = old_opts\n        return lw + 2 * xpad, lh + 2 * ypad, [LayoutLine(0, 0,\n            lw, lh, 1, 0, line1)]\n"
  },
  {
    "path": "tickeys/kivy/core/text/text_layout.pxd",
    "content": "\n\ncdef class LayoutWord:\n    cdef public object text\n    cdef public int lw, lh\n    cdef public dict options\n\n\ncdef class LayoutLine:\n    cdef public int x, y, w, h\n    cdef public int line_wrap  # whether this line wraps from last line\n    cdef public int is_last_line  # in a paragraph\n    cdef public list words\n"
  },
  {
    "path": "tickeys/kivy/core/text/text_pil.py",
    "content": "'''\nText PIL: Draw text with PIL\n'''\n\n__all__ = ('LabelPIL', )\n\ntry:\n    from PIL import Image, ImageFont, ImageDraw\nexcept:\n    raise\n\nfrom kivy.compat import text_type\nfrom kivy.core.text import LabelBase\nfrom kivy.core.image import ImageData\n\n# used for fetching extends before creature image surface\ndefault_font = ImageFont.load_default()\n\n\nclass LabelPIL(LabelBase):\n    _cache = {}\n\n    def _select_font(self):\n        fontsize = int(self.options['font_size'])\n        fontname = self.options['font_name_r']\n        try:\n            id = '%s.%s' % (text_type(fontname), text_type(fontsize))\n        except UnicodeDecodeError:\n            id = '%s.%s' % (fontname, fontsize)\n\n        if not id in self._cache:\n            font = ImageFont.truetype(fontname, fontsize)\n            self._cache[id] = font\n\n        return self._cache[id]\n\n    def get_extents(self, text):\n        font = self._select_font()\n        w, h = font.getsize(text)\n        return w, h\n\n    def get_cached_extents(self):\n        return self._select_font().getsize\n\n    def _render_begin(self):\n        # create a surface, context, font...\n        self._pil_im = Image.new('RGBA', self._size)\n        self._pil_draw = ImageDraw.Draw(self._pil_im)\n\n    def _render_text(self, text, x, y):\n        color = tuple([int(c * 255) for c in self.options['color']])\n        self._pil_draw.text((int(x), int(y)),\n                            text, font=self._select_font(), fill=color)\n\n    def _render_end(self):\n        data = ImageData(self._size[0], self._size[1],\n                         self._pil_im.mode.lower(), self._pil_im.tostring())\n\n        del self._pil_im\n        del self._pil_draw\n\n        return data\n"
  },
  {
    "path": "tickeys/kivy/core/text/text_pygame.py",
    "content": "'''\nText Pygame: Draw text with pygame\n'''\n\n__all__ = ('LabelPygame', )\n\nfrom kivy.compat import PY2\nfrom kivy.core.text import LabelBase\nfrom kivy.core.image import ImageData\n\ntry:\n    import pygame\nexcept:\n    raise\n\npygame_cache = {}\npygame_font_handles = {}\npygame_cache_order = []\n\n# init pygame font\ntry:\n    pygame.ftfont.init()\nexcept:\n    pygame.font.init()\n\n\nclass LabelPygame(LabelBase):\n\n    def _get_font_id(self):\n        if PY2:\n            try:\n                return '|'.join([unicode(self.options[x]) for x in\n                                 ('font_size', 'font_name_r',\n                                  'bold', 'italic')])\n            except UnicodeDecodeError:\n                pass\n        return '|'.join([str(self.options[x]) for x in\n                         ('font_size', 'font_name_r', 'bold', 'italic')])\n\n    def _get_font(self):\n        fontid = self._get_font_id()\n        if fontid not in pygame_cache:\n            # try first the file if it's a filename\n            font_handle = fontobject = None\n            fontname = self.options['font_name_r']\n            ext = fontname.rsplit('.', 1)\n            if len(ext) == 2:\n                # try to open the font if it has an extension\n                font_handle = open(fontname, 'rb')\n                fontobject = pygame.font.Font(font_handle,\n                                              int(self.options['font_size']))\n\n            # fallback to search a system font\n            if fontobject is None:\n                # try to search the font\n                font = pygame.font.match_font(\n                    self.options['font_name_r'].replace(' ', ''),\n                    bold=self.options['bold'],\n                    italic=self.options['italic'])\n\n                # fontobject\n                fontobject = pygame.font.Font(font,\n                                              int(self.options['font_size']))\n            pygame_cache[fontid] = fontobject\n            pygame_font_handles[fontid] = font_handle\n            pygame_cache_order.append(fontid)\n\n        # to prevent too much file open, limit the number of opened fonts to 64\n        while len(pygame_cache_order) > 64:\n            popid = pygame_cache_order.pop(0)\n            del pygame_cache[popid]\n            font_handle = pygame_font_handles.pop(popid)\n            if font_handle is not None:\n                font_handle.close()\n\n        return pygame_cache[fontid]\n\n    def get_ascent(self):\n        return self._get_font().get_ascent()\n\n    def get_descent(self):\n        return self._get_font().get_descent()\n\n    def get_extents(self, text):\n        return self._get_font().size(text)\n\n    def get_cached_extents(self):\n        return self._get_font().size\n\n    def _render_begin(self):\n        self._pygame_surface = pygame.Surface(self._size, pygame.SRCALPHA, 32)\n        self._pygame_surface.fill((0, 0, 0, 0))\n\n    def _render_text(self, text, x, y):\n        font = self._get_font()\n        color = [c * 255 for c in self.options['color']]\n        color[0], color[2] = color[2], color[0]\n        try:\n            text = font.render(text, True, color)\n            self._pygame_surface.blit(text, (x, y), None,\n                                      pygame.BLEND_RGBA_ADD)\n        except pygame.error:\n            pass\n\n    def _render_end(self):\n        w, h = self._size\n        data = ImageData(w, h,\n                         'rgba', self._pygame_surface.get_buffer().raw)\n\n        del self._pygame_surface\n\n        return data\n"
  },
  {
    "path": "tickeys/kivy/core/text/text_sdl2.py",
    "content": "'''\nSDL2 text provider\n==================\n\nBased on SDL2 + SDL2_ttf\n'''\n\n__all__ = ('LabelSDL2', )\n\nfrom kivy.compat import PY2\nfrom kivy.core.text import LabelBase\nfrom kivy.core.text._text_sdl2 import (_SurfaceContainer, _get_extents,\n                                       _get_fontdescent, _get_fontascent)\n\n\nclass LabelSDL2(LabelBase):\n\n    def _get_font_id(self):\n        if PY2:\n            try:\n                return '|'.join([unicode(self.options[x]) for x\n                    in ('font_size', 'font_name_r', 'bold', 'italic')])\n            except UnicodeDecodeError:\n                pass\n        return '|'.join([str(self.options[x]) for x\n            in ('font_size', 'font_name_r', 'bold', 'italic')])\n\n    def get_extents(self, text):\n        try:\n            if PY2:\n                text = text.encode('UTF-8')\n        except:\n            pass\n        return _get_extents(self, text)\n\n    def get_descent(self):\n        return _get_fontdescent(self)\n\n    def get_ascent(self):\n        return _get_fontascent(self)\n\n    def _render_begin(self):\n        self._surface = _SurfaceContainer(self._size[0], self._size[1])\n\n    def _render_text(self, text, x, y):\n        self._surface.render(self, text, x, y)\n\n    def _render_end(self):\n        return self._surface.get_data()\n\n"
  },
  {
    "path": "tickeys/kivy/core/video/__init__.py",
    "content": "'''\nVideo\n=====\n\nCore class for reading video files and managing the\n:class:`kivy.graphics.texture.Texture` video.\n\n.. versionchanged:: 1.8.0\n    There is now 2 distinct Gstreamer implementation: one using Gi/Gst\n    working for both Python 2+3 with Gstreamer 1.0, and one using PyGST\n    working only for Python 2 + Gstreamer 0.10.\n    If you have issue with GStreamer, have a look at\n    :ref:`gstreamer-compatibility`\n\n.. note::\n\n    Recording is not supported.\n'''\n\n__all__ = ('VideoBase', 'Video')\n\nfrom kivy.clock import Clock\nfrom kivy.core import core_select_lib\nfrom kivy.event import EventDispatcher\nfrom kivy.logger import Logger\nfrom kivy.compat import PY2\n\n\nclass VideoBase(EventDispatcher):\n    '''VideoBase, a class used to implement a video reader.\n\n    :Parameters:\n        `filename` : str\n            Filename of the video. Can be a file or an URI.\n        `eos` : str, defaults to 'pause'\n            Action to take when EOS is hit. Can be one of 'pause', 'stop' or\n            'loop'.\n\n            .. versionchanged:: unknown\n                added 'pause'\n\n        `async` : bool, defaults to True\n            Load the video asynchronously (may be not supported by all\n            providers).\n        `autoplay` : bool, defaults to False\n            Auto play the video on init.\n\n    :Events:\n        `on_eos`\n            Fired when EOS is hit.\n        `on_load`\n            Fired when the video is loaded and the texture is available.\n        `on_frame`\n            Fired when a new frame is written to the texture.\n    '''\n\n    __slots__ = ('_wantplay', '_buffer', '_filename', '_texture',\n                 '_volume', 'eos', '_state', '_async', '_autoplay')\n\n    __events__ = ('on_eos', 'on_load', 'on_frame')\n\n    def __init__(self, **kwargs):\n        kwargs.setdefault('filename', None)\n        kwargs.setdefault('eos', 'stop')\n        kwargs.setdefault('async', True)\n        kwargs.setdefault('autoplay', False)\n\n        super(VideoBase, self).__init__()\n\n        self._wantplay = False\n        self._buffer = None\n        self._filename = None\n        self._texture = None\n        self._volume = 1.\n        self._state = ''\n\n        self._autoplay = kwargs.get('autoplay')\n        self._async = kwargs.get('async')\n        self.eos = kwargs.get('eos')\n        if self.eos == 'pause':\n            Logger.warning(\"'pause' is deprecated. Use 'stop' instead.\")\n            self.eos = 'stop'\n        self.filename = kwargs.get('filename')\n\n        Clock.schedule_interval(self._update, 1 / 30.)\n\n        if self._autoplay:\n            self.play()\n\n    def __del__(self):\n        self.unload()\n\n    def on_eos(self):\n        pass\n\n    def on_load(self):\n        pass\n\n    def on_frame(self):\n        pass\n\n    def _get_filename(self):\n        return self._filename\n\n    def _set_filename(self, filename):\n        if filename == self._filename:\n            return\n        self.unload()\n        self._filename = filename\n        if self._filename is None:\n            return\n        self.load()\n\n    filename = property(lambda self: self._get_filename(),\n                        lambda self, x: self._set_filename(x),\n                        doc='Get/set the filename/uri of the current video')\n\n    def _get_position(self):\n        return 0\n\n    def _set_position(self, pos):\n        self.seek(pos)\n\n    position = property(lambda self: self._get_position(),\n                        lambda self, x: self._set_position(x),\n                        doc='Get/set the position in the video (in seconds)')\n\n    def _get_volume(self):\n        return self._volume\n\n    def _set_volume(self, volume):\n        self._volume = volume\n\n    volume = property(lambda self: self._get_volume(),\n                      lambda self, x: self._set_volume(x),\n                      doc='Get/set the volume in the video (1.0 = 100%)')\n\n    def _get_duration(self):\n        return 0\n\n    duration = property(lambda self: self._get_duration(),\n                        doc='Get the video duration (in seconds)')\n\n    def _get_texture(self):\n        return self._texture\n\n    texture = property(lambda self: self._get_texture(),\n                       doc='Get the video texture')\n\n    def _get_state(self):\n        return self._state\n\n    state = property(lambda self: self._get_state(),\n                     doc='Get the video playing status')\n\n    def _do_eos(self, *args):\n        '''\n        .. versionchanged:: 1.4.0\n            Now dispatches the `on_eos` event.\n        '''\n        if self.eos == 'pause':\n            self.pause()\n        elif self.eos == 'stop':\n            self.stop()\n        elif self.eos == 'loop':\n            self.position = 0\n            self.play()\n\n        self.dispatch('on_eos')\n\n    def _update(self, dt):\n        '''Update the video content to texture.\n        '''\n        pass\n\n    def seek(self, percent):\n        '''Move on percent position'''\n        pass\n\n    def stop(self):\n        '''Stop the video playing'''\n        self._state = ''\n\n    def pause(self):\n        '''Pause the video\n\n        .. versionadded:: 1.4.0\n        '''\n        self._state = 'paused'\n\n    def play(self):\n        '''Play the video'''\n        self._state = 'playing'\n\n    def load(self):\n        '''Load the video from the current filename'''\n        pass\n\n    def unload(self):\n        '''Unload the actual video'''\n        self._state = ''\n\n\n# Load the appropriate provider\nvideo_providers = []\ntry:\n    from kivy.lib.gstplayer import GstPlayer  # NOQA\n    video_providers += [('gstplayer', 'video_gstplayer', 'VideoGstplayer')]\nexcept ImportError:\n    #video_providers += [('gi', 'video_gi', 'VideoGi')]\n    if PY2:\n        # if peoples do not have gi, fallback on pygst, only for python2\n        video_providers += [\n            ('pygst', 'video_pygst', 'VideoPyGst')]\nvideo_providers += [\n    ('ffmpeg', 'video_ffmpeg', 'VideoFFMpeg'),\n    ('ffpyplayer', 'video_ffpyplayer', 'VideoFFPy'),\n    ('pyglet', 'video_pyglet', 'VideoPyglet'),\n    ('null', 'video_null', 'VideoNull')]\n\n\nVideo = core_select_lib('video', video_providers)\n"
  },
  {
    "path": "tickeys/kivy/core/video/video_ffmpeg.py",
    "content": "'''\nFFmpeg video abstraction\n========================\n\n.. versionadded:: 1.0.8\n\nThis abstraction requires ffmpeg python extensions. We have made a special\nextension that is used for the android platform but can also be used on x86\nplatforms. The project is available at::\n\n    http://github.com/tito/ffmpeg-android\n\nThe extension is designed for implementing a video player.\nRefer to the documentation of the ffmpeg-android project for more information\nabout the requirements.\n'''\n\ntry:\n    import ffmpeg\nexcept:\n    raise\n\nfrom kivy.core.video import VideoBase\nfrom kivy.graphics.texture import Texture\n\n\nclass VideoFFMpeg(VideoBase):\n\n    def __init__(self, **kwargs):\n        self._do_load = False\n        self._player = None\n        super(VideoFFMpeg, self).__init__(**kwargs)\n\n    def unload(self):\n        if self._player:\n            self._player.stop()\n            self._player = None\n        self._state = ''\n        self._do_load = False\n\n    def load(self):\n        self.unload()\n\n    def play(self):\n        if self._player:\n            self.unload()\n        self._player = ffmpeg.FFVideo(self._filename)\n        self._do_load = True\n\n    def stop(self):\n        self.unload()\n\n    def seek(self, percent):\n        if self._player is None:\n            return\n        self._player.seek(percent)\n\n    def _do_eos(self):\n        self.unload()\n        self.dispatch('on_eos')\n        super(VideoFFMpeg, self)._do_eos()\n\n    def _update(self, dt):\n        if self._do_load:\n            self._player.open()\n            self._do_load = False\n            return\n\n        player = self._player\n        if player is None:\n            return\n        if player.is_open is False:\n            self._do_eos()\n            return\n\n        frame = player.get_next_frame()\n        if frame is None:\n            return\n\n        # first time we got a frame, we know that video is readed now.\n        if self._texture is None:\n            self._texture = Texture.create(size=(\n                player.get_width(), player.get_height()),\n                colorfmt='rgb')\n            self._texture.flip_vertical()\n            self.dispatch('on_load')\n\n        if self._texture:\n            self._texture.blit_buffer(frame)\n            self.dispatch('on_frame')\n\n    def _get_duration(self):\n        if self._player is None:\n            return 0\n        return self._player.get_duration()\n\n    def _get_position(self):\n        if self._player is None:\n            return 0\n        return self._player.get_position()\n\n    def _get_volume(self):\n        if self._player is None:\n            return 0\n        self._volume = self._player.get_volume()\n        return self._volume\n\n    def _set_volume(self, volume):\n        if self._player is None:\n            return\n        self._player.set_volume(volume)\n"
  },
  {
    "path": "tickeys/kivy/core/video/video_ffpyplayer.py",
    "content": "'''\nFFmpeg based video abstraction\n==============================\n\nTo use, you need to install ffpyplyaer and have a compiled ffmpeg shared\nlibrary.\n\n    https://github.com/matham/ffpyplayer\n\nThe docs there describe how to set this up. But briefly, first you need to\ncompile ffmpeg using the shared flags while disabling the static flags (you'll\nprobably have to set the fPIC flag, e.g. CFLAGS=-fPIC). Here's some\ninstructions: https://trac.ffmpeg.org/wiki/CompilationGuide. For Windows, you\ncan download compiled GPL binaries from http://ffmpeg.zeranoe.com/builds/.\nSimilarly, you should download SDL.\n\nNow, you should a ffmpeg and sdl directory. In each, you should have a include,\nbin, and lib directory, where e.g. for Windows, lib contains the .dll.a files,\nwhile bin contains the actual dlls. The include directory holds the headers.\nThe bin directory is only needed if the shared libraries are not already on\nthe path. In the environment define FFMPEG_ROOT and SDL_ROOT, each pointing to\nthe ffmpeg, and SDL directories, respectively. (If you're using SDL2,\nthe include directory will contain a directory called SDL2, which then holds\nthe headers).\n\nOnce defined, download the ffpyplayer git and run\n\n    python setup.py build_ext --inplace\n\nFinally, before running you need to ensure that ffpyplayer is in python's path.\n\n..Note::\n\n    When kivy exits by closing the window while the video is playing,\n    it appears that the __del__method of VideoFFPy\n    is not called. Because of this the VideoFFPy object is not\n    properly deleted when kivy exits. The consequence is that because\n    MediaPlayer creates internal threads which do not have their daemon\n    flag set, when the main threads exists it'll hang and wait for the other\n    MediaPlayer threads to exit. But since __del__ is not called to delete the\n    MediaPlayer object, those threads will remain alive hanging kivy. What this\n    means is that you have to be sure to delete the MediaPlayer object before\n    kivy exits by setting it to None.\n'''\n\n__all__ = ('VideoFFPy', )\n\ntry:\n    import ffpyplayer\n    from ffpyplayer.player import MediaPlayer\n    from ffpyplayer.tools import set_log_callback, loglevels, get_log_callback\nexcept:\n    raise\n\n\nfrom threading import Thread\nfrom kivy.clock import Clock, mainthread\nfrom kivy.logger import Logger\nfrom kivy.core.video import VideoBase\nfrom kivy.graphics import Rectangle, BindTexture\nfrom kivy.graphics.texture import Texture\nfrom kivy.graphics.fbo import Fbo\nfrom kivy.weakmethod import WeakMethod\nimport time\n\nLogger.info('VideoFFPy: Using ffpyplayer {}'.format(ffpyplayer.version))\n\n\nlogger_func = {'quiet': Logger.critical, 'panic': Logger.critical,\n               'fatal': Logger.critical, 'error': Logger.error,\n               'warning': Logger.warning, 'info': Logger.info,\n               'verbose': Logger.debug, 'debug': Logger.debug}\n\n\ndef _log_callback(message, level):\n    message = message.strip()\n    if message:\n        logger_func[level]('ffpyplayer: {}'.format(message))\n\nif not get_log_callback():\n    set_log_callback(_log_callback)\n\n\nclass VideoFFPy(VideoBase):\n\n    YUV_RGB_FS = \"\"\"\n    $HEADER$\n    uniform sampler2D tex_y;\n    uniform sampler2D tex_u;\n    uniform sampler2D tex_v;\n\n    void main(void) {\n        float y = texture2D(tex_y, tex_coord0).r;\n        float u = texture2D(tex_u, tex_coord0).r - 0.5;\n        float v = texture2D(tex_v, tex_coord0).r - 0.5;\n        float r = y +             1.402 * v;\n        float g = y - 0.344 * u - 0.714 * v;\n        float b = y + 1.772 * u;\n        gl_FragColor = vec4(r, g, b, 1.0);\n    }\n    \"\"\"\n\n    def __init__(self, **kwargs):\n        self._ffplayer = None\n        self._thread = None\n        self._next_frame = None\n        self._ffplayer_need_quit = False\n        self._callback_ref = WeakMethod(self._player_callback)\n        self._trigger = Clock.create_trigger(self._redraw)\n\n        super(VideoFFPy, self).__init__(**kwargs)\n\n    def __del__(self):\n        self.unload()\n        if self._log_callback_set:\n            set_log_callback(None)\n\n    def _player_callback(self, selector, value):\n        if self._ffplayer is None:\n            return\n        if selector == 'quit':\n            def close(*args):\n                self.unload()\n            Clock.schedule_once(close, 0)\n\n    def _get_position(self):\n        if self._ffplayer is not None:\n            return self._ffplayer.get_pts()\n        return 0\n\n    def _set_position(self, pos):\n        self.seek(pos)\n\n    def _get_volume(self):\n        if self._ffplayer is not None:\n            self._volume = self._ffplayer.get_volume()\n        return self._volume\n\n    def _set_volume(self, volume):\n        self._volume = volume\n        if self._ffplayer is not None:\n            self._ffplayer.set_volume(volume)\n\n    def _get_duration(self):\n        if self._ffplayer is None:\n            return 0\n        return self._ffplayer.get_metadata()['duration']\n\n    @mainthread\n    def _do_eos(self):\n        if self.eos == 'pause':\n            self.pause()\n        elif self.eos == 'stop':\n            self.stop()\n        elif self.eos == 'loop':\n            self.position = 0\n\n        self.dispatch('on_eos')\n\n    @mainthread\n    def _change_state(self, state):\n        self._state = state\n\n    def _redraw(self, *args):\n        if not self._ffplayer:\n            return\n        next_frame = self._next_frame\n        if not next_frame:\n            return\n\n        img, pts = next_frame\n        if img.get_size() != self._size or self._texture is None:\n            self._size = w, h = img.get_size()\n\n            if self._out_fmt == 'yuv420p':\n                w2 = int(w / 2)\n                h2 = int(h / 2)\n                self._tex_y = Texture.create(\n                    size=(w, h), colorfmt='luminance')\n                self._tex_u = Texture.create(\n                    size=(w2, h2), colorfmt='luminance')\n                self._tex_v = Texture.create(\n                    size=(w2, h2), colorfmt='luminance')\n                self._fbo = fbo = Fbo(size=self._size)\n                with fbo:\n                    BindTexture(texture=self._tex_u, index=1)\n                    BindTexture(texture=self._tex_v, index=2)\n                    Rectangle(size=fbo.size, texture=self._tex_y)\n                fbo.shader.fs = VideoFFPy.YUV_RGB_FS\n                fbo['tex_y'] = 0\n                fbo['tex_u'] = 1\n                fbo['tex_v'] = 2\n                self._texture = fbo.texture\n            else:\n                self._texture = Texture.create(size=self._size, colorfmt='rgba')\n\n            # XXX FIXME\n            #self.texture.add_reload_observer(self.reload_buffer)\n            self._texture.flip_vertical()\n            self.dispatch('on_load')\n\n        if self._texture:\n            if self._out_fmt == 'yuv420p':\n                dy, du, dv, _ = img.to_memoryview()\n                self._tex_y.blit_buffer(dy, colorfmt='luminance')\n                self._tex_u.blit_buffer(du, colorfmt='luminance')\n                self._tex_v.blit_buffer(dv, colorfmt='luminance')\n            else:\n                self._texture.blit_buffer(\n                    img.to_memoryview()[0], colorfmt='rgba')\n\n            self._fbo.ask_update()\n            self._fbo.draw()\n            self.dispatch('on_frame')\n\n    def _next_frame_run(self):\n        ffplayer = self._ffplayer\n        sleep = time.sleep\n        trigger = self._trigger\n        did_dispatch_eof = False\n\n        # fast path, if the source video is yuv420p, we'll use a glsl shader for\n        # buffer conversion to rgba\n        while not self._ffplayer_need_quit:\n            src_pix_fmt = ffplayer.get_metadata().get('src_pix_fmt')\n            if not src_pix_fmt:\n                sleep(0.005)\n                continue\n\n            if src_pix_fmt == 'yuv420p':\n                self._out_fmt = 'yuv420p'\n                ffplayer.set_output_pix_fmt(self._out_fmt)\n            self._ffplayer.toggle_pause()\n            break\n\n        if self._ffplayer_need_quit:\n            return\n\n        # wait until loaded or failed, shouldn't take long, but just to make\n        # sure metadata is available.\n        s = time.clock()\n        while not self._ffplayer_need_quit:\n            if ffplayer.get_metadata()['src_vid_size'] != (0, 0):\n                break\n            # XXX if will fail later then?\n            if time.clock() - s > 10.:\n                break\n            sleep(0.005)\n\n        if self._ffplayer_need_quit:\n            return\n\n        # we got all the informations, now, get the frames :)\n        self._change_state('playing')\n\n        while not self._ffplayer_need_quit:\n            t1 = time.time()\n            frame, val = ffplayer.get_frame()\n            t2 = time.time()\n            if val == 'eof':\n                sleep(0.2)\n                if not did_dispatch_eof:\n                    self._do_eos()\n                    did_dispatch_eof = True\n            elif val == 'paused':\n                did_dispatch_eof = False\n                sleep(0.2)\n            else:\n                did_dispatch_eof = False\n                if frame:\n                    self._next_frame = frame\n                    trigger()\n                else:\n                    val = val if val else (1 / 30.)\n                sleep(val)\n\n    def seek(self, percent):\n        if self._ffplayer is None:\n            return\n        self._ffplayer.seek(percent * self._ffplayer.get_metadata()\n                            ['duration'], relative=False)\n        self._next_frame = None\n\n    def stop(self):\n        self.unload()\n\n    def pause(self):\n        if self._ffplayer and self._state != 'paused':\n            self._ffplayer.toggle_pause()\n            self._state = 'paused'\n\n    def play(self):\n        if self._ffplayer and self._state == 'paused':\n            self._ffplayer.toggle_pause()\n            self._state = 'playing'\n            return\n\n        self.load()\n        self._out_fmt = 'rgba'\n        ff_opts = {\n            'paused': True,\n            'out_fmt': self._out_fmt\n        }\n        self._ffplayer = MediaPlayer(\n                self._filename, callback=self._callback_ref,\n                thread_lib='SDL',\n                loglevel='info', ff_opts=ff_opts)\n\n        self._thread = Thread(target=self._next_frame_run, name='Next frame')\n        self._thread.daemon = True\n        self._thread.start()\n\n    def load(self):\n        self.unload()\n\n    def unload(self):\n        Clock.unschedule(self._redraw)\n        self._ffplayer_need_quit = True\n        if self._thread:\n            self._thread.join()\n            self._thread = None\n        if self._ffplayer:\n            self._ffplayer = None\n        self._next_frame = None\n        self._size = (0, 0)\n        self._state = ''\n        self._ffplayer_need_quit = False\n"
  },
  {
    "path": "tickeys/kivy/core/video/video_gi.py",
    "content": "'''\nVideo GI\n========\n\nImplementation of VideoBase with using pygi / gstreamer. Pygi is both\ncompatible with Python 2 and 3.\n'''\n\n#\n# Important notes: you must take care of glib event + python. If you connect()\n# directly an event to a python object method, the object will be ref, and will\n# be never unref.\n# To prevent memory leak, you must connect() to a func, and you might want to\n# pass the referenced object with weakref()\n#\n\nfrom gi.repository import Gst\nfrom functools import partial\nfrom os.path import realpath\nfrom threading import Lock\nfrom weakref import ref\nfrom kivy.compat import PY2\nfrom kivy.core.video import VideoBase\nfrom kivy.graphics.texture import Texture\nfrom kivy.logger import Logger\nfrom kivy.support import install_gobject_iteration\nfrom ctypes import Structure, c_void_p, c_int, string_at\nimport atexit\n\nif PY2:\n    from urllib import pathname2url\nelse:\n    from urllib.request import pathname2url\n\n# initialize the video/gi. if the older version is used, don't use video_gi.\nGst.init(None)\nversion = Gst.version()\nif version < (1, 0, 0, 0):\n    raise Exception('Cannot use video_gi, Gstreamer < 1.0 is not supported.')\nLogger.info('VideoGi: Using Gstreamer {}'.format(\n    '.'.join(['{}'.format(x) for x in Gst.version()])))\ninstall_gobject_iteration()\n\n\nclass _MapInfo(Structure):\n    _fields_ = [\n        ('memory', c_void_p),\n        ('flags', c_int),\n        ('data', c_void_p)]\n        # we don't care about the rest\n\n\ndef _gst_new_buffer(obj, appsink):\n    obj = obj()\n    if not obj:\n        return\n    with obj._buffer_lock:\n        obj._buffer = obj._appsink.emit('pull-sample')\n    return False\n\n\ndef _on_gst_message(bus, message):\n    Logger.trace('VideoGi: (bus) {}'.format(message))\n    # log all error messages\n    if message.type == Gst.MessageType.ERROR:\n        error, debug = list(map(str, message.parse_error()))\n        Logger.error('VideoGi: {}'.format(error))\n        Logger.debug('VideoGi: {}'.format(debug))\n\n\ndef _on_gst_eos(obj, *largs):\n    obj = obj()\n    if not obj:\n        return\n    obj._do_eos()\n\n\ndef _on_videogi_unref(obj):\n    if obj in VideoGi._instances:\n        VideoGi._instances.remove(obj)\n\n\nclass VideoGi(VideoBase):\n\n    _instances = []\n\n    def __init__(self, **kwargs):\n        self._buffer_lock = Lock()\n        self._buffer = None\n        self._texture = None\n        self._gst_init()\n        wk = ref(self, _on_videogi_unref)\n        VideoGi._instances.append(wk)\n        super(VideoGi, self).__init__(**kwargs)\n\n    def _gst_init(self):\n        # self._appsink will receive the buffers so we can upload them to GPU\n        self._appsink = Gst.ElementFactory.make('appsink', '')\n        self._appsink.props.caps = Gst.caps_from_string(\n            'video/x-raw,format=RGB')\n\n        self._appsink.props.async = True\n        self._appsink.props.drop = True\n        self._appsink.props.qos = True\n        self._appsink.props.emit_signals = True\n        self._appsink.connect('new-sample', partial(\n            _gst_new_buffer, ref(self)))\n\n        # playbin, takes care of all, loading, playing, etc.\n        self._playbin = Gst.ElementFactory.make('playbin', 'playbin')\n        self._playbin.props.video_sink = self._appsink\n\n        # gstreamer bus, to attach and listen to gst messages\n        self._bus = self._playbin.get_bus()\n        self._bus.add_signal_watch()\n        self._bus.connect('message', _on_gst_message)\n        self._bus.connect('message::eos', partial(\n            _on_gst_eos, ref(self)))\n\n    def _update_texture(self, sample):\n        # texture will be updated with newest buffer/frame\n\n        # read the data from the buffer memory\n        mapinfo = data = None\n        try:\n            buf = sample.get_buffer()\n            result, mapinfo = buf.map(Gst.MapFlags.READ)\n\n            # We cannot get the data out of mapinfo, using Gst 1.0.6 + Gi 3.8.0\n            # related bug report:\n            #     https://bugzilla.gnome.org/show_bug.cgi?id=678663\n            # ie: mapinfo.data is normally a char*, but here, we have an int\n            # So right now, we use ctypes instead to read the mapinfo ourself.\n            addr = mapinfo.__hash__()\n            c_mapinfo = _MapInfo.from_address(addr)\n\n            # now get the memory\n            data = string_at(c_mapinfo.data, mapinfo.size)\n        finally:\n            if mapinfo is not None:\n                buf.unmap(mapinfo)\n\n        # upload the data to the GPU\n        info = sample.get_caps().get_structure(0)\n        size = info.get_value('width'), info.get_value('height')\n\n        # texture is not allocated yet, create it first\n        if not self._texture:\n            self._texture = Texture.create(size=size, colorfmt='rgb')\n            self._texture.flip_vertical()\n            self.dispatch('on_load')\n\n        if self._texture:\n            self._texture.blit_buffer(data, size=size, colorfmt='rgb')\n\n    def _update(self, dt):\n        buf = None\n        with self._buffer_lock:\n            buf = self._buffer\n            self._buffer = None\n        if buf is not None:\n            self._update_texture(buf)\n            self.dispatch('on_frame')\n\n    def unload(self):\n        self._playbin.set_state(Gst.State.NULL)\n        self._buffer = None\n        self._texture = None\n\n    def load(self):\n        Logger.debug('VideoGi: Load <{}>'.format(self._filename))\n        self._playbin.set_state(Gst.State.NULL)\n        self._playbin.props.uri = self._get_uri()\n        self._playbin.set_state(Gst.State.READY)\n\n    def stop(self):\n        self._state = ''\n        self._playbin.set_state(Gst.State.PAUSED)\n\n    def pause(self):\n        self._state = 'paused'\n        self._playbin.set_state(Gst.State.PAUSED)\n\n    def play(self):\n        self._state = 'playing'\n        self._playbin.set_state(Gst.State.PLAYING)\n\n    def seek(self, percent):\n        seek_t = percent * self._get_duration() * 10e8\n        seek_format = Gst.Format.TIME\n        seek_flags = Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT\n        self._playbin.seek_simple(seek_format, seek_flags, seek_t)\n\n        #if pipeline is not playing, we need to pull pre-roll to update frame\n        if not self._state == 'playing':\n            with self._buffer_lock:\n                self._buffer = self._appsink.emit('pull-preroll')\n\n    def _get_uri(self):\n        uri = self.filename\n        if not uri:\n            return\n        if not '://' in uri:\n            uri = 'file:' + pathname2url(realpath(uri))\n        return uri\n\n    def _get_position(self):\n        try:\n            ret, value = self._appsink.query_position(Gst.Format.TIME)\n            if ret:\n                return value / float(Gst.SECOND)\n        except:\n            pass\n        return -1\n\n    def _get_duration(self):\n        try:\n            ret, value = self._playbin.query_duration(Gst.Format.TIME)\n            if ret:\n                return value / float(Gst.SECOND)\n        except:\n            pass\n        return -1\n\n    def _get_volume(self):\n        self._volume = self._playbin.props.volume\n        return self._volume\n\n    def _set_volume(self, volume):\n        self._playbin.props.volume = volume\n        self._volume = volume\n\n\n@atexit.register\ndef video_gi_clean():\n    # if we leave the python process with some video running, we can hit a\n    # segfault. This is forcing the stop/unload of all remaining videos before\n    # exiting the python process.\n    for weakvideo in VideoGi._instances:\n        video = weakvideo()\n        if video:\n            video.stop()\n            video.unload()\n"
  },
  {
    "path": "tickeys/kivy/core/video/video_gstplayer.py",
    "content": "'''\nVideo Gstplayer\n===============\n\n.. versionadded:: 1.8.0\n\nImplementation of a VideoBase with Kivy :class:`~kivy.lib.gstplayer.GstPlayer`\nThis player is the prefered player, using Gstreamer 1.0, working on both Python\n2 and 3.\n'''\n\nfrom kivy.lib.gstplayer import GstPlayer, get_gst_version\nfrom kivy.graphics.texture import Texture\nfrom kivy.core.video import VideoBase\nfrom kivy.logger import Logger\nfrom kivy.clock import Clock\nfrom kivy.compat import PY2\nfrom threading import Lock\nfrom functools import partial\nfrom os.path import realpath\nfrom weakref import ref\n\nif PY2:\n    from urllib import pathname2url\nelse:\n    from urllib.request import pathname2url\n\nLogger.info('VideoGstplayer: Using Gstreamer {}'.format(\n    '.'.join(map(str, get_gst_version()))))\n\n\ndef _on_gstplayer_buffer(video, width, height, data):\n    video = video()\n    # if we still receive the video but no more player, remove it.\n    if not video:\n        return\n    with video._buffer_lock:\n        video._buffer = (width, height, data)\n\n\ndef _on_gstplayer_message(mtype, message):\n    if mtype == 'error':\n        Logger.error('VideoGstplayer: {}'.format(message))\n    elif mtype == 'warning':\n        Logger.warning('VideoGstplayer: {}'.format(message))\n    elif mtype == 'info':\n        Logger.info('VideoGstplayer: {}'.format(message))\n\n\nclass VideoGstplayer(VideoBase):\n\n    def __init__(self, **kwargs):\n        self.player = None\n        self._buffer = None\n        self._buffer_lock = Lock()\n        super(VideoGstplayer, self).__init__(**kwargs)\n\n    def _on_gst_eos_sync(self):\n        Clock.schedule_once(self._do_eos, 0)\n\n    def load(self):\n        Logger.debug('VideoGstplayer: Load <{}>'.format(self._filename))\n        uri = self._get_uri()\n        wk_self = ref(self)\n        self.player_callback = partial(_on_gstplayer_buffer, wk_self)\n        self.player = GstPlayer(uri, self.player_callback,\n                                self._on_gst_eos_sync, _on_gstplayer_message)\n        self.player.load()\n\n    def unload(self):\n        if self.player:\n            self.player.unload()\n            self.player = None\n        with self._buffer_lock:\n            self._buffer = None\n        self._texture = None\n\n    def stop(self):\n        super(VideoGstplayer, self).stop()\n        self.player.stop()\n\n    def pause(self):\n        super(VideoGstplayer, self).pause()\n        self.player.pause()\n\n    def play(self):\n        super(VideoGstplayer, self).play()\n        self.player.set_volume(self.volume)\n        self.player.play()\n\n    def seek(self, percent):\n        self.player.seek(percent)\n\n    def _get_position(self):\n        return self.player.get_position()\n\n    def _get_duration(self):\n        return self.player.get_duration()\n\n    def _get_volume(self):\n        return self._volume\n\n    def _set_volume(self, value):\n        self._volume = value\n        if self.player:\n            self.player.set_volume(self._volume)\n\n    def _update(self, dt):\n        buf = None\n        with self._buffer_lock:\n            buf = self._buffer\n            self._buffer = None\n        if buf is not None:\n            self._update_texture(buf)\n            self.dispatch('on_frame')\n\n    def _update_texture(self, buf):\n        width, height, data = buf\n\n        # texture is not allocated yet, create it first\n        if not self._texture:\n            self._texture = Texture.create(size=(width, height),\n                                           colorfmt='rgb')\n            self._texture.flip_vertical()\n            self.dispatch('on_load')\n\n        if self._texture:\n            self._texture.blit_buffer(\n                data, size=(width, height), colorfmt='rgb')\n\n    def _get_uri(self):\n        uri = self.filename\n        if not uri:\n            return\n        if not '://' in uri:\n            uri = 'file:' + pathname2url(realpath(uri))\n        return uri\n"
  },
  {
    "path": "tickeys/kivy/core/video/video_null.py",
    "content": "\n'''\nVideoNull: empty implementation of VideoBase for the no provider case\n'''\n\nfrom kivy.core.video import VideoBase\n\n\nclass VideoNull(VideoBase):\n    '''VideoBase implementation when there is no provider.\n    '''\n    pass\n"
  },
  {
    "path": "tickeys/kivy/core/video/video_pyglet.py",
    "content": "\n'''\nVideoPyglet: implementation of VideoBase with Pyglet\n'''\n\nimport pyglet\n\nfrom kivy.core.video import VideoBase\n\n\n#have to set these before importing pyglet.gl\n#otherwise pyglet creates a seperate gl context and fails\n# on error checks becasue we use pygame window\npyglet.options['shadow_window'] = False\npyglet.options['debug_gl'] = False\nimport pyglet.gl\n\n\nclass FakePygletContext:\n    # another pyglet fix, because pyglet has a bugfix which is a bad hacked,\n    # it checks for context._workaround_unpack_row_length..but we're using\n    # the implicit context form pyglet or glut window\n    # this means we cant have a pyglet window provider though! if we do,\n    # this will break pyglet window context\n    _workaround_unpack_row_length = False\n\npyglet.gl.current_context = FakePygletContext()\n\n\nclass VideoPyglet(VideoBase):\n    '''VideoBase implementation using Pyglet\n    '''\n\n    def unload(self):\n        self.player = None\n        self._source = None\n        self._fbo = None\n\n    def load(self):\n        self.unload()  # make sure we unload an resources\n\n        #load media file and set size of video\n        self._source = source = pyglet.media.load(self._filename)\n        self._format = source.video_format\n        self.size = (self._format.width, self._format.height)\n\n        #load pyglet player and have it play teh video we loaded\n        self._player = None\n        self._player = pyglet.media.Player()\n        self._player.queue(source)\n        self.play()\n        self.stop()\n\n        # we have to keep track of tie ourselves..\n        # at least its the only way i can get pyglet player to restart,\n        # _player.time does not get reset when you do seek(0) for soe reason,\n        # and is read only\n        self.time = self._player.time\n\n    def _update(self, dt):\n        if self._source.duration - self.time < 0.1:  # we are at the end\n            self.seek(0)\n        if self.state == 'playing':\n            # keep track of time into video\n            self.time += dt\n            # required by pyglet video if not in pyglet window\n            self._player.dispatch_events(dt)\n        if self._player.get_texture():\n            # TODO: blit the pyglet texture to our own texture.\n            assert('TODO')\n\n    def stop(self):\n        self._player.pause()\n        super(VideoPyglet, self).stop()\n\n    def play(self):\n        self._player.play()\n        super(VideoPyglet, self).play()\n\n    def seek(self, percent):\n        t = self._source.duration * percent\n        self.time = t\n        self._player.seek(t)\n        self.stop()\n\n    def _get_position(self):\n        if self._player:\n            return self.time\n\n    def _get_duration(self):\n        if self._source:\n            return self._source.duration\n\n    def _get_volume(self):\n        if self._player:\n            return self._player.volume\n        return 0\n\n    def _set_volume(self, volume):\n        if self._player:\n            self._player.volume = volume\n            self.dispatch('on_frame')\n"
  },
  {
    "path": "tickeys/kivy/core/video/video_pygst.py",
    "content": "'''\nVideo PyGst\n===========\n\nImplementation of a VideoBase using PyGST. This module is compatible only with\nPython 2.\n'''\n\n#\n# Important notes: you must take care of glib event + python. If you connect()\n# directly an event to a python object method, the object will be ref, and will\n# be never unref.\n# To prevent memory leak, you must connect() to a func, and you might want to\n# pass the referenced object with weakref()\n#\n\nimport pygst\n\nif not hasattr(pygst, '_gst_already_checked'):\n    found = False\n    for version in ('1.0', '0.10'):\n        try:\n            pygst.require(version)\n            found = True\n            break\n\n        except:\n            continue\n\n    if found:\n        pygst._gst_already_checked = True\n    else:\n        raise Exception('Unable to find a valid Gstreamer version to use')\n\nimport gst\nfrom functools import partial\nfrom os import path\nfrom threading import Lock\nfrom urllib import pathname2url\nfrom weakref import ref\nfrom kivy.core.video import VideoBase\nfrom kivy.graphics.texture import Texture\nfrom kivy.logger import Logger\nfrom kivy.support import install_gobject_iteration\n\n\ninstall_gobject_iteration()\n\n\ndef _gst_new_buffer(obj, appsink):\n    obj = obj()\n    if not obj:\n        return\n    with obj._buffer_lock:\n        obj._buffer = obj._appsink.emit('pull-buffer')\n\n\ndef _on_gst_message(bus, message):\n    Logger.trace('VideoPyGst: (bus) %s' % str(message))\n    # log all error messages\n    if message.type == gst.MESSAGE_ERROR:\n        error, debug = list(map(str, message.parse_error()))\n        Logger.error('VideoPyGst: %s' % error)\n        Logger.debug('VideoPyGst: %s' % debug)\n\n\ndef _on_gst_eos(obj, *largs):\n    obj = obj()\n    if not obj:\n        return\n    obj._do_eos()\n\n\nclass VideoPyGst(VideoBase):\n\n    def __init__(self, **kwargs):\n        self._buffer_lock = Lock()\n        self._buffer = None\n        self._texture = None\n        self._gst_init()\n        super(VideoPyGst, self).__init__(**kwargs)\n\n    def _gst_init(self):\n        # self._appsink will receive the buffers so we can upload them to GPU\n        self._appsink = gst.element_factory_make('appsink', '')\n        self._appsink.set_property('caps', gst.Caps(\n            'video/x-raw-rgb,red_mask=(int)0xff0000,'\n            'green_mask=(int)0x00ff00,blue_mask=(int)0x0000ff'))\n\n        self._appsink.set_property('async', True)\n        self._appsink.set_property('drop', True)\n        self._appsink.set_property('qos', True)\n        self._appsink.set_property('emit-signals', True)\n        self._appsink.connect('new-buffer', partial(\n            _gst_new_buffer, ref(self)))\n\n        # playbin, takes care of all, loading, playing, etc.\n        # XXX playbin2 have some issue when playing some video or streaming :/\n        self._playbin = gst.element_factory_make('playbin', 'playbin')\n        self._playbin.set_property('video-sink', self._appsink)\n\n        # gstreamer bus, to attach and listen to gst messages\n        self._bus = self._playbin.get_bus()\n        self._bus.add_signal_watch()\n        self._bus.connect('message', _on_gst_message)\n        self._bus.connect('message::eos', partial(\n            _on_gst_eos, ref(self)))\n\n    def _update_texture(self, buf):\n        # texture will be updated with newest buffer/frame\n        size = None\n        caps = buf.get_caps()\n        _s = caps.get_structure(0)\n        size = _s['width'], _s['height']\n        if not self._texture:\n            # texture is not allocated yet, so create it first\n            self._texture = Texture.create(size=size, colorfmt='rgb')\n            self._texture.flip_vertical()\n            self.dispatch('on_load')\n\n        # upload texture data to GPU\n        if self._texture:\n            self._texture.blit_buffer(buf.data, size=size, colorfmt='rgb')\n\n    def _update(self, dt):\n        buf = None\n        with self._buffer_lock:\n            buf = self._buffer\n            self._buffer = None\n        if buf is not None:\n            self._update_texture(buf)\n            self.dispatch('on_frame')\n\n    def unload(self):\n        self._playbin.set_state(gst.STATE_NULL)\n        self._buffer = None\n        self._texture = None\n\n    def load(self):\n        Logger.debug('VideoPyGst: Load <%s>' % self._filename)\n        self._playbin.set_state(gst.STATE_NULL)\n        self._playbin.set_property('uri', self._get_uri())\n        self._playbin.set_state(gst.STATE_READY)\n\n    def stop(self):\n        '''.. versionchanged:: 1.4.0'''\n        self._state = ''\n        self._playbin.set_state(gst.STATE_PAUSED)\n\n    def pause(self):\n        '''.. versionadded:: 1.4.0'''\n        self._state = 'paused'\n        self._playbin.set_state(gst.STATE_PAUSED)\n\n    def play(self):\n        self._state = 'playing'\n        self._playbin.set_state(gst.STATE_PLAYING)\n\n    def seek(self, percent):\n        seek_t = percent * self._get_duration() * 10e8\n        seek_format = gst.FORMAT_TIME\n        seek_flags = gst.SEEK_FLAG_FLUSH | gst.SEEK_FLAG_KEY_UNIT\n        self._playbin.seek_simple(seek_format, seek_flags, seek_t)\n\n        #if pipeline is not playing, we need to pull pre-roll to update frame\n        if not self._state == 'playing':\n            with self._buffer_lock:\n                self._buffer = self._appsink.emit('pull-preroll')\n\n    def _get_uri(self):\n        uri = self.filename\n        if not uri:\n            return\n        if not '://' in uri:\n            uri = 'file:' + pathname2url(path.realpath(uri))\n        return uri\n\n    def _get_position(self):\n        try:\n            value, fmt = self._appsink.query_position(gst.FORMAT_TIME)\n            return value / 10e8\n        except:\n            return -1\n\n    def _get_duration(self):\n        try:\n            return self._playbin.query_duration(gst.FORMAT_TIME)[0] / 10e8\n        except:\n            return -1\n\n    def _get_volume(self):\n        self._volume = self._playbin.get_property('volume')\n        return self._volume\n\n    def _set_volume(self, volume):\n        self._playbin.set_property('volume', volume)\n        self._volume = volume\n"
  },
  {
    "path": "tickeys/kivy/core/window/__init__.py",
    "content": "# pylint: disable=W0611\n# coding: utf-8\n'''\nWindow\n======\n\nCore class for creating the default Kivy window. Kivy supports only one window\nper application: please don't try to create more than one.\n'''\n\n__all__ = ('Keyboard', 'WindowBase', 'Window')\n\nfrom os.path import join, exists\nfrom os import getcwd\n\nfrom kivy.core import core_select_lib\nfrom kivy.clock import Clock\nfrom kivy.config import Config\nfrom kivy.logger import Logger\nfrom kivy.base import EventLoop, stopTouchApp\nfrom kivy.modules import Modules\nfrom kivy.event import EventDispatcher\nfrom kivy.properties import ListProperty, ObjectProperty, AliasProperty, \\\n    NumericProperty, OptionProperty, StringProperty, BooleanProperty\nfrom kivy.utils import platform, reify\nfrom kivy.context import get_current_context\nfrom kivy.uix.behaviors import FocusBehavior\nfrom kivy.setupconfig import USE_SDL2\nfrom kivy.graphics.transformation import Matrix\n\n# late import\nVKeyboard = None\nandroid = None\n\n\nclass Keyboard(EventDispatcher):\n    '''Keyboard interface that is returned by\n    :meth:`WindowBase.request_keyboard`. When you request a keyboard,\n    you'll get an instance of this class. Whatever the keyboard input is\n    (system or virtual keyboard), you'll receive events through this\n    instance.\n\n    :Events:\n        `on_key_down`: keycode, text, modifiers\n            Fired when a new key is pressed down\n        `on_key_up`: keycode\n            Fired when a key is released (up)\n\n    Here is an example of how to request a Keyboard in accordance with the\n    current configuration:\n\n    .. include:: ../../examples/widgets/keyboardlistener.py\n        :literal:\n\n    '''\n\n    # Keycodes mapping, between str <-> int. Theses keycode are\n    # currently taken from pygame.key. But when a new provider will be\n    # used, it must do the translation to these keycodes too.\n    keycodes = {\n        # specials keys\n        'backspace': 8, 'tab': 9, 'enter': 13, 'rshift': 303, 'shift': 304,\n        'alt': 308, 'rctrl': 306, 'lctrl': 305,\n        'super': 309, 'alt-gr': 307, 'compose': 311, 'pipe': 310,\n        'capslock': 301, 'escape': 27, 'spacebar': 32, 'pageup': 280,\n        'pagedown': 281, 'end': 279, 'home': 278, 'left': 276, 'up':\n        273, 'right': 275, 'down': 274, 'insert': 277, 'delete': 127,\n        'numlock': 300, 'print': 144, 'screenlock': 145, 'pause': 19,\n\n        # a-z keys\n        'a': 97, 'b': 98, 'c': 99, 'd': 100, 'e': 101, 'f': 102, 'g': 103,\n        'h': 104, 'i': 105, 'j': 106, 'k': 107, 'l': 108, 'm': 109, 'n': 110,\n        'o': 111, 'p': 112, 'q': 113, 'r': 114, 's': 115, 't': 116, 'u': 117,\n        'v': 118, 'w': 119, 'x': 120, 'y': 121, 'z': 122,\n\n        # 0-9 keys\n        '0': 48, '1': 49, '2': 50, '3': 51, '4': 52,\n        '5': 53, '6': 54, '7': 55, '8': 56, '9': 57,\n\n        # numpad\n        'numpad0': 256, 'numpad1': 257, 'numpad2': 258, 'numpad3': 259,\n        'numpad4': 260, 'numpad5': 261, 'numpad6': 262, 'numpad7': 263,\n        'numpad8': 264, 'numpad9': 265, 'numpaddecimal': 266,\n        'numpaddivide': 267, 'numpadmul': 268, 'numpadsubstract': 269,\n        'numpadadd': 270, 'numpadenter': 271,\n\n        # F1-15\n        'f1': 282, 'f2': 283, 'f3': 284, 'f4': 285, 'f5': 286, 'f6': 287,\n        'f7': 288, 'f8': 289, 'f9': 290, 'f10': 291, 'f11': 292, 'f12': 293,\n        'f13': 294, 'f14': 295, 'f15': 296,\n\n        # other keys\n        '(': 40, ')': 41,\n        '[': 91, ']': 93,\n        '{': 123, '}': 125,\n        ':': 59, ';': 59,\n        '=': 61, '+': 43,\n        '-': 45, '_': 95,\n        '/': 47, '*': 42,\n        '?': 47,\n        '`': 96, '~': 126,\n        '´': 180, '¦': 166,\n        '\\\\': 92, '|': 124,\n        '\"': 34, \"'\": 39,\n        ',': 44, '.': 46,\n        '<': 60, '>': 62,\n        '@': 64, '!': 33,\n        '#': 35, '$': 36,\n        '%': 37, '^': 94,\n        '&': 38, '¬': 172,\n        '¨': 168, '…': 8230,\n        'ù': 249, 'à': 224,\n        'é': 233, 'è': 232,\n    }\n\n    __events__ = ('on_key_down', 'on_key_up', 'on_textinput')\n\n    def __init__(self, **kwargs):\n        super(Keyboard, self).__init__()\n\n        #: Window which the keyboard is attached too\n        self.window = kwargs.get('window', None)\n\n        #: Callback that will be called when the keyboard is released\n        self.callback = kwargs.get('callback', None)\n\n        #: Target that have requested the keyboard\n        self.target = kwargs.get('target', None)\n\n        #: VKeyboard widget, if allowed by the configuration\n        self.widget = kwargs.get('widget', None)\n\n    def on_key_down(self, keycode, text, modifiers):\n        pass\n\n    def on_key_up(self, keycode):\n        pass\n\n    def on_textinput(self, text):\n        pass\n\n    def release(self):\n        '''Call this method to release the current keyboard.\n        This will ensure that the keyboard is no longer attached to your\n        callback.'''\n        if self.window:\n            self.window.release_keyboard(self.target)\n\n    def _on_window_textinput(self, instance, text):\n        return self.dispatch('on_textinput', text)\n\n    def _on_window_key_down(self, instance, keycode, scancode, text,\n                            modifiers):\n        keycode = (keycode, self.keycode_to_string(keycode))\n        if text == '\\x04':\n            Window.trigger_keyboard_height()\n            return\n        return self.dispatch('on_key_down', keycode, text, modifiers)\n\n    def _on_window_key_up(self, instance, keycode, *largs):\n        keycode = (keycode, self.keycode_to_string(keycode))\n        return self.dispatch('on_key_up', keycode)\n\n    def _on_vkeyboard_key_down(self, instance, keycode, text, modifiers):\n        if keycode is None:\n            keycode = text.lower()\n        keycode = (self.string_to_keycode(keycode), keycode)\n        return self.dispatch('on_key_down', keycode, text, modifiers)\n\n    def _on_vkeyboard_key_up(self, instance, keycode, text, modifiers):\n        if keycode is None:\n            keycode = text\n        keycode = (self.string_to_keycode(keycode), keycode)\n        return self.dispatch('on_key_up', keycode)\n\n    def _on_vkeyboard_textinput(self, instance, text):\n        return self.dispatch('on_textinput', text)\n\n    def string_to_keycode(self, value):\n        '''Convert a string to a keycode number according to the\n        :attr:`Keyboard.keycodes`. If the value is not found in the\n        keycodes, it will return -1.\n        '''\n        return Keyboard.keycodes.get(value, -1)\n\n    def keycode_to_string(self, value):\n        '''Convert a keycode number to a string according to the\n        :attr:`Keyboard.keycodes`. If the value is not found in the\n        keycodes, it will return ''.\n        '''\n        keycodes = list(Keyboard.keycodes.values())\n        if value in keycodes:\n            return list(Keyboard.keycodes.keys())[keycodes.index(value)]\n        return ''\n\n\nclass WindowBase(EventDispatcher):\n    '''WindowBase is an abstract window widget for any window implementation.\n\n    :Parameters:\n        `borderless`: str, one of ('0', '1')\n            Set the window border state. Check the\n            :mod:`~kivy.config` documentation for a\n            more detailed explanation on the values.\n        `fullscreen`: str, one of ('0', '1', 'auto', 'fake')\n            Make the window fullscreen. Check the\n            :mod:`~kivy.config` documentation for a\n            more detailed explanation on the values.\n        `width`: int\n            Width of the window.\n        `height`: int\n            Height of the window.\n\n    :Events:\n        `on_motion`: etype, motionevent\n            Fired when a new :class:`~kivy.input.motionevent.MotionEvent` is\n            dispatched\n        `on_touch_down`:\n            Fired when a new touch event is initiated.\n        `on_touch_move`:\n            Fired when an existing touch event changes location.\n        `on_touch_up`:\n            Fired when an existing touch event is terminated.\n        `on_draw`:\n            Fired when the :class:`Window` is being drawn.\n        `on_flip`:\n            Fired when the :class:`Window` GL surface is being flipped.\n        `on_rotate`: rotation\n            Fired when the :class:`Window` is being rotated.\n        `on_close`:\n            Fired when the :class:`Window` is closed.\n        `on_request_close`:\n            Fired when the event loop wants to close the window, or if the\n            escape key is pressed and `exit_on_escape` is `True`. If a function\n            bound to this event returns `True`, the window will not be closed.\n            If the the event is triggered because of the keyboard escape key,\n            the keyword argument `source` is dispatched along with a value of\n            `keyboard` to the bound functions.\n\n            .. versionadded:: 1.9.0\n\n        `on_keyboard`: key, scancode, codepoint, modifier\n            Fired when the keyboard is used for input.\n\n            .. versionchanged:: 1.3.0\n                The *unicode* parameter has been deprecated in favor of\n                codepoint, and will be removed completely in future versions.\n\n        `on_key_down`: key, scancode, codepoint\n            Fired when a key pressed.\n\n            .. versionchanged:: 1.3.0\n                The *unicode* parameter has been deprecated in favor of\n                codepoint, and will be removed completely in future versions.\n\n        `on_key_up`: key, scancode, codepoint\n            Fired when a key is released.\n\n            .. versionchanged:: 1.3.0\n                The *unicode* parameter has be deprecated in favor of\n                codepoint, and will be removed completely in future versions.\n\n        `on_dropfile`: str\n            Fired when a file is dropped on the application.\n\n    '''\n\n    __instance = None\n    __initialized = False\n    _fake_fullscreen = False\n    _density = 1\n\n    # private properties\n    _size = ListProperty([0, 0])\n    _modifiers = ListProperty([])\n    _rotation = NumericProperty(0)\n    _clearcolor = ObjectProperty([0, 0, 0, 1])\n\n    children = ListProperty([])\n    '''List of the children of this window.\n\n    :attr:`children` is a :class:`~kivy.properties.ListProperty` instance and\n    defaults to an empty list.\n\n    Use :meth:`add_widget` and :meth:`remove_widget` to manipulate the list of\n    children. Don't manipulate the list directly unless you know what you are\n    doing.\n    '''\n\n    parent = ObjectProperty(None, allownone=True)\n    '''Parent of this window.\n\n    :attr:`parent` is a :class:`~kivy.properties.ObjectProperty` instance and\n    defaults to None. When created, the parent is set to the window itself.\n    You must take care of it if you are doing a recursive check.\n    '''\n\n    icon = StringProperty()\n\n    def _get_modifiers(self):\n        return self._modifiers\n\n    modifiers = AliasProperty(_get_modifiers, None)\n    '''List of keyboard modifiers currently active.\n    '''\n\n    def _get_size(self):\n        r = self._rotation\n        w, h = self._size\n        if self._density != 1:\n            w, h = self._win._get_gl_size()\n        if self.softinput_mode == 'resize':\n            h -= self.keyboard_height\n        if r in (0, 180):\n            return w, h\n        return h, w\n\n    def _set_size(self, size):\n        if self._size != size:\n            r = self._rotation\n            if r in (0, 180):\n                self._size = size\n            else:\n                self._size = size[1], size[0]\n\n            self.dispatch('on_resize', *size)\n            return True\n        else:\n            return False\n\n    size = AliasProperty(_get_size, _set_size, bind=('_size', ))\n    '''Get the rotated size of the window. If :attr:`rotation` is set, then the\n    size will change to reflect the rotation.\n    '''\n\n    def _get_clearcolor(self):\n        return self._clearcolor\n\n    def _set_clearcolor(self, value):\n        if value is not None:\n            if type(value) not in (list, tuple):\n                raise Exception('Clearcolor must be a list or tuple')\n            if len(value) != 4:\n                raise Exception('Clearcolor must contain 4 values')\n        self._clearcolor = value\n\n    clearcolor = AliasProperty(_get_clearcolor, _set_clearcolor,\n                               bind=('_clearcolor', ))\n    '''Color used to clear the window.\n\n    ::\n\n        from kivy.core.window import Window\n\n        # red background color\n        Window.clearcolor = (1, 0, 0, 1)\n\n        # don't clear background at all\n        Window.clearcolor = None\n\n    .. versionchanged:: 1.7.2\n        The clearcolor default value is now: (0, 0, 0, 1).\n\n    '''\n\n    # make some property read-only\n    def _get_width(self):\n        _size = self._size\n        if self._density != 1:\n            _size = self._win._get_gl_size()\n        r = self._rotation\n        if r == 0 or r == 180:\n            return _size[0]\n        return _size[1]\n\n    width = AliasProperty(_get_width, None, bind=('_rotation', '_size'))\n    '''Rotated window width.\n\n    :attr:`width` is a read-only :class:`~kivy.properties.AliasProperty`.\n    '''\n\n    def _get_height(self):\n        '''Rotated window height'''\n        r = self._rotation\n        _size = self._size\n        if self._density != 1:\n            _size = self._win._get_gl_size()\n        kb = self.keyboard_height if self.softinput_mode == 'resize' else 0\n        if r == 0 or r == 180:\n            return _size[1] - kb\n        return _size[0] - kb\n\n    height = AliasProperty(_get_height, None, bind=('_rotation', '_size'))\n    '''Rotated window height.\n\n    :attr:`height` is a read-only :class:`~kivy.properties.AliasProperty`.\n    '''\n\n    def _get_center(self):\n        return self.width / 2., self.height / 2.\n\n    center = AliasProperty(_get_center, None, bind=('width', 'height'))\n    '''Center of the rotated window.\n\n    :attr:`center` is a :class:`~kivy.properties.AliasProperty`.\n    '''\n\n    def _get_rotation(self):\n        return self._rotation\n\n    def _set_rotation(self, x):\n        x = int(x % 360)\n        if x == self._rotation:\n            return\n        if x not in (0, 90, 180, 270):\n            raise ValueError('can rotate only 0, 90, 180, 270 degrees')\n        self._rotation = x\n        if self.initialized is False:\n            return\n        self.dispatch('on_resize', *self.size)\n        self.dispatch('on_rotate', x)\n\n    rotation = AliasProperty(_get_rotation, _set_rotation,\n                             bind=('_rotation', ))\n    '''Get/set the window content rotation. Can be one of 0, 90, 180, 270\n    degrees.\n    '''\n\n    softinput_mode = OptionProperty('', options=('', 'pan', 'scale', 'resize'))\n    '''This specifies the behavior of window contents on display of soft\n    keyboard on mobile platform. Can be one of '', 'pan', 'scale', 'resize'.\n\n    When '' The main window is left as it is allowing the user to use\n    :attr:`keyboard_height` to manage the window contents the way they want.\n\n    when 'pan' The main window pans moving the bottom part of the window to be\n    always on top of the keyboard.\n\n    when 'resize' The window is resized and the contents scaled to fit the\n    remaining space.\n\n    ..versionadded::1.9.0\n\n    :attr:`softinput_mode` is a :class:`OptionProperty` defaults to None.\n\n    '''\n\n    _keyboard_changed = BooleanProperty(False)\n\n    def _upd_kbd_height(self, *kargs):\n        self._keyboard_changed = not self._keyboard_changed\n\n    def _get_ios_kheight(self):\n        return 0\n\n    def _get_android_kheight(self):\n        global android\n        if not android:\n            import android\n        return android.get_keyboard_height()\n\n    def _get_kheight(self):\n        if platform == 'android':\n            return self._get_android_kheight()\n        if platform == 'ios':\n            return self._get_ios_kheight()\n        return 0\n\n    keyboard_height = AliasProperty(_get_kheight, None,\n                                    bind=('_keyboard_changed',))\n    '''Rerturns the height of the softkeyboard/IME on mobile platforms.\n    Will return 0 if not on mobile platform or if IME is not active.\n\n    ..versionadded:: 1.9.0\n\n    :attr:`keyboard_height` is a read-only :class:`AliasProperty` defaults to 0.\n    '''\n\n    def _set_system_size(self, size):\n        self._size = size\n\n    def _get_system_size(self):\n        if self.softinput_mode == 'resize':\n            return self._size[0], self._size[1] - self.keyboard_height\n        return self._size\n\n    system_size = AliasProperty(\n        _get_system_size,\n        _set_system_size,\n        bind=('_size', ))\n    '''Real size of the window ignoring rotation.\n    '''\n\n    borderless = BooleanProperty(False)\n    '''When set to True, this property removes the window border/decoration.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`borderless` is a :class:`BooleanProperty`, defaults to False.\n    '''\n\n    fullscreen = OptionProperty(False, options=(True, False, 'auto', 'fake'))\n    '''This property sets the fullscreen mode of the window. Available options\n    are: True, False, 'auto', 'fake'. Check the :mod:`~kivy.config`\n    documentation for a more detailed explanation on the values.\n\n    .. versionadded:: 1.2.0\n\n    .. note::\n        The 'fake' option has been deprecated, use the :attr:`borderless`\n        property instead.\n    '''\n\n    mouse_pos = ObjectProperty([0, 0])\n    '''2d position of the mouse within the window.\n\n    .. versionadded:: 1.2.0\n    '''\n\n    @property\n    def __self__(self):\n        return self\n\n    top = NumericProperty(None, allownone=True)\n    left = NumericProperty(None, allownone=True)\n    position = OptionProperty('auto', options=['auto', 'custom'])\n    render_context = ObjectProperty(None)\n    canvas = ObjectProperty(None)\n    title = StringProperty('Kivy')\n\n    __events__ = (\n        'on_draw', 'on_flip', 'on_rotate', 'on_resize', 'on_close',\n        'on_motion', 'on_touch_down', 'on_touch_move', 'on_touch_up',\n        'on_mouse_down', 'on_mouse_move', 'on_mouse_up', 'on_keyboard',\n        'on_key_down', 'on_key_up', 'on_textinput', 'on_dropfile',\n        'on_request_close', 'on_joy_axis', 'on_joy_hat', 'on_joy_ball',\n        'on_joy_button_down', \"on_joy_button_up\")\n\n    def __new__(cls, **kwargs):\n        if cls.__instance is None:\n            cls.__instance = EventDispatcher.__new__(cls)\n        return cls.__instance\n\n    def __init__(self, **kwargs):\n\n        force = kwargs.pop('force', False)\n\n        # don't init window 2 times,\n        # except if force is specified\n        if WindowBase.__instance is not None and not force:\n            return\n\n        self.initialized = False\n        self._is_desktop = Config.getboolean('kivy', 'desktop')\n\n        # create a trigger for update/create the window when one of window\n        # property changes\n        self.trigger_create_window = Clock.create_trigger(\n            self.create_window, -1)\n\n        # Create a trigger for updating the keyboard height\n        self.trigger_keyboard_height = Clock.create_trigger(\n            self._upd_kbd_height, .5)\n\n        # set the default window parameter according to the configuration\n        if 'borderless' not in kwargs:\n            kwargs['borderless'] = Config.getboolean('graphics', 'borderless')\n        if 'fullscreen' not in kwargs:\n            fullscreen = Config.get('graphics', 'fullscreen')\n            if fullscreen not in ('auto', 'fake'):\n                fullscreen = fullscreen.lower() in ('true', '1', 'yes', 'yup')\n            kwargs['fullscreen'] = fullscreen\n        if 'width' not in kwargs:\n            kwargs['width'] = Config.getint('graphics', 'width')\n        if 'height' not in kwargs:\n            kwargs['height'] = Config.getint('graphics', 'height')\n        if 'rotation' not in kwargs:\n            kwargs['rotation'] = Config.getint('graphics', 'rotation')\n        if 'position' not in kwargs:\n            kwargs['position'] = Config.getdefault('graphics', 'position',\n                                                   'auto')\n        if 'top' in kwargs:\n            kwargs['position'] = 'custom'\n            kwargs['top'] = kwargs['top']\n        else:\n            kwargs['top'] = Config.getint('graphics', 'top')\n        if 'left' in kwargs:\n            kwargs['position'] = 'custom'\n            kwargs['left'] = kwargs['left']\n        else:\n            kwargs['left'] = Config.getint('graphics', 'left')\n        kwargs['_size'] = (kwargs.pop('width'), kwargs.pop('height'))\n\n        super(WindowBase, self).__init__(**kwargs)\n\n        # bind all the properties that need to recreate the window\n        self._bind_create_window()\n        self.bind(size=self.trigger_keyboard_height,\n                  rotation=self.trigger_keyboard_height)\n\n        self.bind(softinput_mode=lambda *dt: self.update_viewport(),\n                  keyboard_height=lambda *dt: self.update_viewport())\n\n        # init privates\n        self._system_keyboard = Keyboard(window=self)\n        self._keyboards = {'system': self._system_keyboard}\n        self._vkeyboard_cls = None\n\n        self.children = []\n        self.parent = self\n\n        # before creating the window\n        import kivy.core.gl  # NOQA\n\n        # configure the window\n        self.create_window()\n\n        # attach modules + listener event\n        EventLoop.set_window(self)\n        Modules.register_window(self)\n        EventLoop.add_event_listener(self)\n\n        # manage keyboard(s)\n        self.configure_keyboards()\n\n        # assign the default context of the widget creation\n        if not hasattr(self, '_context'):\n            self._context = get_current_context()\n\n        # mark as initialized\n        self.initialized = True\n\n    def _bind_create_window(self):\n        for prop in (\n                'fullscreen', 'borderless', 'position', 'top',\n                'left', '_size', 'system_size'):\n            self.bind(**{prop: self.trigger_create_window})\n\n    def _unbind_create_window(self):\n        for prop in (\n                'fullscreen', 'borderless', 'position', 'top',\n                'left', '_size', 'system_size'):\n            self.unbind(**{prop: self.trigger_create_window})\n\n    def toggle_fullscreen(self):\n        '''Toggle between fullscreen and windowed mode.\n\n        .. deprecated:: 1.9.0\n            Use :attr:`fullscreen` instead.\n        '''\n        pass\n\n    def maximize(self):\n        '''Maximizes the window. This method should be used on desktop\n        platforms only.\n\n        .. versionadded:: 1.9.0\n\n        .. note::\n            This feature works with the SDL2 window provider only.\n\n        .. warning::\n            This code is still experimental, and its API may be subject to\n            change in a future version.\n        '''\n        Logger.warning('Window: maximize() is not implemented in the current '\n                        'window provider.')\n\n    def minimize(self):\n        '''Minimizes the window. This method should be used on desktop\n        platforms only.\n\n        .. versionadded:: 1.9.0\n\n        .. note::\n            This feature works with the SDL2 window provider only.\n\n        .. warning::\n            This code is still experimental, and its API may be subject to\n            change in a future version.\n        '''\n        Logger.warning('Window: minimize() is not implemented in the current '\n                        'window provider.')\n\n    def restore(self):\n        '''Restores the size and position of a maximized or minimized window.\n        This method should be used on desktop platforms only.\n\n        .. versionadded:: 1.9.0\n\n        .. note::\n            This feature works with the SDL2 window provider only.\n\n        .. warning::\n            This code is still experimental, and its API may be subject to\n            change in a future version.\n        '''\n        Logger.warning('Window: restore() is not implemented in the current '\n                        'window provider.')\n\n    def hide(self):\n        '''Hides the window. This method should be used on desktop\n        platforms only.\n\n        .. versionadded:: 1.9.0\n\n        .. note::\n            This feature works with the SDL2 window provider only.\n\n        .. warning::\n            This code is still experimental, and its API may be subject to\n            change in a future version.\n        '''\n        Logger.warning('Window: hide() is not implemented in the current '\n                        'window provider.')\n\n    def show(self):\n        '''Shows the window. This method should be used on desktop\n        platforms only.\n\n        .. versionadded:: 1.9.0\n\n        .. note::\n            This feature works with the SDL2 window provider only.\n\n        .. warning::\n            This code is still experimental, and its API may be subject to\n            change in a future version.\n        '''\n        Logger.warning('Window: show() is not implemented in the current '\n                        'window provider.')\n\n    def close(self):\n        '''Close the window'''\n        pass\n\n    def create_window(self, *largs):\n        '''Will create the main window and configure it.\n\n        .. warning::\n            This method is called automatically at runtime. If you call it, it\n            will recreate a RenderContext and Canvas. This means you'll have a\n            new graphics tree, and the old one will be unusable.\n\n            This method exist to permit the creation of a new OpenGL context\n            AFTER closing the first one. (Like using runTouchApp() and\n            stopTouchApp()).\n\n            This method has only been tested in a unittest environment and\n            is not suitable for Applications.\n\n            Again, don't use this method unless you know exactly what you are\n            doing!\n        '''\n        # just to be sure, if the trigger is set, and if this method is\n        # manually called, unset the trigger\n        Clock.unschedule(self.create_window)\n\n        # ensure the window creation will not be called twice\n        if platform in ('android', 'ios'):\n            self._unbind_create_window()\n\n        if not self.initialized:\n            from kivy.core.gl import init_gl\n            init_gl()\n\n            # create the render context and canvas, only the first time.\n            from kivy.graphics import RenderContext, Canvas\n            self.render_context = RenderContext()\n            self.canvas = Canvas()\n            self.render_context.add(self.canvas)\n\n        else:\n            # if we get initialized more than once, then reload opengl state\n            # after the second time.\n            # XXX check how it's working on embed platform.\n            if platform == 'linux' or Window.__class__.__name__ == 'WindowSDL':\n                # on linux, it's safe for just sending a resize.\n                self.dispatch('on_resize', *self.system_size)\n\n            else:\n                # on other platform, window are recreated, we need to reload.\n                from kivy.graphics.context import get_context\n                get_context().reload()\n                Clock.schedule_once(lambda x: self.canvas.ask_update(), 0)\n                self.dispatch('on_resize', *self.system_size)\n\n        # ensure the gl viewport is correct\n        self.update_viewport()\n\n    def on_flip(self):\n        '''Flip between buffers (event)'''\n        self.flip()\n\n    def flip(self):\n        '''Flip between buffers'''\n        pass\n\n    def _update_childsize(self, instance, value):\n        self.update_childsize([instance])\n\n    def add_widget(self, widget, canvas=None):\n        '''Add a widget to a window'''\n        widget.parent = self\n        self.children.insert(0, widget)\n        canvas = self.canvas.before if canvas == 'before' else \\\n            self.canvas.after if canvas == 'after' else self.canvas\n        canvas.add(widget.canvas)\n        self.update_childsize([widget])\n        widget.bind(\n            pos_hint=self._update_childsize,\n            size_hint=self._update_childsize,\n            size=self._update_childsize,\n            pos=self._update_childsize)\n\n    def remove_widget(self, widget):\n        '''Remove a widget from a window\n        '''\n        if not widget in self.children:\n            return\n        self.children.remove(widget)\n        if widget.canvas in self.canvas.children:\n            self.canvas.remove(widget.canvas)\n        elif widget.canvas in self.canvas.after.children:\n            self.canvas.after.remove(widget.canvas)\n        elif widget.canvas in self.canvas.before.children:\n            self.canvas.before.remove(widget.canvas)\n        widget.parent = None\n        widget.unbind(\n            pos_hint=self._update_childsize,\n            size_hint=self._update_childsize,\n            size=self._update_childsize,\n            pos=self._update_childsize)\n\n    def clear(self):\n        '''Clear the window with the background color'''\n        # XXX FIXME use late binding\n        from kivy.graphics.opengl import glClearColor, glClear, \\\n            GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT\n        cc = self._clearcolor\n        if cc is not None:\n            glClearColor(*cc)\n            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |\n                    GL_STENCIL_BUFFER_BIT)\n\n    def set_title(self, title):\n        '''Set the window title.\n\n        .. versionadded:: 1.0.5\n        '''\n        self.title = title\n\n    def set_icon(self, filename):\n        '''Set the icon of the window.\n\n        .. versionadded:: 1.0.5\n        '''\n        self.icon = filename\n\n    def to_widget(self, x, y, initial=True, relative=False):\n        return (x, y)\n\n    def to_window(self, x, y, initial=True, relative=False):\n        return (x, y)\n\n    def _apply_transform(self, m):\n        return m\n\n    def get_window_matrix(self, x=0, y=0):\n        m = Matrix()\n        m.translate(x, y, 0)\n        return m\n\n    def get_root_window(self):\n        return self\n\n    def get_parent_window(self):\n        return self\n\n    def get_parent_layout(self):\n        return None\n\n    def on_draw(self):\n        self.clear()\n        self.render_context.draw()\n\n    def on_motion(self, etype, me):\n        '''Event called when a Motion Event is received.\n\n        :Parameters:\n            `etype`: str\n                One of 'begin', 'update', 'end'\n            `me`: :class:`~kivy.input.motionevent.MotionEvent`\n                The Motion Event currently dispatched.\n        '''\n        if me.is_touch:\n            w, h = self.system_size\n            if platform == 'ios':\n                w, h = self.size\n            me.scale_for_screen(w, h, rotation=self._rotation,\n                                smode=self.softinput_mode,\n                                kheight=self.keyboard_height)\n            if etype == 'begin':\n                self.dispatch('on_touch_down', me)\n            elif etype == 'update':\n                self.dispatch('on_touch_move', me)\n            elif etype == 'end':\n                self.dispatch('on_touch_up', me)\n                FocusBehavior._handle_post_on_touch_up(me)\n\n    def on_touch_down(self, touch):\n        '''Event called when a touch down event is initiated.\n\n        .. versionchanged:: 1.9.0\n            The touch `pos` is now transformed to window coordinates before\n            this method is called. Before, the touch `pos` coordinate would be\n            `(0, 0)` when this method was called.\n        '''\n        for w in self.children[:]:\n            if w.dispatch('on_touch_down', touch):\n                return True\n\n    def on_touch_move(self, touch):\n        '''Event called when a touch event moves (changes location).\n\n        .. versionchanged:: 1.9.0\n            The touch `pos` is now transformed to window coordinates before\n            this method is called. Before, the touch `pos` coordinate would be\n            `(0, 0)` when this method was called.\n        '''\n        for w in self.children[:]:\n            if w.dispatch('on_touch_move', touch):\n                return True\n\n    def on_touch_up(self, touch):\n        '''Event called when a touch event is released (terminated).\n\n        .. versionchanged:: 1.9.0\n            The touch `pos` is now transformed to window coordinates before\n            this method is called. Before, the touch `pos` coordinate would be\n            `(0, 0)` when this method was called.\n        '''\n        for w in self.children[:]:\n            if w.dispatch('on_touch_up', touch):\n                return True\n\n    def on_resize(self, width, height):\n        '''Event called when the window is resized.'''\n        self.update_viewport()\n\n    def update_viewport(self):\n        from kivy.graphics.opengl import glViewport\n        from kivy.graphics.transformation import Matrix\n        from math import radians\n\n        w, h = self.system_size\n        if self._density != 1:\n            w, h = self.size\n\n        smode = self.softinput_mode\n        kheight = self.keyboard_height\n\n        w2, h2 = w / 2., h / 2.\n        r = radians(self.rotation)\n\n        x, y = 0, 0\n        _h = h\n        if smode:\n            y = kheight\n        if smode == 'scale':\n            _h -= kheight\n\n        # prepare the viewport\n        glViewport(x, y, w, _h)\n\n        # do projection matrix\n        projection_mat = Matrix()\n        projection_mat.view_clip(0.0, w, 0.0, h, -1.0, 1.0, 0)\n        self.render_context['projection_mat'] = projection_mat\n\n        # do modelview matrix\n        modelview_mat = Matrix().translate(w2, h2, 0)\n        modelview_mat = modelview_mat.multiply(Matrix().rotate(r, 0, 0, 1))\n\n        w, h = self.size\n        w2, h2 = w / 2., h / 2.\n        modelview_mat = modelview_mat.multiply(Matrix().translate(-w2, -h2, 0))\n        self.render_context['modelview_mat'] = modelview_mat\n\n        # redraw canvas\n        self.canvas.ask_update()\n\n        # and update childs\n        self.update_childsize()\n\n    def update_childsize(self, childs=None):\n        width, height = self.size\n        if childs is None:\n            childs = self.children\n        for w in childs:\n            shw, shh = w.size_hint\n            if shw and shh:\n                w.size = shw * width, shh * height\n            elif shw:\n                w.width = shw * width\n            elif shh:\n                w.height = shh * height\n            for key, value in w.pos_hint.items():\n                if key == 'x':\n                    w.x = value * width\n                elif key == 'right':\n                    w.right = value * width\n                elif key == 'y':\n                    w.y = value * height\n                elif key == 'top':\n                    w.top = value * height\n                elif key == 'center_x':\n                    w.center_x = value * width\n                elif key == 'center_y':\n                    w.center_y = value * height\n\n    def screenshot(self, name='screenshot{:04d}.png'):\n        '''Save the actual displayed image in a file\n        '''\n        i = 0\n        path = None\n        if name != 'screenshot{:04d}.png':\n            _ext = name.split('.')[-1]\n            name = ''.join((name[:-(len(_ext) + 1)], '{:04d}.', _ext))\n        while True:\n            i += 1\n            path = join(getcwd(), name.format(i))\n            if not exists(path):\n                break\n        return path\n\n    def on_rotate(self, rotation):\n        '''Event called when the screen has been rotated.\n        '''\n        pass\n\n    def on_close(self, *largs):\n        '''Event called when the window is closed'''\n        Modules.unregister_window(self)\n        EventLoop.remove_event_listener(self)\n\n    def on_request_close(self, *largs, **kwargs):\n        '''Event called before we close the window. If a bound function returns\n        `True`, the window will not be closed. If the the event is triggered\n        because of the keyboard escape key, the keyword argument `source` is\n        dispatched along with a value of `keyboard` to the bound functions.\n\n        .. warning::\n            When the bound function returns True the window will not be closed,\n            so use with care because the user would not be able to close the\n            program, even if the red X is clicked.\n        '''\n        pass\n\n    def on_mouse_down(self, x, y, button, modifiers):\n        '''Event called when the mouse is used (pressed/released)'''\n        pass\n\n    def on_mouse_move(self, x, y, modifiers):\n        '''Event called when the mouse is moved with buttons pressed'''\n        pass\n\n    def on_mouse_up(self, x, y, button, modifiers):\n        '''Event called when the mouse is moved with buttons pressed'''\n        pass\n\n    def on_joy_axis(self, stickid, axisid, value):\n        '''Event called when a joystick has a stick or other axis moved\n\n        .. versionadded:: 1.9.0'''\n        pass\n\n    def on_joy_hat(self, stickid, hatid, value):\n        '''Event called when a joystick has a hat/dpad moved\n\n        .. versionadded:: 1.9.0'''\n        pass\n\n    def on_joy_ball(self, stickid, ballid, value):\n        '''Event called when a joystick has a ball moved\n\n        .. versionadded:: 1.9.0'''\n        pass\n\n    def on_joy_button_down(self, stickid, buttonid):\n        '''Event called when a joystick has a button pressed\n\n        .. versionadded:: 1.9.0'''\n        pass\n\n    def on_joy_button_up(self, stickid, buttonid):\n        '''Event called when a joystick has a button released\n\n        .. versionadded:: 1.9.0'''\n        pass\n\n    def on_keyboard(self, key, scancode=None, codepoint=None,\n                    modifier=None, **kwargs):\n        '''Event called when keyboard is used.\n\n        .. warning::\n            Some providers may omit `scancode`, `codepoint` and/or `modifier`!\n        '''\n        if 'unicode' in kwargs:\n            Logger.warning(\"The use of the unicode parameter is deprecated, \"\n                           \"and will be removed in future versions. Use \"\n                           \"codepoint instead, which has identical \"\n                           \"semantics.\")\n\n        # Quit if user presses ESC or the typical OSX shortcuts CMD+q or CMD+w\n        # TODO If just CMD+w is pressed, only the window should be closed.\n        is_osx = platform == 'darwin'\n        if WindowBase.on_keyboard.exit_on_escape:\n            if key == 27 or all([is_osx, key in [113, 119], modifier == 1024]):\n                if not self.dispatch('on_request_close', source='keyboard'):\n                    stopTouchApp()\n                    self.close()\n                    return True\n\n    if Config:\n        on_keyboard.exit_on_escape = Config.getboolean('kivy', 'exit_on_escape')\n\n        def __exit(section, name, value):\n            WindowBase.__dict__['on_keyboard'].exit_on_escape = \\\n                Config.getboolean('kivy', 'exit_on_escape')\n\n        Config.add_callback(__exit, 'kivy', 'exit_on_escape')\n\n    def on_key_down(self, key, scancode=None, codepoint=None,\n                    modifier=None, **kwargs):\n        '''Event called when a key is down (same arguments as on_keyboard)'''\n        if 'unicode' in kwargs:\n            Logger.warning(\"The use of the unicode parameter is deprecated, \"\n                           \"and will be removed in future versions. Use \"\n                           \"codepoint instead, which has identical \"\n                           \"semantics.\")\n\n    def on_key_up(self, key, scancode=None, codepoint=None,\n                  modifier=None, **kwargs):\n        '''Event called when a key is released (same arguments as on_keyboard)\n        '''\n        if 'unicode' in kwargs:\n            Logger.warning(\"The use of the unicode parameter is deprecated, \"\n                           \"and will be removed in future versions. Use \"\n                           \"codepoint instead, which has identical \"\n                           \"semantics.\")\n\n    def on_textinput(self, text):\n        '''Event called whem text: i.e. alpha numeric non control keys or set\n        of keys is entered. As it is not gaurenteed whether we get one\n        character or multiple ones, this event supports handling multiple\n        characters.\n\n        ..versionadded:: 1.9.0\n        '''\n        pass\n\n    def on_dropfile(self, filename):\n        '''Event called when a file is dropped on the application.\n\n        .. warning::\n\n            This event currently works with sdl2 window provider, on pygame\n            window provider and MacOSX with a patched version of pygame.\n            This event is left in place for further evolution\n            (ios, android etc.)\n\n        .. versionadded:: 1.2.0\n        '''\n        pass\n\n    @reify\n    def dpi(self):\n        '''Return the DPI of the screen. If the implementation doesn't support\n        any DPI lookup, it will just return 96.\n\n        .. warning::\n\n            This value is not cross-platform. Use\n            :attr:`kivy.base.EventLoop.dpi` instead.\n        '''\n        return 96.\n\n    def configure_keyboards(self):\n        # Configure how to provide keyboards (virtual or not)\n\n        # register system keyboard to listening keys from window\n        sk = self._system_keyboard\n        self.bind(\n            on_key_down=sk._on_window_key_down,\n            on_key_up=sk._on_window_key_up,\n            on_textinput=sk._on_window_textinput)\n\n        # use the device's real keyboard\n        self.use_syskeyboard = True\n\n        # use the device's real keyboard\n        self.allow_vkeyboard = False\n\n        # one single vkeyboard shared between all widgets\n        self.single_vkeyboard = True\n\n        # the single vkeyboard is always sitting at the same position\n        self.docked_vkeyboard = False\n\n        # now read the configuration\n        mode = Config.get('kivy', 'keyboard_mode')\n        if mode not in ('', 'system', 'dock', 'multi', 'systemanddock',\n                        'systemandmulti'):\n            Logger.critical('Window: unknown keyboard mode %r' % mode)\n\n        # adapt mode according to the configuration\n        if mode == 'system':\n            self.use_syskeyboard = True\n            self.allow_vkeyboard = False\n            self.single_vkeyboard = True\n            self.docked_vkeyboard = False\n        elif mode == 'dock':\n            self.use_syskeyboard = False\n            self.allow_vkeyboard = True\n            self.single_vkeyboard = True\n            self.docked_vkeyboard = True\n        elif mode == 'multi':\n            self.use_syskeyboard = False\n            self.allow_vkeyboard = True\n            self.single_vkeyboard = False\n            self.docked_vkeyboard = False\n        elif mode == 'systemanddock':\n            self.use_syskeyboard = True\n            self.allow_vkeyboard = True\n            self.single_vkeyboard = True\n            self.docked_vkeyboard = True\n        elif mode == 'systemandmulti':\n            self.use_syskeyboard = True\n            self.allow_vkeyboard = True\n            self.single_vkeyboard = False\n            self.docked_vkeyboard = False\n\n        Logger.info(\n            'Window: virtual keyboard %sallowed, %s, %s' % (\n                '' if self.allow_vkeyboard else 'not ',\n                'single mode' if self.single_vkeyboard else 'multiuser mode',\n                'docked' if self.docked_vkeyboard else 'not docked'))\n\n    def set_vkeyboard_class(self, cls):\n        '''.. versionadded:: 1.0.8\n\n        Set the VKeyboard class to use. If set to None, it will use the\n        :class:`kivy.uix.vkeyboard.VKeyboard`.\n        '''\n        self._vkeyboard_cls = cls\n\n    def release_all_keyboards(self):\n        '''.. versionadded:: 1.0.8\n\n        This will ensure that no virtual keyboard / system keyboard is\n        requested. All instances will be closed.\n        '''\n        for key in list(self._keyboards.keys())[:]:\n            keyboard = self._keyboards[key]\n            if keyboard:\n                keyboard.release()\n\n    def request_keyboard(self, callback, target, input_type='text'):\n        '''.. versionadded:: 1.0.4\n\n        Internal widget method to request the keyboard. This method is rarely\n        required by the end-user as it is handled automatically by the\n        :class:`~kivy.uix.textinput.TextInput`. We expose it in case you want\n        to handle the keyboard manually for unique input scenarios.\n\n        A widget can request the keyboard, indicating a callback to call\n        when the keyboard is released (or taken by another widget).\n\n        :Parameters:\n            `callback`: func\n                Callback that will be called when the keyboard is\n                closed. This can be because somebody else requested the\n                keyboard or the user closed it.\n            `target`: Widget\n                Attach the keyboard to the specified `target`. This should be\n                the widget that requested the keyboard. Ensure you have a\n                different target attached to each keyboard if you're working in\n                a multi user mode.\n\n                .. versionadded:: 1.0.8\n\n            `input_type`: string\n                Choose the type of soft keyboard to request. Can be one of\n                'text', 'number', 'url', 'mail', 'datetime', 'tel', 'address'.\n\n                .. note::\n\n                    `input_type` is currently only honored on mobile devices.\n\n                .. versionadded:: 1.8.0\n\n        :Return:\n            An instance of :class:`Keyboard` containing the callback, target,\n            and if the configuration allows it, a\n            :class:`~kivy.uix.vkeyboard.VKeyboard` instance attached as a\n            *.widget* property.\n\n        .. note::\n\n            The behavior of this function is heavily influenced by the current\n            `keyboard_mode`. Please see the Config's\n            :ref:`configuration tokens <configuration-tokens>` section for\n            more information.\n\n        '''\n\n        # release any previous keyboard attached.\n        self.release_keyboard(target)\n\n        # if we can use virtual vkeyboard, activate it.\n        if self.allow_vkeyboard:\n            keyboard = None\n\n            # late import\n            global VKeyboard\n            if VKeyboard is None and self._vkeyboard_cls is None:\n                from kivy.uix.vkeyboard import VKeyboard\n                self._vkeyboard_cls = VKeyboard\n\n            # if the keyboard doesn't exist, create it.\n            key = 'single' if self.single_vkeyboard else target\n            if key not in self._keyboards:\n                vkeyboard = self._vkeyboard_cls()\n                keyboard = Keyboard(widget=vkeyboard, window=self)\n                vkeyboard.bind(\n                    on_key_down=keyboard._on_vkeyboard_key_down,\n                    on_key_up=keyboard._on_vkeyboard_key_up,\n                    on_textinput=keyboard._on_vkeyboard_textinput)\n                self._keyboards[key] = keyboard\n            else:\n                keyboard = self._keyboards[key]\n\n            # configure vkeyboard\n            keyboard.target = keyboard.widget.target = target\n            keyboard.callback = keyboard.widget.callback = callback\n\n            # add to the window\n            self.add_widget(keyboard.widget)\n\n            # only after add, do dock mode\n            keyboard.widget.docked = self.docked_vkeyboard\n            keyboard.widget.setup_mode()\n\n        else:\n            # system keyboard, just register the callback.\n            keyboard = self._system_keyboard\n            keyboard.callback = callback\n            keyboard.target = target\n\n        # use system (hardware) keyboard according to flag\n        if self.allow_vkeyboard and self.use_syskeyboard:\n            self.unbind(\n                on_key_down=keyboard._on_window_key_down,\n                on_key_up=keyboard._on_window_key_up,\n                on_textinput=keyboard._on_window_textinput)\n            self.bind(\n                on_key_down=keyboard._on_window_key_down,\n                on_key_up=keyboard._on_window_key_up,\n                on_textinput=keyboard._on_window_textinput)\n\n        return keyboard\n\n    def release_keyboard(self, target=None):\n        '''.. versionadded:: 1.0.4\n\n        Internal method for the widget to release the real-keyboard. Check\n        :meth:`request_keyboard` to understand how it works.\n        '''\n        if self.allow_vkeyboard:\n            key = 'single' if self.single_vkeyboard else target\n            if key not in self._keyboards:\n                return\n            keyboard = self._keyboards[key]\n            callback = keyboard.callback\n            if callback:\n                keyboard.callback = None\n                callback()\n            keyboard.target = None\n            self.remove_widget(keyboard.widget)\n            if key != 'single' and key in self._keyboards:\n                del self._keyboards[key]\n        elif self._system_keyboard.callback:\n            # this way will prevent possible recursion.\n            callback = self._system_keyboard.callback\n            self._system_keyboard.callback = None\n            callback()\n            return True\n\n#: Instance of a :class:`WindowBase` implementation\nwindow_impl = []\nif platform == 'linux':\n    window_impl += [('egl_rpi', 'window_egl_rpi', 'WindowEglRpi')]\nif USE_SDL2:\n    window_impl += [('sdl2', 'window_sdl2', 'WindowSDL')]\nelse:\n    window_impl += [\n        ('pygame', 'window_pygame', 'WindowPygame')]\nif platform == 'linux':\n    window_impl += [('x11', 'window_x11', 'WindowX11')]\nWindow = core_select_lib('window', window_impl, True)\n"
  },
  {
    "path": "tickeys/kivy/core/window/window_egl_rpi.py",
    "content": "'''\nEGL Rpi Window: EGL Window provider, specialized for the Pi\n\nInspired by: rpi_vid_core + JF002 rpi kivy  repo\n'''\n\n__all__ = ('WindowEglRpi', )\n\nfrom kivy.logger import Logger\nfrom kivy.core.window import WindowBase\nfrom kivy.base import EventLoop\nfrom kivy.lib.vidcore_lite import bcm, egl\n\n\nclass WindowEglRpi(WindowBase):\n\n    def create_window(self):\n        bcm.host_init()\n\n        w, h = bcm.graphics_get_display_size(0)\n        Logger.debug('Window: Actual display size: {}x{}'.format(\n            w, h))\n        self._size = w, h\n        self._create_window(w, h)\n        self._create_egl_context(self.win, 0)\n        super(WindowEglRpi, self).create_window()\n\n    def _create_window(self, w, h):\n        dst = bcm.Rect(0, 0, w, h)\n        src = bcm.Rect(0, 0, w << 16, h << 16)\n        display = egl.bcm_display_open(0)\n        update = egl.bcm_update_start(0)\n        element = egl.bcm_element_add(update, display, 0, dst, src)\n        self.win = egl.NativeWindow(element, w, h)\n        egl.bcm_update_submit_sync(update)\n\n    def _create_egl_context(self, win, flags):\n        api = egl._constants.EGL_OPENGL_ES_API\n        c = egl._constants\n\n        attribs = [\n            c.EGL_RED_SIZE, 8,\n            c.EGL_GREEN_SIZE, 8,\n            c.EGL_BLUE_SIZE, 8,\n            c.EGL_ALPHA_SIZE, 8,\n            c.EGL_DEPTH_SIZE, 16,\n            c.EGL_STENCIL_SIZE, 8,\n            c.EGL_SURFACE_TYPE, c.EGL_WINDOW_BIT,\n            c.EGL_NONE]\n\n        attribs_context = [c.EGL_CONTEXT_CLIENT_VERSION, 2, c.EGL_NONE]\n\n        display = egl.GetDisplay(c.EGL_DEFAULT_DISPLAY)\n        egl.Initialise(display)\n        egl.BindAPI(c.EGL_OPENGL_ES_API)\n        egl.GetConfigs(display)\n        config = egl.ChooseConfig(display, attribs, 1)[0]\n        surface = egl.CreateWindowSurface(display, config, win)\n        context = egl.CreateContext(display, config, None, attribs_context)\n        egl.MakeCurrent(display, surface, surface, context)\n\n        self.egl_info = (display, surface, context)\n        egl.MakeCurrent(display, surface, surface, context)\n\n    def close(self):\n        egl.Terminate(self.egl_info[0])\n\n    def flip(self):\n        egl.SwapBuffers(self.egl_info[0], self.egl_info[1])\n\n    def _mainloop(self):\n        EventLoop.idle()\n\n    def mainloop(self):\n        while not EventLoop.quit and EventLoop.status == 'started':\n            try:\n                self._mainloop()\n            except BaseException as inst:\n                raise\n                '''\n                # use exception manager first\n                r = ExceptionManager.handle_exception(inst)\n                if r == ExceptionManager.RAISE:\n                    #stopTouchApp()\n                    raise\n                else:\n                    pass\n                '''\n"
  },
  {
    "path": "tickeys/kivy/core/window/window_pygame.py",
    "content": "'''\nWindow Pygame: windowing provider based on Pygame\n'''\n\n__all__ = ('WindowPygame', )\n\n# fail early if possible\nimport pygame\n\nfrom kivy.compat import PY2\nfrom kivy.core.window import WindowBase\nfrom kivy.core import CoreCriticalException\nfrom os import environ\nfrom os.path import exists, join\nfrom kivy.config import Config\nfrom kivy import kivy_data_dir\nfrom kivy.base import ExceptionManager\nfrom kivy.logger import Logger\nfrom kivy.base import stopTouchApp, EventLoop\nfrom kivy.utils import platform, deprecated\nfrom kivy.resources import resource_find\nfrom kivy.clock import Clock\n\ntry:\n    android = None\n    if platform == 'android':\n        import android\nexcept ImportError:\n    pass\n\n# late binding\nglReadPixels = GL_RGBA = GL_UNSIGNED_BYTE = None\n\n\nclass WindowPygame(WindowBase):\n\n    def create_window(self, *largs):\n        # ensure the mouse is still not up after window creation, otherwise, we\n        # have some weird bugs\n        self.dispatch('on_mouse_up', 0, 0, 'all', [])\n\n        # force display to show (available only for fullscreen)\n        displayidx = Config.getint('graphics', 'display')\n        if not 'SDL_VIDEO_FULLSCREEN_HEAD' in environ and displayidx != -1:\n            environ['SDL_VIDEO_FULLSCREEN_HEAD'] = '%d' % displayidx\n\n        # init some opengl, same as before.\n        self.flags = pygame.HWSURFACE | pygame.OPENGL | pygame.DOUBLEBUF\n\n        # right now, activate resizable window only on linux.\n        # on window / macosx, the opengl context is lost, and we need to\n        # reconstruct everything. Check #168 for a state of the work.\n        if platform in ('linux', 'macosx', 'win') and \\\n                Config.getboolean('graphics', 'resizable'):\n            self.flags |= pygame.RESIZABLE\n\n        try:\n            pygame.display.init()\n        except pygame.error as e:\n            raise CoreCriticalException(e.message)\n\n        multisamples = Config.getint('graphics', 'multisamples')\n\n        if multisamples > 0:\n            pygame.display.gl_set_attribute(pygame.GL_MULTISAMPLEBUFFERS, 1)\n            pygame.display.gl_set_attribute(pygame.GL_MULTISAMPLESAMPLES,\n                                            multisamples)\n        pygame.display.gl_set_attribute(pygame.GL_DEPTH_SIZE, 16)\n        pygame.display.gl_set_attribute(pygame.GL_STENCIL_SIZE, 1)\n        pygame.display.set_caption(self.title)\n\n        if self.position == 'auto':\n            self._pos = None\n        elif self.position == 'custom':\n            self._pos = self.left, self.top\n        else:\n            raise ValueError('position token in configuration accept only '\n                             '\"auto\" or \"custom\"')\n\n        if self._fake_fullscreen:\n            if not self.borderless:\n                self.fullscreen = self._fake_fullscreen = False\n            elif not self.fullscreen or self.fullscreen == 'auto':\n                self.borderless = self._fake_fullscreen = False\n\n        if self.fullscreen == 'fake':\n            self.borderless = self._fake_fullscreen = True\n            Logger.warning(\"The 'fake' fullscreen option has been \"\n                            \"deprecated, use Window.borderless or the \"\n                            \"borderless Config option instead.\")\n\n        if self.fullscreen == 'fake' or self.borderless:\n            Logger.debug('WinPygame: Set window to borderless mode.')\n\n            self.flags |= pygame.NOFRAME\n            # If no position set in borderless mode, we always need\n            # to set the position. So use 0, 0.\n            if self._pos is None:\n                self._pos = (0, 0)\n            environ['SDL_VIDEO_WINDOW_POS'] = '%d,%d' % self._pos\n\n        elif self.fullscreen in ('auto', True):\n            Logger.debug('WinPygame: Set window to fullscreen mode')\n            self.flags |= pygame.FULLSCREEN\n\n        elif self._pos is not None:\n            environ['SDL_VIDEO_WINDOW_POS'] = '%d,%d' % self._pos\n\n        # never stay with a None pos, application using w.center will be fired.\n        self._pos = (0, 0)\n\n        # prepare keyboard\n        repeat_delay = int(Config.get('kivy', 'keyboard_repeat_delay'))\n        repeat_rate = float(Config.get('kivy', 'keyboard_repeat_rate'))\n        pygame.key.set_repeat(repeat_delay, int(1000. / repeat_rate))\n\n        # set window icon before calling set_mode\n        try:\n            filename_icon = self.icon or Config.get('kivy', 'window_icon')\n            if filename_icon == '':\n                logo_size = 32\n                if platform == 'macosx':\n                    logo_size = 512\n                elif platform == 'win':\n                    logo_size = 64\n                filename_icon = 'kivy-icon-{}.png'.format(logo_size)\n                filename_icon = resource_find(\n                        join(kivy_data_dir, 'logo', filename_icon))\n            self.set_icon(filename_icon)\n        except:\n            Logger.exception('Window: cannot set icon')\n\n        # try to use mode with multisamples\n        try:\n            self._pygame_set_mode()\n        except pygame.error as e:\n            if multisamples:\n                Logger.warning('WinPygame: Video: failed (multisamples=%d)' %\n                               multisamples)\n                Logger.warning('WinPygame: trying without antialiasing')\n                pygame.display.gl_set_attribute(\n                    pygame.GL_MULTISAMPLEBUFFERS, 0)\n                pygame.display.gl_set_attribute(\n                    pygame.GL_MULTISAMPLESAMPLES, 0)\n                multisamples = 0\n                try:\n                    self._pygame_set_mode()\n                except pygame.error as e:\n                    raise CoreCriticalException(e.message)\n            else:\n                raise CoreCriticalException(e.message)\n\n        info = pygame.display.Info()\n        self._size = (info.current_w, info.current_h)\n        #self.dispatch('on_resize', *self._size)\n\n        # in order to debug futur issue with pygame/display, let's show\n        # more debug output.\n        Logger.debug('Window: Display driver ' + pygame.display.get_driver())\n        Logger.debug('Window: Actual window size: %dx%d',\n                     info.current_w, info.current_h)\n        if platform != 'android':\n            # unsupported platform, such as android that doesn't support\n            # gl_get_attribute.\n            Logger.debug(\n                'Window: Actual color bits r%d g%d b%d a%d',\n                pygame.display.gl_get_attribute(pygame.GL_RED_SIZE),\n                pygame.display.gl_get_attribute(pygame.GL_GREEN_SIZE),\n                pygame.display.gl_get_attribute(pygame.GL_BLUE_SIZE),\n                pygame.display.gl_get_attribute(pygame.GL_ALPHA_SIZE))\n            Logger.debug(\n                'Window: Actual depth bits: %d',\n                pygame.display.gl_get_attribute(pygame.GL_DEPTH_SIZE))\n            Logger.debug(\n                'Window: Actual stencil bits: %d',\n                pygame.display.gl_get_attribute(pygame.GL_STENCIL_SIZE))\n            Logger.debug(\n                'Window: Actual multisampling samples: %d',\n                pygame.display.gl_get_attribute(pygame.GL_MULTISAMPLESAMPLES))\n        super(WindowPygame, self).create_window()\n\n        # set mouse visibility\n        pygame.mouse.set_visible(\n            Config.getboolean('graphics', 'show_cursor'))\n\n        # if we are on android platform, automaticly create hooks\n        if android:\n            from kivy.support import install_android\n            install_android()\n\n    def close(self):\n        pygame.display.quit()\n        self.dispatch('on_close')\n\n    def on_title(self, instance, value):\n        if self.initialized:\n            pygame.display.set_caption(self.title)\n\n    def set_icon(self, filename):\n        if not exists(filename):\n            return False\n        try:\n            if platform == 'win':\n                try:\n                    if self._set_icon_win(filename):\n                        return True\n                except:\n                    # fallback on standard loading then.\n                    pass\n\n            # for all others platform, or if the ico is not available, use the\n            # default way to set it.\n            self._set_icon_standard(filename)\n            super(WindowPygame, self).set_icon(filename)\n        except:\n            Logger.exception('WinPygame: unable to set icon')\n\n    def _set_icon_standard(self, filename):\n        if PY2:\n            try:\n                im = pygame.image.load(filename)\n            except UnicodeEncodeError:\n                im = pygame.image.load(filename.encode('utf8'))\n        else:\n            im = pygame.image.load(filename)\n        if im is None:\n            raise Exception('Unable to load window icon (not found)')\n        pygame.display.set_icon(im)\n\n    def _set_icon_win(self, filename):\n        # ensure the window ico is ended by ico\n        if not filename.endswith('.ico'):\n            filename = '{}.ico'.format(filename.rsplit('.', 1)[0])\n        if not exists(filename):\n            return False\n\n        import win32api\n        import win32gui\n        import win32con\n        hwnd = pygame.display.get_wm_info()['window']\n        icon_big = win32gui.LoadImage(\n            None, filename, win32con.IMAGE_ICON,\n            48, 48, win32con.LR_LOADFROMFILE)\n        icon_small = win32gui.LoadImage(\n            None, filename, win32con.IMAGE_ICON,\n            16, 16, win32con.LR_LOADFROMFILE)\n        win32api.SendMessage(\n            hwnd, win32con.WM_SETICON, win32con.ICON_SMALL, icon_small)\n        win32api.SendMessage(\n            hwnd, win32con.WM_SETICON, win32con.ICON_BIG, icon_big)\n        return True\n\n    def screenshot(self, *largs, **kwargs):\n        global glReadPixels, GL_RGBA, GL_UNSIGNED_BYTE\n        filename = super(WindowPygame, self).screenshot(*largs, **kwargs)\n        if filename is None:\n            return None\n        if glReadPixels is None:\n            from kivy.graphics.opengl import (glReadPixels, GL_RGBA,\n                                              GL_UNSIGNED_BYTE)\n        width, height = self.system_size\n        data = glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE)\n        if PY2:\n            data = str(buffer(data))\n        else:\n            data = bytes(bytearray(data))\n        surface = pygame.image.fromstring(data, (width, height), 'RGBA', True)\n        pygame.image.save(surface, filename)\n        Logger.debug('Window: Screenshot saved at <%s>' % filename)\n        return filename\n\n    def flip(self):\n        pygame.display.flip()\n        super(WindowPygame, self).flip()\n\n    @deprecated\n    def toggle_fullscreen(self):\n        if self.flags & pygame.FULLSCREEN:\n            self.flags &= ~pygame.FULLSCREEN\n        else:\n            self.flags |= pygame.FULLSCREEN\n        self._pygame_set_mode()\n\n    def _mainloop(self):\n        EventLoop.idle()\n\n        for event in pygame.event.get():\n\n            # kill application (SIG_TERM)\n            if event.type == pygame.QUIT:\n                if self.dispatch('on_request_close'):\n                    continue\n                EventLoop.quit = True\n                self.close()\n\n            # mouse move\n            elif event.type == pygame.MOUSEMOTION:\n                x, y = event.pos\n                self.mouse_pos = x, self.system_size[1] - y\n                # don't dispatch motion if no button are pressed\n                if event.buttons == (0, 0, 0):\n                    continue\n                self._mouse_x = x\n                self._mouse_y = y\n                self._mouse_meta = self.modifiers\n                self.dispatch('on_mouse_move', x, y, self.modifiers)\n\n            # mouse action\n            elif event.type in (pygame.MOUSEBUTTONDOWN,\n                                pygame.MOUSEBUTTONUP):\n                self._pygame_update_modifiers()\n                x, y = event.pos\n                btn = 'left'\n                if event.button == 3:\n                    btn = 'right'\n                elif event.button == 2:\n                    btn = 'middle'\n                elif event.button == 4:\n                    btn = 'scrolldown'\n                elif event.button == 5:\n                    btn = 'scrollup'\n                elif event.button == 6:\n                    btn = 'scrollright'\n                elif event.button == 7:\n                    btn = 'scrollleft'\n                eventname = 'on_mouse_down'\n                if event.type == pygame.MOUSEBUTTONUP:\n                    eventname = 'on_mouse_up'\n                self._mouse_x = x\n                self._mouse_y = y\n                self._mouse_meta = self.modifiers\n                self._mouse_btn = btn\n                self._mouse_down = eventname == 'on_mouse_down'\n                self.dispatch(eventname, x, y, btn, self.modifiers)\n\n            # joystick action\n            elif event.type == pygame.JOYAXISMOTION:\n                self.dispatch('on_joy_axis', event.joy, event.axis, event.value)\n\n            elif event.type == pygame.JOYHATMOTION:\n                self.dispatch('on_joy_hat', event.joy, event.hat, event.value)\n\n            elif event.type == pygame.JOYBALLMOTION:\n                self.dispatch('on_joy_ball', event.joy, event.ballid,\n                            event.rel[0], event.rel[1])\n\n            elif event.type == pygame.JOYBUTTONDOWN:\n                self.dispatch('on_joy_button_down', event.joy, event.button)\n\n            elif event.type == pygame.JOYBUTTONUP:\n                self.dispatch('on_joy_button_up', event.joy, event.button)\n\n            # keyboard action\n            elif event.type in (pygame.KEYDOWN, pygame.KEYUP):\n                self._pygame_update_modifiers(event.mod)\n                # atm, don't handle keyup\n                if event.type == pygame.KEYUP:\n                    self.dispatch('on_key_up', event.key,\n                                  event.scancode)\n                    continue\n\n                # don't dispatch more key if down event is accepted\n                if self.dispatch('on_key_down', event.key,\n                                 event.scancode, event.unicode,\n                                 self.modifiers):\n                    continue\n                self.dispatch('on_keyboard', event.key,\n                              event.scancode, event.unicode,\n                              self.modifiers)\n\n            # video resize\n            elif event.type == pygame.VIDEORESIZE:\n                self._size = event.size\n                self.update_viewport()\n\n            elif event.type == pygame.VIDEOEXPOSE:\n                self.canvas.ask_update()\n\n            # ignored event\n            elif event.type == pygame.ACTIVEEVENT:\n                pass\n\n            # drop file (pygame patch needed)\n            elif event.type == pygame.USEREVENT and \\\n                    hasattr(pygame, 'USEREVENT_DROPFILE') and \\\n                    event.code == pygame.USEREVENT_DROPFILE:\n                self.dispatch('on_dropfile', event.filename)\n\n            '''\n            # unhandled event !\n            else:\n                Logger.debug('WinPygame: Unhandled event %s' % str(event))\n            '''\n\n    def mainloop(self):\n        while not EventLoop.quit and EventLoop.status == 'started':\n            try:\n                self._mainloop()\n                if not pygame.display.get_active():\n                    pygame.time.wait(100)\n            except BaseException as inst:\n                # use exception manager first\n                r = ExceptionManager.handle_exception(inst)\n                if r == ExceptionManager.RAISE:\n                    stopTouchApp()\n                    raise\n                else:\n                    pass\n\n    #\n    # Pygame wrapper\n    #\n    def _pygame_set_mode(self, size=None):\n        if size is None:\n            size = self.size\n        if self.fullscreen == 'auto':\n            pygame.display.set_mode((0, 0), self.flags)\n        else:\n            pygame.display.set_mode(size, self.flags)\n\n    def _pygame_update_modifiers(self, mods=None):\n        # Available mod, from dir(pygame)\n        # 'KMOD_ALT', 'KMOD_CAPS', 'KMOD_CTRL', 'KMOD_LALT',\n        # 'KMOD_LCTRL', 'KMOD_LMETA', 'KMOD_LSHIFT', 'KMOD_META',\n        # 'KMOD_MODE', 'KMOD_NONE'\n        if mods is None:\n            mods = pygame.key.get_mods()\n        self._modifiers = []\n        if mods & (pygame.KMOD_SHIFT | pygame.KMOD_LSHIFT):\n            self._modifiers.append('shift')\n        if mods & (pygame.KMOD_ALT | pygame.KMOD_LALT):\n            self._modifiers.append('alt')\n        if mods & (pygame.KMOD_CTRL | pygame.KMOD_LCTRL):\n            self._modifiers.append('ctrl')\n        if mods & (pygame.KMOD_META | pygame.KMOD_LMETA):\n            self._modifiers.append('meta')\n\n    def request_keyboard(self, callback, target, input_type='text'):\n        keyboard = super(WindowPygame, self).request_keyboard(\n            callback, target, input_type)\n        if android and not self.allow_vkeyboard:\n            android.show_keyboard(target, input_type)\n        return keyboard\n\n    def release_keyboard(self, *largs):\n        super(WindowPygame, self).release_keyboard(*largs)\n        if android:\n            android.hide_keyboard()\n        return True\n"
  },
  {
    "path": "tickeys/kivy/core/window/window_sdl2.py",
    "content": "# found a way to include it more easily.\n'''\nSDL2 Window\n===========\n\nWindowing provider directly based on our own wrapped version of SDL.\n\nTODO:\n    - fix keys\n    - support scrolling\n    - clean code\n    - manage correctly all sdl events\n\n'''\n\n__all__ = ('WindowSDL2', )\n\nfrom os.path import join\nfrom kivy import kivy_data_dir\nfrom kivy.logger import Logger\nfrom kivy import metrics\nfrom kivy.base import EventLoop, ExceptionManager, stopTouchApp\nfrom kivy.clock import Clock\nfrom kivy.config import Config\nfrom kivy.core.window import WindowBase\nfrom kivy.core.window._window_sdl2 import _WindowSDL2Storage\nfrom kivy.input.provider import MotionEventProvider\nfrom kivy.input.motionevent import MotionEvent\nfrom kivy.resources import resource_find\nfrom kivy.utils import platform, deprecated\nfrom kivy.compat import unichr\nfrom collections import deque\n\nKMOD_LCTRL = 64\nKMOD_RCTRL = 128\nKMOD_RSHIFT = 2\nKMOD_LSHIFT = 1\nKMOD_RALT = 512\nKMOD_LALT = 256\nKMOD_LMETA = 1024\nKMOD_RMETA = 2048\n\nSDLK_SHIFTL = 1073742049\nSDLK_SHIFTR = 1073742053\nSDLK_LCTRL = 1073742048\nSDLK_RCTRL = 1073742052\nSDLK_LALT = 1073742050\nSDLK_RALT = 1073742054\nSDLK_LEFT = 1073741904\nSDLK_RIGHT = 1073741903\nSDLK_UP = 1073741906\nSDLK_DOWN = 1073741905\nSDLK_HOME = 1073741898\nSDLK_END = 1073741901\nSDLK_PAGEUP = 1073741899\nSDLK_PAGEDOWN = 1073741902\nSDLK_SUPER = 1073742051\nSDLK_CAPS = 1073741881\nSDLK_INSERT = 1073741897\nSDLK_KEYPADNUM = 1073741907\nSDLK_F1 = 1073741882\nSDLK_F2 = 1073741883\nSDLK_F3 = 1073741884\nSDLK_F4 = 1073741885\nSDLK_F5 = 1073741886\nSDLK_F6 = 1073741887\nSDLK_F7 = 1073741888\nSDLK_F8 = 1073741889\nSDLK_F9 = 1073741890\nSDLK_F10 = 1073741891\nSDLK_F11 = 1073741892\nSDLK_F12 = 1073741893\nSDLK_F13 = 1073741894\nSDLK_F14 = 1073741895\nSDLK_F15 = 1073741896\n\n\nclass SDL2MotionEvent(MotionEvent):\n    def depack(self, args):\n        self.is_touch = True\n        self.profile = ('pos', )\n        self.sx, self.sy = args\n        win = EventLoop.window\n        super(SDL2MotionEvent, self).depack(args)\n\n\nclass SDL2MotionEventProvider(MotionEventProvider):\n    win = None\n    q = deque()\n    touchmap = {}\n\n    def update(self, dispatch_fn):\n        touchmap = self.touchmap\n        while True:\n            try:\n                value = self.q.pop()\n            except IndexError:\n                return\n\n            action, fid, x, y = value\n            y = 1 - y\n            if fid not in touchmap:\n                touchmap[fid] = me = SDL2MotionEvent('sdl', fid, (x, y))\n            else:\n                me = touchmap[fid]\n                me.move((x, y))\n            if action == 'fingerdown':\n                dispatch_fn('begin', me)\n            elif action == 'fingerup':\n                me.update_time_end()\n                dispatch_fn('end', me)\n                del touchmap[fid]\n            else:\n                dispatch_fn('update', me)\n\n\nclass WindowSDL(WindowBase):\n\n    def __init__(self, **kwargs):\n        self._win = _WindowSDL2Storage()\n        super(WindowSDL, self).__init__()\n        self._mouse_x = self._mouse_y = -1\n        self._meta_keys = (KMOD_LCTRL, KMOD_RCTRL, KMOD_RSHIFT,\n            KMOD_LSHIFT, KMOD_RALT, KMOD_LALT, KMOD_LMETA,\n            KMOD_RMETA)\n        self.command_keys = {\n                    27: 'escape',\n                    9: 'tab',\n                    8: 'backspace',\n                    13: 'enter',\n                    127: 'del',\n                    271: 'enter',\n                    273: 'up',\n                    274: 'down',\n                    275: 'right',\n                    276: 'left',\n                    278: 'home',\n                    279: 'end',\n                    280: 'pgup',\n                    281: 'pgdown'}\n        self._mouse_buttons_down = set()\n\n    def create_window(self, *largs):\n\n        if self._fake_fullscreen:\n            if not self.borderless:\n                self.fullscreen = self._fake_fullscreen = False\n            elif not self.fullscreen or self.fullscreen == 'auto':\n                self.borderless = self._fake_fullscreen = False\n\n        if self.fullscreen == 'fake':\n            self.borderless = self._fake_fullscreen = True\n            Logger.warning(\"The 'fake' fullscreen option has been \"\n                            \"deprecated, use Window.borderless or the \"\n                            \"borderless Config option instead.\")\n\n        if not self.initialized:\n\n            if self.position == 'auto':\n                pos = None, None\n            elif self.position == 'custom':\n                pos = self.left, self.top\n\n            # setup !\n            w, h = self.system_size\n            resizable = Config.getboolean('graphics', 'resizable')\n            state = (Config.get('graphics', 'window_state')\n                     if self._is_desktop else None)\n            self.system_size = _size = self._win.setup_window(\n                pos[0], pos[1], w, h, self.borderless,\n                self.fullscreen, resizable, state)\n\n            # calculate density\n            sz = self._win._get_gl_size()[0]\n            self._density = density = sz / _size[0]\n            if self._is_desktop and self.size[0] != _size[0]:\n                self.dpi = density * 96.\n\n            # never stay with a None pos, application using w.center\n            # will be fired.\n            self._pos = (0, 0)\n        else:\n            w, h = self.system_size\n            self._win.resize_window(w, h)\n            self._win.set_border_state(self.borderless)\n            self._win.set_fullscreen_mode(self.fullscreen)\n\n        super(WindowSDL, self).create_window()\n\n        if self.initialized:\n            return\n\n        # auto add input provider\n        Logger.info('Window: auto add sdl2 input provider')\n        from kivy.base import EventLoop\n        SDL2MotionEventProvider.win = self\n        EventLoop.add_input_provider(SDL2MotionEventProvider('sdl', ''))\n\n        # set window icon before calling set_mode\n        try:\n            filename_icon = self.icon or Config.get('kivy', 'window_icon')\n            if filename_icon == '':\n                logo_size = 32\n                if platform == 'macosx':\n                    logo_size = 512\n                elif platform == 'win':\n                    logo_size = 64\n                filename_icon = 'kivy-icon-{}.png'.format(logo_size)\n                filename_icon = resource_find(\n                        join(kivy_data_dir, 'logo', filename_icon))\n            self.set_icon(filename_icon)\n        except:\n            Logger.exception('Window: cannot set icon')\n\n    def close(self):\n        self._win.teardown_window()\n        self.dispatch('on_close')\n\n    def maximize(self):\n        if self._is_desktop:\n            self._win.maximize_window()\n        else:\n            Logger.warning('Window: maximize() is used only on desktop OSes.')\n\n    def minimize(self):\n        if self._is_desktop:\n            self._win.minimize_window()\n        else:\n            Logger.warning('Window: minimize() is used only on desktop OSes.')\n\n    def restore(self):\n        if self._is_desktop:\n            self._win.restore_window()\n        else:\n            Logger.warning('Window: restore() is used only on desktop OSes.')\n\n    def hide(self):\n        if self._is_desktop:\n            self._win.hide_window()\n        else:\n            Logger.warning('Window: hide() is used only on desktop OSes.')\n\n    def show(self):\n        if self._is_desktop:\n            self._win.show_window()\n        else:\n            Logger.warning('Window: show() is used only on desktop OSes.')\n\n    @deprecated\n    def toggle_fullscreen(self):\n        if self.fullscreen in (True, 'auto'):\n            self.fullscreen = False\n        else:\n            self.fullscreen = 'auto'\n\n    def set_title(self, title):\n        self._win.set_window_title(title)\n\n    def set_icon(self, filename):\n        self._win.set_window_icon(str(filename))\n\n    def screenshot(self, *largs, **kwargs):\n        filename = super(WindowSDL, self).screenshot(*largs, **kwargs)\n        if filename is None:\n            return\n\n        from kivy.graphics.opengl import glReadPixels, GL_RGB, GL_UNSIGNED_BYTE\n        width, height = self.size\n        data = glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE)\n        self._win.save_bytes_in_png(filename, data, width, height)\n        Logger.debug('Window: Screenshot saved at <%s>' % filename)\n        return filename\n\n    def flip(self):\n        self._win.flip()\n        super(WindowSDL, self).flip()\n\n    def _fix_mouse_pos(self, x, y):\n        density = self._density\n        y -= 1\n        if self._is_desktop and self.size[0] != self._size[0]:\n            x, y = x * density, (y * density) - self.system_size[1]\n            #y = self.system_size[1] - y\n            self.mouse_pos = x, y\n        else:\n            self.mouse_pos = x, self.system_size[1] - y\n        return x, y\n\n    def _mainloop(self):\n        EventLoop.idle()\n\n        while True:\n            event = self._win.poll()\n            if event is False:\n                break\n            if event is None:\n                continue\n\n            action, args = event[0], event[1:]\n            if action == 'quit':\n                EventLoop.quit = True\n                self.close()\n                break\n\n            elif action in ('fingermotion', 'fingerdown', 'fingerup'):\n                # for finger, pass the raw event to SDL motion event provider\n                # XXX this is problematic. On OSX, it generates touches with 0,\n                # 0 coordinates, at the same times as mouse. But it works.\n                # We have a conflict of using either the mouse or the finger.\n                # Right now, we have no mechanism that we could use to know\n                # which is the preferred one for the application.\n                if platform == \"ios\":\n                    SDL2MotionEventProvider.q.appendleft(event)\n                pass\n\n            elif action == 'mousemotion':\n                x, y = args\n                x, y = self._fix_mouse_pos(x, y)\n                self._mouse_x = x\n                self._mouse_y = y\n                # don't dispatch motion if no button are pressed\n                if len(self._mouse_buttons_down) == 0:\n                    continue\n                self._mouse_meta = self.modifiers\n                self.dispatch('on_mouse_move', x, y, self.modifiers)\n\n            elif action in ('mousebuttondown', 'mousebuttonup'):\n                x, y, button = args\n                x, y = self._fix_mouse_pos(x, y)\n                btn = 'left'\n                if button == 3:\n                    btn = 'right'\n                elif button == 2:\n                    btn = 'middle'\n                eventname = 'on_mouse_down'\n                self._mouse_buttons_down.add(button)\n                if action == 'mousebuttonup':\n                    eventname = 'on_mouse_up'\n                    self._mouse_buttons_down.remove(button)\n                self._mouse_x = x\n                self._mouse_y = y\n                self.dispatch(eventname, x, y, btn, self.modifiers)\n            elif action.startswith('mousewheel'):\n                self._update_modifiers()\n                x, y, button = args\n                btn = 'scrolldown'\n                if action.endswith('up'):\n                    btn = 'scrollup'\n                elif action.endswith('right'):\n                    btn = 'scrollright'\n                elif action.endswith('left'):\n                    btn = 'scrollleft'\n\n                self._mouse_meta = self.modifiers\n                self._mouse_btn = btn\n                #times = x if y == 0 else y\n                #times = min(abs(times), 100)\n                #for k in range(times):\n                self._mouse_down = True\n                self.dispatch('on_mouse_down',\n                    self._mouse_x, self._mouse_y, btn, self.modifiers)\n                self._mouse_down = False\n                self.dispatch('on_mouse_up',\n                    self._mouse_x, self._mouse_y, btn, self.modifiers)\n\n            elif action == 'dropfile':\n                dropfile = args\n                self.dispatch('on_dropfile', dropfile[0])\n            # video resize\n            elif action == 'windowresized':\n                self._size = self._win.window_size\n                # don't use trigger here, we want to delay the resize event\n                cb = self._do_resize\n                Clock.unschedule(cb)\n                Clock.schedule_once(cb, .1)\n\n            elif action == 'windowresized':\n                self.canvas.ask_update()\n\n            elif action == 'windowrestored':\n                self.canvas.ask_update()\n\n            elif action == 'windowexposed':\n                self.canvas.ask_update()\n\n            elif action == 'windowminimized':\n                if Config.getboolean('kivy', 'pause_on_minimize'):\n                    self.do_pause()\n\n            elif action == 'joyaxismotion':\n                stickid, axisid, value = args\n                self.dispatch('on_joy_axis', stickid, axisid, value)\n            elif action == 'joyhatmotion':\n                stickid, hatid, value = args\n                self.dispatch('on_joy_hat', stickid, hatid, value)\n            elif action == 'joyballmotion':\n                stickid, ballid, xrel, yrel = args\n                self.dispatch('on_joy_ball', stickid, ballid, xrel, yrel)\n            elif action == 'joybuttondown':\n                stickid, buttonid = args\n                self.dispatch('on_joy_button_down', stickid, buttonid)\n            elif action == 'joybuttonup':\n                stickid, buttonid = args\n                self.dispatch('on_joy_button_up', stickid, buttonid)\n\n            elif action in ('keydown', 'keyup'):\n                mod, key, scancode, kstr = args\n\n                key_swap = {\n                    SDLK_LEFT: 276, SDLK_RIGHT: 275, SDLK_UP: 273,\n                    SDLK_DOWN: 274, SDLK_HOME: 278, SDLK_END: 279,\n                    SDLK_PAGEDOWN: 281, SDLK_PAGEUP: 280, SDLK_SHIFTR: 303,\n                    SDLK_SHIFTL: 304, SDLK_SUPER: 309, SDLK_LCTRL: 305,\n                    SDLK_RCTRL: 306, SDLK_LALT: 308, SDLK_RALT: 307,\n                    SDLK_CAPS: 301, SDLK_INSERT: 277, SDLK_F1: 282,\n                    SDLK_F2: 283, SDLK_F3: 284, SDLK_F4: 285, SDLK_F5: 286,\n                    SDLK_F6: 287, SDLK_F7: 288, SDLK_F8: 289, SDLK_F9: 290,\n                    SDLK_F10: 291, SDLK_F11: 292, SDLK_F12: 293, SDLK_F13: 294,\n                    SDLK_F14: 295, SDLK_F15: 296, SDLK_KEYPADNUM: 300}\n\n                if platform == 'ios':\n                    # XXX ios keyboard suck, when backspace is hit, the delete\n                    # keycode is sent. fix it.\n                    key_swap[127] = 8  # back\n\n                try:\n                    key = key_swap[key]\n                except KeyError:\n                    pass\n\n                if action == 'keydown':\n                    self._update_modifiers(mod, key)\n                else:\n                    self._update_modifiers(mod)  # ignore the key, it\n                                                 # has been released\n\n                # if mod in self._meta_keys:\n                if (key not in self._modifiers and\n                    key not in self.command_keys.keys()):\n                    try:\n                        kstr = unichr(key)\n                    except ValueError:\n                        pass\n                #if 'shift' in self._modifiers and key\\\n                #        not in self.command_keys.keys():\n                #    return\n\n                if action == 'keyup':\n                    self.dispatch('on_key_up', key, scancode)\n                    continue\n\n                # don't dispatch more key if down event is accepted\n                if self.dispatch('on_key_down', key,\n                                 scancode, kstr,\n                                 self.modifiers):\n                    continue\n                self.dispatch('on_keyboard', key,\n                              scancode, kstr,\n                              self.modifiers)\n\n            elif action == 'textinput':\n                text = args[0]\n                self.dispatch('on_textinput', text)\n                # XXX on IOS, keydown/up don't send unicode anymore.\n                # With latest sdl, the text is sent over textinput\n                # Right now, redo keydown/up, but we need to seperate both call\n                # too. (and adapt on_key_* API.)\n                #self.dispatch()\n                #self.dispatch('on_key_down', key, None, args[0],\n                #              self.modifiers)\n                #self.dispatch('on_keyboard', None, None, args[0],\n                #              self.modifiers)\n                #self.dispatch('on_key_up', key, None, args[0],\n                #              self.modifiers)\n\n            # unhandled event !\n            else:\n                Logger.trace('WindowSDL: Unhandled event %s' % str(event))\n\n    def _do_resize(self, dt):\n        Logger.debug('Window: Resize window to %s' % str(self.size))\n        self._win.resize_window(*self._size)\n        self.dispatch('on_resize', *self.size)\n\n    def do_pause(self):\n        # should go to app pause mode.\n        from kivy.app import App\n        from kivy.base import stopTouchApp\n        app = App.get_running_app()\n        if not app:\n            Logger.info('WindowSDL: No running App found, exit.')\n            stopTouchApp()\n            return\n\n        if not app.dispatch('on_pause'):\n            Logger.info('WindowSDL: App doesn\\'t support pause mode, stop.')\n            stopTouchApp()\n            return\n\n        # XXX FIXME wait for sdl resume\n        while True:\n            event = self._win.poll()\n            if event is False:\n                continue\n            if event is None:\n                continue\n\n            action, args = event[0], event[1:]\n            if action == 'quit':\n                EventLoop.quit = True\n                self.close()\n                break\n            elif action == 'windowrestored':\n                break\n\n        app.dispatch('on_resume')\n\n    def mainloop(self):\n        # don't known why, but pygame required a resize event\n        # for opengl, before mainloop... window reinit ?\n        #self.dispatch('on_resize', *self.size)\n\n        while not EventLoop.quit and EventLoop.status == 'started':\n            try:\n                self._mainloop()\n            except BaseException as inst:\n                # use exception manager first\n                r = ExceptionManager.handle_exception(inst)\n                if r == ExceptionManager.RAISE:\n                    stopTouchApp()\n                    raise\n                else:\n                    pass\n\n    #\n    # Pygame wrapper\n    #\n    def _update_modifiers(self, mods=None, key=None):\n        # Available mod, from dir(pygame)\n        # 'KMOD_ALT', 'KMOD_CAPS', 'KMOD_CTRL', 'KMOD_LALT',\n        # 'KMOD_LCTRL', 'KMOD_LMETA', 'KMOD_LSHIFT', 'KMOD_META',\n        # 'KMOD_MODE', 'KMOD_NONE'\n        if mods is None and key is None:\n            return\n        modifiers = set()\n\n        if mods is not None:\n            if mods & (KMOD_RSHIFT | KMOD_LSHIFT):\n                modifiers.add('shift')\n            if mods & (KMOD_RALT | KMOD_LALT):\n                modifiers.add('alt')\n            if mods & (KMOD_RCTRL | KMOD_LCTRL):\n                modifiers.add('ctrl')\n            if mods & (KMOD_RMETA | KMOD_LMETA):\n                modifiers.add('meta')\n\n        if key is not None:\n            if key in (KMOD_RSHIFT, KMOD_LSHIFT):\n                modifiers.add('shift')\n            if key in (KMOD_RALT, KMOD_LALT):\n                modifiers.add('alt')\n            if key in (KMOD_RCTRL, KMOD_LCTRL):\n                modifiers.add('ctrl')\n            if key in (KMOD_RMETA, KMOD_LMETA):\n                modifiers.add('meta')\n\n        self._modifiers = list(modifiers)\n        return\n\n    def request_keyboard(self, callback, target, input_type='text'):\n        self._sdl_keyboard = super(WindowSDL, self).\\\n            request_keyboard(callback, target, input_type)\n        self._win.show_keyboard()\n        Clock.schedule_interval(self._check_keyboard_shown, 1 / 5.)\n        return self._sdl_keyboard\n\n    def release_keyboard(self, *largs):\n        super(WindowSDL, self).release_keyboard(*largs)\n        self._win.hide_keyboard()\n        self._sdl_keyboard = None\n        return True\n\n    def _check_keyboard_shown(self, dt):\n        if self._sdl_keyboard is None:\n            return False\n        if not self._win.is_keyboard_shown():\n            self._sdl_keyboard.release()\n\n"
  },
  {
    "path": "tickeys/kivy/data/glsl/default.fs",
    "content": "$HEADER$\nvoid main (void){\n    gl_FragColor = frag_color * texture2D(texture0, tex_coord0);\n}\n"
  },
  {
    "path": "tickeys/kivy/data/glsl/default.vs",
    "content": "$HEADER$\nvoid main (void) {\n  frag_color = color * vec4(1.0, 1.0, 1.0, opacity);\n  tex_coord0 = vTexCoords0;\n  gl_Position = projection_mat * modelview_mat * vec4(vPosition.xy, 0.0, 1.0);\n}\n"
  },
  {
    "path": "tickeys/kivy/data/glsl/header.fs",
    "content": "#ifdef GL_ES\n    precision highp float;\n#endif\n\n/* Outputs from the vertex shader */\nvarying vec4 frag_color;\nvarying vec2 tex_coord0;\n\n/* uniform texture samplers */\nuniform sampler2D texture0;\n"
  },
  {
    "path": "tickeys/kivy/data/glsl/header.vs",
    "content": "#ifdef GL_ES\n    precision highp float;\n#endif\n\n/* Outputs to the fragment shader */\nvarying vec4 frag_color;\nvarying vec2 tex_coord0;\n\n/* vertex attributes */\nattribute vec2     vPosition;\nattribute vec2     vTexCoords0;\n\n/* uniform variables */\nuniform mat4       modelview_mat;\nuniform mat4       projection_mat;\nuniform vec4       color;\nuniform float      opacity;\n"
  },
  {
    "path": "tickeys/kivy/data/images/defaulttheme.atlas",
    "content": "{\"defaulttheme-0.png\": {\"progressbar_background\": [391, 227, 24, 24], \"tab_btn_disabled\": [264, 137, 32, 32], \"tab_btn_pressed\": [366, 137, 32, 32], \"image-missing\": [152, 171, 48, 48], \"splitter_h\": [174, 123, 32, 7], \"splitter_down\": [501, 253, 7, 32], \"splitter_disabled_down\": [503, 291, 7, 32], \"vkeyboard_key_down\": [468, 137, 32, 32], \"vkeyboard_disabled_key_down\": [400, 137, 32, 32], \"selector_right\": [248, 223, 55, 62], \"player-background\": [2, 287, 103, 103], \"selector_middle\": [191, 223, 55, 62], \"spinner\": [235, 82, 29, 37], \"tab_btn_disabled_pressed\": [298, 137, 32, 32], \"switch-button_disabled\": [277, 291, 43, 32], \"textinput_disabled_active\": [372, 326, 64, 64], \"splitter_grip\": [36, 50, 12, 26], \"vkeyboard_key_normal\": [2, 44, 32, 32], \"button_disabled\": [80, 82, 29, 37], \"media-playback-stop\": [302, 171, 48, 48], \"splitter\": [501, 87, 7, 32], \"splitter_down_h\": [140, 123, 32, 7], \"sliderh_background_disabled\": [72, 132, 41, 37], \"modalview-background\": [464, 456, 45, 54], \"button\": [142, 82, 29, 37], \"splitter_disabled\": [502, 137, 7, 32], \"checkbox_radio_disabled_on\": [433, 87, 32, 32], \"slider_cursor\": [402, 171, 48, 48], \"vkeyboard_disabled_background\": [68, 221, 64, 64], \"checkbox_disabled_on\": [297, 87, 32, 32], \"sliderv_background_disabled\": [2, 78, 37, 41], \"button_disabled_pressed\": [111, 82, 29, 37], \"audio-volume-muted\": [102, 171, 48, 48], \"close\": [417, 231, 20, 20], \"action_group_disabled\": [452, 171, 33, 48], \"vkeyboard_background\": [2, 221, 64, 64], \"checkbox_off\": [331, 87, 32, 32], \"tab_disabled\": [305, 253, 96, 32], \"sliderh_background\": [115, 132, 41, 37], \"switch-button\": [322, 291, 43, 32], \"tree_closed\": [439, 231, 20, 20], \"bubble_btn_pressed\": [435, 291, 32, 32], \"selector_left\": [134, 223, 55, 62], \"filechooser_file\": [174, 326, 64, 64], \"checkbox_radio_disabled_off\": [399, 87, 32, 32], \"checkbox_radio_on\": [196, 137, 32, 32], \"checkbox_on\": [365, 87, 32, 32], \"button_pressed\": [173, 82, 29, 37], \"audio-volume-high\": [464, 406, 48, 48], \"audio-volume-low\": [2, 171, 48, 48], \"progressbar\": [305, 227, 32, 24], \"previous_normal\": [487, 187, 19, 32], \"separator\": [504, 342, 5, 48], \"filechooser_folder\": [240, 326, 64, 64], \"checkbox_radio_off\": [467, 87, 32, 32], \"textinput_active\": [306, 326, 64, 64], \"textinput\": [438, 326, 64, 64], \"player-play-overlay\": [122, 395, 117, 115], \"media-playback-pause\": [202, 171, 48, 48], \"sliderv_background\": [41, 78, 37, 41], \"ring\": [354, 402, 108, 108], \"bubble_arrow\": [487, 175, 16, 10], \"slider_cursor_disabled\": [352, 171, 48, 48], \"checkbox_disabled_off\": [469, 291, 32, 32], \"action_group_down\": [2, 121, 33, 48], \"spinner_disabled\": [204, 82, 29, 37], \"splitter_disabled_h\": [106, 123, 32, 7], \"bubble\": [107, 325, 65, 65], \"media-playback-start\": [252, 171, 48, 48], \"vkeyboard_disabled_key_normal\": [434, 137, 32, 32], \"overflow\": [230, 137, 32, 32], \"tree_opened\": [461, 231, 20, 20], \"action_item\": [339, 227, 24, 24], \"bubble_btn\": [401, 291, 32, 32], \"audio-volume-medium\": [52, 171, 48, 48], \"action_group\": [37, 121, 33, 48], \"spinner_pressed\": [266, 82, 29, 37], \"filechooser_selected\": [2, 392, 118, 118], \"tab\": [403, 253, 96, 32], \"action_bar\": [158, 133, 36, 36], \"action_view\": [365, 227, 24, 24], \"tab_btn\": [332, 137, 32, 32], \"switch-background\": [192, 291, 83, 32], \"splitter_disabled_down_h\": [72, 123, 32, 7], \"action_item_down\": [367, 291, 32, 32], \"switch-background_disabled\": [107, 291, 83, 32], \"textinput_disabled\": [241, 399, 111, 111], \"splitter_grip_h\": [483, 239, 26, 12]}}"
  },
  {
    "path": "tickeys/kivy/data/keyboards/azerty.json",
    "content": "{\n    \"title\" : \"Azerty\",\n    \"description\" : \"A French keyboard without international keys\",\n    \"cols\" : 15,\n\t\"rows\": 5,\n    \"normal_1\" : [\n        [\"@\", \"@\", \"`\", 1],    [\"&\", \"&\", \"1\", 1],    [\"\\u00e9\", \"\\u00e9\", \"2\", 1],\n        [\"'\", \"'\", \"3\", 1],    [\"\\\"\", \"\\\"\", \"4\", 1],  [\"[\", \"[\", \"5\", 1],\n        [\"-\", \"-\", \"6\", 1],    [\"\\u00e8\", \"\\u00e8\", \"7\", 1],    [\"_\", \"_\", \"8\", 1],\n        [\"\\u00e7\", \"\\u00e7\", \"9\", 1],    [\"\\u00e0\", \"\\u00e0\", \"0\", 1],    [\"]\", \"]\", \"+\", 1],\n        [\"=\", \"=\", \"=\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"normal_2\" : [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"a\", \"a\", \"a\", 1],    [\"z\", \"z\", \"z\", 1],\n        [\"e\", \"e\", \"e\", 1],    [\"r\", \"r\", \"r\", 1],    [\"t\", \"t\", \"t\", 1],\n        [\"y\", \"y\", \"y\", 1],    [\"u\", \"u\", \"u\", 1],    [\"i\", \"i\", \"i\", 1],\n        [\"o\", \"o\", \"o\", 1],    [\"p\", \"p\", \"p\", 1],    [\"^\", \"^\", \"^\", 1],\n        [\"$\", \"$\", \"}\", 1],    [\"\\u23ce\", null, \"enter\", 1.5]\n    ],\n    \"normal_3\" : [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"q\", \"q\", \"q\", 1],    [\"s\", \"s\", \"s\", 1],\n        [\"d\", \"d\", \"d\", 1],    [\"f\", \"f\", \"f\", 1],    [\"g\", \"g\", \"g\", 1],\n        [\"h\", \"h\", \"h\", 1],    [\"j\", \"j\", \"j\", 1],    [\"k\", \"k\", \"k\", 1],\n        [\"l\", \"l\", \"l\", 1],    [\"m\", \"m\", \"m\", 1],    [\"\\u00f9\", \"\\u00f9\", \"%\", 1],\n        [\"*\", \"*\", \"*\", 1],    [\"\\u23ce\", null, \"enter\", 1.2]\n    ],\n    \"normal_4\" : [\n        [\"\\u21e7\", null, \"shift\", 1.5],  [\"<\", \"<\", null, 1],    [\"w\", \"w\", null, 1],\n        [\"x\", \"x\", null, 1],\n        [\"c\", \"c\", null, 1],    [\"v\", \"v\", null, 1],    [\"b\", \"b\", null, 1],\n        [\"n\", \"n\", null, 1],    [\",\", \",\", null, 1],    [\";\", \";\", null, 1],\n        [\":\", \":\", null, 1],    [\"!\", \"!\", null, 1],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"normal_5\" : [\n        [\" \", \" \", \"spacebar\", 12], [\"\\u2b12\", null, \"layout\", 1.5], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ],\n    \"shift_1\" : [\n        [\"|\", \"|\", \"|\", 1],    [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],\n        [\"3\", \"3\", \"3\", 1],    [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],\n        [\"6\", \"6\", \"6\", 1],    [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],\n        [\"9\", \"9\", \"9\", 1],    [\"0\", \"0\", \"0\", 1],    [\"#\", \"#\", \"#\", 1],\n        [\"+\", \"+\", \"+\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"shift_2\" : [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"A\", \"A\", \"a\", 1],    [\"Z\", \"Z\", null, 1],\n        [\"E\", \"E\", \"e\", 1],    [\"R\", \"R\", \"r\", 1],    [\"T\", \"T\", \"t\", 1],\n        [\"Y\", \"Y\", \"y\", 1],    [\"U\", \"U\", \"u\", 1],    [\"I\", \"I\", \"i\", 1],\n        [\"O\", \"O\", \"o\", 1],    [\"P\", \"P\", \"p\", 1],    [\"[\", \"[\", \"[\", 1],\n        [\"]\", \"]\", \"]\", 1],    [\"\\u23ce\", null, \"enter\", 1.5]\n    ],\n    \"shift_3\" : [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"Q\", \"Q\", \"q\", 1],    [\"S\", \"S\", \"s\", 1],\n        [\"D\", \"D\", \"d\", 1],    [\"F\", \"F\", \"f\", 1],    [\"G\", \"G\", \"g\", 1],\n        [\"H\", \"H\", \"h\", 1],    [\"J\", \"J\", \"j\", 1],    [\"K\", \"K\", \"k\", 1],\n        [\"L\", \"L\", \"l\", 1],    [\"M\", \"M\", \"m\", 1],    [\"%\", \"%\", \"%\", 1],\n        [\"\\u00b5\", \"\\u00b5\", \"*\", 1],    [\"\\u23ce\", null, \"enter\", 1.2]\n    ],\n    \"shift_4\" : [\n        [\"\\u21e7\", null, \"shift\", 1.5],  [\">\", \">\", \">\", 1],    [\"W\", \"W\", \"w\", 1],\n        [\"X\", \"X\", \"x\", 1],    [\"C\", \"C\", \"c\", 1],    [\"V\", \"V\", \"v\", 1],\n        [\"B\", \"B\", \"b\", 1],    [\"N\", \"N\", \"n\", 1],    [\"?\", \"?\", \"?\", 1],\n        [\".\", \".\", \".\", 1],    [\"/\", \"/\", \"/\", 1],    [\"\\u00a7\", \"\\u00a7\", \"!\", 1],\n        [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"shift_5\" : [\n        [\" \", \" \", \"spacebar\", 12], [\"\\u2b12\", null, \"layout\", 1.5], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ]\n}\n"
  },
  {
    "path": "tickeys/kivy/data/keyboards/de_CH.json",
    "content": "{\n    \"title\": \"de_CH\",\n    \"description\": \"A Swiss German keyboard, touch optimized (no shift+caps lock)\",\n\t\"cols\": 15,\n    \"rows\": 5,\n    \"normal_1\": [\n        [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],    [\"3\", \"3\", \"3\", 1],\n        [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],    [\"6\", \"6\", \"6\", 1],\n        [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],    [\"9\", \"9\", \"9\", 1],\n        [\"0\", \"0\", \"0\", 1],    [\"@\", \"@\", \"@\", 1],    [\"?\", \"?\", \"?\", 1],\n        [\"!\", \"!\", \"!\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"normal_2\" : [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"q\", \"q\", \"q\", 1],    [\"w\", \"w\", \"w\", 1],\n        [\"e\", \"e\", \"e\", 1],    [\"r\", \"r\", \"r\", 1],    [\"t\", \"t\", \"t\", 1],\n        [\"z\", \"z\", \"z\", 1],    [\"u\", \"u\", \"u\", 1],    [\"i\", \"i\", \"i\", 1],\n        [\"o\", \"o\", \"o\", 1],    [\"p\", \"p\", \"p\", 1],    [\"ü\", \"ü\", \"ü\", 1],\n        [\":\", \":\", \":\", 1],    [\"$\", \"$\", \"$\", 1.5]\n    ],\n    \"normal_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"a\", \"a\", \"a\", 1],    [\"s\", \"s\", \"s\", 1],\n        [\"d\", \"d\", \"d\", 1],    [\"f\", \"f\", \"f\", 1],    [\"g\", \"g\", \"g\", 1],\n        [\"h\", \"h\", \"h\", 1],    [\"j\", \"j\", \"j\", 1],    [\"k\", \"k\", \"k\", 1],\n        [\"l\", \"l\", \"l\", 1],    [\"ö\", \"ö\", \"ö\", 1],    [\"ä\", \"ä\", \"ä\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"normal_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"y\", \"y\", \"y\", 1],    [\"x\", \"x\", \"x\", 1],\n        [\"c\", \"c\", \"c\", 1],    [\"v\", \"v\", \"v\", 1],    [\"b\", \"b\", \"b\", 1],\n        [\"n\", \"n\", \"n\", 1],    [\"m\", \"m\", \"m\", 1],    [\",\", \",\", \",\", 1],\n        [\".\", \".\", \".\", 1],    [\"-\", \"-\", \"-\", 1],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"normal_5\": [\n        [\"#+=\", null, \"special\", 2.5], [\" \", \" \", \"spacebar\", 11], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ],\n\n    \"shift_1\": [\n        [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],    [\"3\", \"3\", \"3\", 1],\n        [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],    [\"6\", \"6\", \"6\", 1],\n        [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],    [\"9\", \"9\", \"9\", 1],\n        [\"0\", \"0\", \"0\", 1],    [\"@\", \"@\", \"@\", 1],    [\"?\", \"?\", \"?\", 1],\n        [\"!\", \"!\", \"!\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"shift_2\": [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"Q\", \"Q\", null, 1],    [\"W\", \"W\", null, 1],\n        [\"E\", \"E\", \"e\", 1],    [\"R\", \"R\", \"r\", 1],    [\"T\", \"T\", \"t\", 1],\n        [\"Z\", \"Z\", \"z\", 1],    [\"U\", \"U\", \"u\", 1],    [\"I\", \"I\", \"i\", 1],\n        [\"O\", \"O\", \"o\", 1],    [\"P\", \"P\", \"p\", 1],    [\"Ü\", \"Ü\", \"Ü\", 1],\n        [\":\", \":\", \":\", 1],    [\"/\", \"/\", \"/\", 1.5]\n    ],\n    \"shift_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"A\", \"A\", \"a\", 1],    [\"S\", \"S\", \"s\", 1],\n        [\"D\", \"D\", \"d\", 1],    [\"F\", \"F\", \"f\", 1],    [\"G\", \"G\", \"g\", 1],\n        [\"H\", \"H\", \"h\", 1],    [\"J\", \"J\", \"j\", 1],    [\"K\", \"K\", \"k\", 1],\n        [\"L\", \"L\", \"l\", 1],    [\"Ö\", \"Ö\", \"Ö\", 1],    [\"Ä\", \"Ä\", \"Ä\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"shift_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"Y\", \"Y\", \"y\", 1],  [\"X\", \"X\", \"x\", 1],\n        [\"C\", \"C\", \"c\", 1],    [\"V\", \"V\", \"v\", 1],    [\"B\", \"B\", \"b\", 1],\n        [\"N\", \"N\", \"n\", 1],    [\"M\", \"M\", \"m\", 1],    [\";\", \";\", \";\", 1],\n        [\":\", \":\", \":\", 1],    [\"_\", \"_\", \"_\", 1],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"shift_5\": [\n        [\"#+=\", null, \"special\", 2.5], [\" \", \" \", \"spacebar\", 11], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ],\n\n    \"special_1\": [\n        [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],    [\"3\", \"3\", \"3\", 1],\n        [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],    [\"6\", \"6\", \"6\", 1],\n        [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],    [\"9\", \"9\", \"9\", 1],\n        [\"0\", \"0\", \"0\", 1],    [\"@\", \"@\", \"@\", 1],    [\"?\", \"?\", \"?\", 1],\n        [\"!\", \"!\", \"!\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"special_2\": [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"(\", \"(\", \"(\", 1],    [\")\", \")\", \")\", 1],\n        [\"{\", \"{\", \"{\", 1],    [\"}\", \"}\", \"}\", 1],    [\"[\", \"[\", \"[\", 1],\n        [\"]\", \"]\", \"]\", 1],    [\"€\", \"€\", \"€\", 1],    [\"$\", \"$\", \"$\", 1],\n        [\"£\", \"£\", \"£\", 1],    [\"¥\", \"¥\", \"¥\", 1],    [\"è\", \"è\", \"è\", 1],\n        [\"•\", \"•\", \"•\", 1],    [\"|\", \"|\", \"|\", 1.5]\n    ],\n    \"special_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"“\", \"“\", \"“\", 1],    [\"`\", \"`\", \"`\", 1],\n        [\"«\", \"«\", \"«\", 1],    [\"»\", \"»\", \"»\", 1],    [\"#\", \"#\", \"#\", 1],\n        [\"%\", \"%\", \"%\", 1],    [\"^\", \"^\", \"^\", 1],    [\"°\", \"°\", \"°\", 1],\n        [\"&\", \"&\", \"&\", 1],    [\"é\", \"é\", \"é\", 1],    [\"à\", \"à\", \"à\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"special_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"+\", \"+\", \"+\", 1],  [\"=\", \"=\", \"=\", 1],\n        [\"<\", \"<\", \"<\", 1],    [\">\", \">\", \">\", 1],    [\"*\", \"*\", \"*\", 1],\n        [\"È\", \"È\", \"È\", 1],    [\"É\", \"É\", \"É\", 1],    [\"À\", \"À\", \"À\", 1],\n        [\":\", \":\", \":\", 1],    [\"_\", \"_\", \"_\", 1],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"special_5\": [\n        [\"#+=\", null, \"special\", 2.5], [\" \", \" \", \"spacebar\", 11], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ]\n}\n"
  },
  {
    "path": "tickeys/kivy/data/keyboards/en_US.json",
    "content": "{\n    \"title\": \"en_US\",\n    \"description\": \"A US Keyboard, touch optimized (no shift+caps lock)\",\n\t\"cols\": 15,\n    \"rows\": 5,\n    \"normal_1\": [\n        [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],    [\"3\", \"3\", \"3\", 1],\n        [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],    [\"6\", \"6\", \"6\", 1],\n        [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],    [\"9\", \"9\", \"9\", 1],\n        [\"0\", \"0\", \"0\", 1],    [\"@\", \"@\", \"@\", 1],    [\"?\", \"?\", \"?\", 1],\n        [\"!\", \"!\", \"!\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"normal_2\" : [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"q\", \"q\", \"q\", 1],    [\"w\", \"w\", \"w\", 1],\n        [\"e\", \"e\", \"e\", 1],    [\"r\", \"r\", \"r\", 1],    [\"t\", \"t\", \"t\", 1],\n        [\"y\", \"y\", \"y\", 1],    [\"u\", \"u\", \"u\", 1],    [\"i\", \"i\", \"i\", 1],\n        [\"o\", \"o\", \"o\", 1],    [\"p\", \"p\", \"p\", 1],    [\"[\", \"[\", \"[\", 1],\n        [\"]\", \"]\", \"]\", 1],    [\"\\\\\", \"\\\\\", \"\\\\\", 1.5]\n    ],\n    \"normal_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"a\", \"a\", \"a\", 1],    [\"s\", \"s\", \"s\", 1],\n        [\"d\", \"d\", \"d\", 1],    [\"f\", \"f\", \"f\", 1],    [\"g\", \"g\", \"g\", 1],\n        [\"h\", \"h\", \"h\", 1],    [\"j\", \"j\", \"j\", 1],    [\"k\", \"k\", \"k\", 1],\n        [\"l\", \"l\", \"l\", 1],    [\";\", \";\", \";\", 1],    [\"'\", \"'\", \"'\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"normal_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"z\", \"z\", \"z\", 1],    [\"x\", \"x\", \"x\", 1],\n        [\"c\", \"c\", \"c\", 1],    [\"v\", \"v\", \"v\", 1],    [\"b\", \"b\", \"b\", 1],\n        [\"n\", \"n\", \"n\", 1],    [\"m\", \"m\", \"m\", 1],    [\",\", \",\", \",\", 1],\n        [\".\", \".\", \".\", 1],    [\"/\", \"/\", \"/\", 1],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"normal_5\": [\n        [\"#+=\", null, \"special\", 2.5], [\" \", \" \", \"spacebar\", 11], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ],\n\n    \"shift_1\": [\n        [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],    [\"3\", \"3\", \"3\", 1],\n        [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],    [\"6\", \"6\", \"6\", 1],\n        [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],    [\"9\", \"9\", \"9\", 1],\n        [\"0\", \"0\", \"0\", 1],    [\"@\", \"@\", \"@\", 1],    [\"?\", \"?\", \"?\", 1],\n        [\"!\", \"!\", \"!\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"shift_2\": [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"Q\", \"Q\", null, 1],    [\"W\", \"W\", null, 1],\n        [\"E\", \"E\", \"e\", 1],    [\"R\", \"R\", \"r\", 1],    [\"T\", \"T\", \"t\", 1],\n        [\"Y\", \"Y\", \"y\", 1],    [\"U\", \"U\", \"u\", 1],    [\"I\", \"I\", \"i\", 1],\n        [\"O\", \"O\", \"o\", 1],    [\"P\", \"P\", \"p\", 1],    [\"{\", \"{\", \"{\", 1],\n        [\"}\", \"}\", \"}\", 1],    [\"|\", \"|\", \"|\", 1.5]\n    ],\n    \"shift_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"A\", \"A\", \"a\", 1],    [\"S\", \"S\", \"s\", 1],\n        [\"D\", \"D\", \"d\", 1],    [\"F\", \"F\", \"f\", 1],    [\"G\", \"G\", \"g\", 1],\n        [\"H\", \"H\", \"h\", 1],    [\"J\", \"J\", \"j\", 1],    [\"K\", \"K\", \"k\", 1],\n        [\"L\", \"L\", \"l\", 1],    [\":\", \":\", \":\", 1],    [\"\\\"\", \"\\\"\", \"\\\"\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"shift_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"Z\", \"Z\", \"z\", 1],  [\"X\", \"X\", \"x\", 1],\n        [\"C\", \"C\", \"c\", 1],    [\"V\", \"V\", \"v\", 1],    [\"B\", \"B\", \"b\", 1],\n        [\"N\", \"N\", \"n\", 1],    [\"M\", \"M\", \"m\", 1],    [\"<\", \"<\", \"<\", 1],\n        [\">\", \">\", \">\", 1],    [\"?\", \"?\", \"?\", 1],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"shift_5\": [\n        [\"#+=\", null, \"special\", 2.5], [\" \", \" \", \"spacebar\", 11], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ],\n\n    \"special_1\": [\n        [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],    [\"3\", \"3\", \"3\", 1],\n        [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],    [\"6\", \"6\", \"6\", 1],\n        [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],    [\"9\", \"9\", \"9\", 1],\n        [\"0\", \"0\", \"0\", 1],    [\"@\", \"@\", \"@\", 1],    [\"?\", \"?\", \"?\", 1],\n        [\"!\", \"!\", \"!\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"special_2\": [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"(\", \"(\", \"(\", 1],    [\")\", \")\", \")\", 1],\n        [\"{\", \"{\", \"{\", 1],    [\"}\", \"}\", \"}\", 1],    [\"[\", \"[\", \"[\", 1],\n        [\"]\", \"]\", \"]\", 1],    [\"€\", \"€\", \"€\", 1],    [\"$\", \"$\", \"$\", 1],\n        [\"£\", \"£\", \"£\", 1],    [\"¥\", \"¥\", \"¥\", 1],    [\"˘\", \"˘\", \"˘\", 1],\n        [\"•\", \"•\", \"•\", 1],    [\"|\", \"|\", \"|\", 1.5]\n    ],\n    \"special_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"“\", \"“\", \"“\", 1],    [\"`\", \"`\", \"`\", 1],\n        [\"«\", \"«\", \"«\", 1],    [\"»\", \"»\", \"»\", 1],    [\"#\", \"#\", \"#\", 1],\n        [\"%\", \"%\", \"%\", 1],    [\"^\", \"^\", \"^\", 1],    [\"°\", \"°\", \"°\", 1],\n        [\"&\", \"&\", \"&\", 1],    [\"ÿ\", \"ÿ\", \"ÿ\", 1],    [\"Æ\", \"Æ\", \"Æ\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"special_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"+\", \"+\", \"+\", 1],  [\"=\", \"=\", \"=\", 1],\n        [\"<\", \"<\", \"<\", 1],    [\">\", \">\", \">\", 1],    [\"*\", \"*\", \"*\", 1],\n        [\"Ù\", \"Ù\", \"Ù\", 1],    [\"~\", \"~\", \"~\", 1],    [\"À\", \"À\", \"À\", 1],\n        [\":\", \":\", \":\", 1],    [\"_\", \"_\", \"_\", 1],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"special_5\": [\n        [\"#+=\", null, \"special\", 2.5], [\" \", \" \", \"spacebar\", 11], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ]\n}\n"
  },
  {
    "path": "tickeys/kivy/data/keyboards/fr_CH.json",
    "content": "{\n    \"title\": \"fr_CH\",\n    \"description\": \"A Swiss French keyboard, touch optimized (no shift+caps lock)\",\n\t\"cols\": 15,\n    \"rows\": 5,\n    \"normal_1\": [\n        [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],    [\"3\", \"3\", \"3\", 1],\n        [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],    [\"6\", \"6\", \"6\", 1],\n        [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],    [\"9\", \"9\", \"9\", 1],\n        [\"0\", \"0\", \"0\", 1],    [\"@\", \"@\", \"@\", 1],    [\"?\", \"?\", \"?\", 1],\n        [\"!\", \"!\", \"!\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"normal_2\" : [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"q\", \"q\", \"q\", 1],    [\"w\", \"w\", \"w\", 1],\n        [\"e\", \"e\", \"e\", 1],    [\"r\", \"r\", \"r\", 1],    [\"t\", \"t\", \"t\", 1],\n        [\"z\", \"z\", \"z\", 1],    [\"u\", \"u\", \"u\", 1],    [\"i\", \"i\", \"i\", 1],\n        [\"o\", \"o\", \"o\", 1],    [\"p\", \"p\", \"p\", 1],    [\"è\", \"è\", \"è\", 1],\n        [\":\", \":\", \":\", 1],    [\"$\", \"$\", \"$\", 1.5]\n    ],\n    \"normal_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"a\", \"a\", \"a\", 1],    [\"s\", \"s\", \"s\", 1],\n        [\"d\", \"d\", \"d\", 1],    [\"f\", \"f\", \"f\", 1],    [\"g\", \"g\", \"g\", 1],\n        [\"h\", \"h\", \"h\", 1],    [\"j\", \"j\", \"j\", 1],    [\"k\", \"k\", \"k\", 1],\n        [\"l\", \"l\", \"l\", 1],    [\"é\", \"é\", \"é\", 1],    [\"à\", \"à\", \"à\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"normal_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"y\", \"y\", \"y\", 1],    [\"x\", \"x\", \"x\", 1],\n        [\"c\", \"c\", \"c\", 1],    [\"v\", \"v\", \"v\", 1],    [\"b\", \"b\", \"b\", 1],\n        [\"n\", \"n\", \"n\", 1],    [\"m\", \"m\", \"m\", 1],    [\",\", \",\", \",\", 1],\n        [\".\", \".\", \".\", 1],    [\"-\", \"-\", \"-\", 1],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"normal_5\": [\n        [\"#+=\", null, \"special\", 2.5], [\" \", \" \", \"spacebar\", 11], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ],\n\n    \"shift_1\": [\n        [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],    [\"3\", \"3\", \"3\", 1],\n        [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],    [\"6\", \"6\", \"6\", 1],\n        [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],    [\"9\", \"9\", \"9\", 1],\n        [\"0\", \"0\", \"0\", 1],    [\"@\", \"@\", \"@\", 1],    [\"?\", \"?\", \"?\", 1],\n        [\"!\", \"!\", \"!\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"shift_2\": [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"Q\", \"Q\", null, 1],    [\"W\", \"W\", null, 1],\n        [\"E\", \"E\", \"e\", 1],    [\"R\", \"R\", \"r\", 1],    [\"T\", \"T\", \"t\", 1],\n        [\"Z\", \"Z\", \"z\", 1],    [\"U\", \"U\", \"u\", 1],    [\"I\", \"I\", \"i\", 1],\n        [\"O\", \"O\", \"o\", 1],    [\"P\", \"P\", \"p\", 1],    [\"È\", \"È\", \"È\", 1],\n        [\":\", \":\", \":\", 1],    [\"/\", \"/\", \"/\", 1.5]\n    ],\n    \"shift_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"A\", \"A\", \"a\", 1],    [\"S\", \"S\", \"s\", 1],\n        [\"D\", \"D\", \"d\", 1],    [\"F\", \"F\", \"f\", 1],    [\"G\", \"G\", \"g\", 1],\n        [\"H\", \"H\", \"h\", 1],    [\"J\", \"J\", \"j\", 1],    [\"K\", \"K\", \"k\", 1],\n        [\"L\", \"L\", \"l\", 1],    [\"É\", \"É\", \"É\", 1],    [\"À\", \"À\", \"À\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"shift_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"Y\", \"Y\", \"y\", 1],  [\"X\", \"X\", \"x\", 1],\n        [\"C\", \"C\", \"c\", 1],    [\"V\", \"V\", \"v\", 1],    [\"B\", \"B\", \"b\", 1],\n        [\"N\", \"N\", \"n\", 1],    [\"M\", \"M\", \"m\", 1],    [\";\", \";\", \";\", 1],\n        [\":\", \":\", \":\", 1],    [\"_\", \"_\", \"_\", 1],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"shift_5\": [\n        [\"#+=\", null, \"special\", 2.5], [\" \", \" \", \"spacebar\", 11], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ],\n\n    \"special_1\": [\n        [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],    [\"3\", \"3\", \"3\", 1],\n        [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],    [\"6\", \"6\", \"6\", 1],\n        [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],    [\"9\", \"9\", \"9\", 1],\n        [\"0\", \"0\", \"0\", 1],    [\"@\", \"@\", \"@\", 1],    [\"?\", \"?\", \"?\", 1],\n        [\"!\", \"!\", \"!\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"special_2\": [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"(\", \"(\", \"(\", 1],    [\")\", \")\", \")\", 1],\n        [\"{\", \"{\", \"{\", 1],    [\"}\", \"}\", \"}\", 1],    [\"[\", \"[\", \"[\", 1],\n        [\"]\", \"]\", \"]\", 1],    [\"€\", \"€\", \"€\", 1],    [\"$\", \"$\", \"$\", 1],\n        [\"£\", \"£\", \"£\", 1],    [\"¥\", \"¥\", \"¥\", 1],    [\"ü\", \"ü\", \"ü\", 1],\n        [\"•\", \"•\", \"•\", 1],    [\"|\", \"|\", \"|\", 1.5]\n    ],\n    \"special_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"“\", \"“\", \"“\", 1],    [\"`\", \"`\", \"`\", 1],\n        [\"«\", \"«\", \"«\", 1],    [\"»\", \"»\", \"»\", 1],    [\"#\", \"#\", \"#\", 1],\n        [\"%\", \"%\", \"%\", 1],    [\"^\", \"^\", \"^\", 1],    [\"°\", \"°\", \"°\", 1],\n        [\"&\", \"&\", \"&\", 1],    [\"ö\", \"ö\", \"ö\", 1],    [\"ä\", \"ä\", \"ä\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"special_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"+\", \"+\", \"+\", 1],  [\"=\", \"=\", \"=\", 1],\n        [\"<\", \"<\", \"<\", 1],    [\">\", \">\", \">\", 1],    [\"*\", \"*\", \"*\", 1],\n        [\"Ö\", \"Ö\", \"Ö\", 1],    [\"Ä\", \"Ä\", \"Ä\", 1],    [\"Ü\", \"Ü\", \"Ü\", 1],\n        [\":\", \":\", \":\", 1],    [\"_\", \"_\", \"_\", 1],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"special_5\": [\n        [\"#+=\", null, \"special\", 2.5], [\" \", \" \", \"spacebar\", 11], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ]\n}\n"
  },
  {
    "path": "tickeys/kivy/data/keyboards/qwerty.json",
    "content": "{\n    \"title\": \"Qwerty\",\n    \"description\": \"A classical US Keyboard\",\n\t\"cols\": 15,\n    \"rows\": 5,\n    \"normal_1\": [\n        [\"`\", \"`\", \"`\", 1],    [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],\n        [\"3\", \"3\", \"3\", 1],    [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],\n        [\"6\", \"6\", \"6\", 1],    [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],\n        [\"9\", \"9\", \"9\", 1],    [\"0\", \"0\", \"0\", 1],    [\"-\", \"-\", \"-\", 1],\n        [\"=\", \"=\", \"=\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"normal_2\" : [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"q\", \"q\", \"q\", 1],    [\"w\", \"w\", \"w\", 1],\n        [\"e\", \"e\", \"e\", 1],    [\"r\", \"r\", \"r\", 1],    [\"t\", \"t\", \"t\", 1],\n        [\"y\", \"y\", \"y\", 1],    [\"u\", \"u\", \"u\", 1],    [\"i\", \"i\", \"i\", 1],\n        [\"o\", \"o\", \"o\", 1],    [\"p\", \"p\", \"p\", 1],    [\"[\", \"[\", \"[\", 1],\n        [\"]\", \"]\", \"j\", 1],    [\"\\\\\", \"\\\\\", \"\\\\\", 1]\n    ],\n    \"normal_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"a\", \"a\", \"a\", 1],    [\"s\", \"s\", \"s\", 1],\n        [\"d\", \"d\", \"d\", 1],    [\"f\", \"f\", \"f\", 1],    [\"g\", \"g\", \"g\", 1],\n        [\"h\", \"h\", \"h\", 1],    [\"j\", \"j\", \"j\", 1],    [\"k\", \"k\", \"k\", 1],\n        [\"l\", \"l\", \"l\", 1],    [\":\", \":\", \":\", 1],    [\"'\", \"'\", \"'\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"normal_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"z\", \"z\", null, 1],    [\"x\", \"x\", \"x\", 1],\n        [\"c\", \"c\", \"c\", 1],    [\"v\", \"v\", \"v\", 1],    [\"b\", \"b\", \"b\", 1],\n        [\"n\", \"n\", \"n\", 1],    [\"m\", \"m\", \"m\", 1],    [\",\", \",\", \",\", 1],\n        [\".\", \".\", \".\", 1],    [\"/\", \"/\", \"/\", 1],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"normal_5\": [\n        [\" \", \" \", \"spacebar\", 12], [\"\\u2b12\", null, \"layout\", 1.5], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ],\n    \"shift_1\": [\n        [\"~\", \"~\", \"~\", 1],    [\"!\", \"!\", \"!\", 1],    [\"@\", \"@\", \"@\", 1],\n        [\"#\", \"#\", \"#\", 1],    [\"$\", \"$\", \"$\", 1],    [\"%\", \"%\", \"%\", 1],\n        [\"^\", \"^\", null, 1],   [\"&\", \"&\", \"&\", 1],    [\"*\", \"*\", \"*\", 1],\n        [\"(\", \"(\", \"(\", 1],    [\")\", \")\", \")\", 1],    [\"_\", \"_\", \"_\", 1],\n        [\"+\", \"+\", \"+\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"shift_2\": [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"Q\", \"Q\", null, 1],    [\"W\", \"W\", null, 1],\n        [\"E\", \"E\", \"e\", 1],    [\"R\", \"R\", \"r\", 1],    [\"T\", \"T\", \"t\", 1],\n        [\"Y\", \"Y\", \"y\", 1],    [\"U\", \"U\", \"u\", 1],    [\"I\", \"I\", \"i\", 1],\n        [\"O\", \"O\", \"o\", 1],    [\"P\", \"P\", \"p\", 1],    [\"{\", \"{\", \"{\", 1],\n        [\"}\", \"}\", \"}\", 1],    [\"|\", \"|\", \"|\", 1.5]\n    ],\n    \"shift_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"A\", \"A\", \"a\", 1],    [\"S\", \"S\", \"s\", 1],\n        [\"D\", \"D\", \"d\", 1],    [\"F\", \"F\", \"f\", 1],    [\"G\", \"G\", \"g\", 1],\n        [\"H\", \"H\", \"h\", 1],    [\"J\", \"J\", \"j\", 1],    [\"K\", \"K\", \"k\", 1],\n        [\"L\", \"L\", \"l\", 1],    [\";\", \";\", \";\", 1],    [\"\\\"\", \"\\\"\", \"\\\"\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"shift_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"Z\", \"Z\", \"z\", 1],    [\"X\", \"X\", \"x\", 1],\n        [\"C\", \"C\", \"c\", 1],    [\"V\", \"V\", \"v\", 1],    [\"B\", \"B\", \"b\", 1],\n        [\"N\", \"N\", \"n\", 1],    [\"M\", \"M\", \"m\", 1],    [\"<\", \"<\", \"<\", 1],\n        [\">\", \">\", \">\", 1],    [\"?\", \"?\", \"?\", 1.5],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"shift_5\": [\n        [\" \", \" \", \"spacebar\", 12], [\"\\u2b12\", null, \"layout\", 1.5], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ]\n}\n"
  },
  {
    "path": "tickeys/kivy/data/keyboards/qwertz.json",
    "content": "{\n    \"title\": \"Qwerty\",\n    \"description\": \"A german Keyboard\",\n\t\"cols\": 15,\n    \"rows\": 5,\n    \"normal_1\": [\n        [\"!\", \"!\", \"!\", 1],    [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],\n        [\"3\", \"3\", \"3\", 1],    [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],\n        [\"6\", \"6\", \"6\", 1],    [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],\n        [\"9\", \"9\", \"9\", 1],    [\"0\", \"0\", \"0\", 1],    [\"ß\", \"ß\", \"ß\", 1],\n        [\"?\", \"?\", \"?\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"normal_2\" : [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"q\", \"q\", \"q\", 1],    [\"w\", \"w\", \"w\", 1],\n        [\"e\", \"e\", \"e\", 1],    [\"r\", \"r\", \"r\", 1],    [\"t\", \"t\", \"t\", 1],\n        [\"z\", \"z\", \"z\", 1],    [\"u\", \"u\", \"u\", 1],    [\"i\", \"i\", \"i\", 1],\n        [\"o\", \"o\", \"o\", 1],    [\"p\", \"p\", \"p\", 1],    [\"ü\", \"ü\", \"ü\", 1],\n        [\":\", \":\", \":\", 1],    [\"/\", \"/\", \"/\", 1]\n    ],\n    \"normal_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"a\", \"a\", \"a\", 1],    [\"s\", \"s\", \"s\", 1],\n        [\"d\", \"d\", \"d\", 1],    [\"f\", \"f\", \"f\", 1],    [\"g\", \"g\", \"g\", 1],\n        [\"h\", \"h\", \"h\", 1],    [\"j\", \"j\", \"j\", 1],    [\"k\", \"k\", \"k\", 1],\n        [\"l\", \"l\", \"l\", 1],    [\"ö\", \"ö\", \"ö\", 1],    [\"ä\", \"ä\", \"ä\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"normal_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"y\", \"y\", null, 1],    [\"x\", \"x\", \"x\", 1],\n        [\"c\", \"c\", \"c\", 1],    [\"v\", \"v\", \"v\", 1],    [\"b\", \"b\", \"b\", 1],\n        [\"n\", \"n\", \"n\", 1],    [\"m\", \"m\", \"m\", 1],    [\",\", \",\", \",\", 1],\n        [\".\", \".\", \".\", 1],    [\"-\", \"-\", \"-\", 1],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"normal_5\": [\n        [\" \", \" \", \"spacebar\", 12], [\"\\u2b12\", null, \"layout\", 1.5], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ],\n    \"shift_1\": [\n        [\"\\\"\", \"\\\"\", \"\\\"\", 1],    [\"+\", \"+\", \"+\", 1],    [\"@\", \"@\", \"@\", 1],\n        [\"#\", \"#\", \"#\", 1],    [\"$\", \"$\", \"$\", 1],    [\"€\", \"€\", \"€\", 1],\n        [\"%\", \"%\", \"%\", 1],   [\"&\", \"&\", \"&\", 1],    [\"*\", \"*\", \"*\", 1],\n        [\"(\", \"(\", \"(\", 1],    [\")\", \")\", \")\", 1],    [\"<\", \"<\", \"<\", 1],\n        [\">\", \">\", \">\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"shift_2\": [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"Q\", \"Q\", null, 1],    [\"W\", \"W\", null, 1],\n        [\"E\", \"E\", \"e\", 1],    [\"R\", \"R\", \"r\", 1],    [\"T\", \"T\", \"t\", 1],\n        [\"Z\", \"Z\", \"z\", 1],    [\"U\", \"U\", \"u\", 1],    [\"I\", \"I\", \"i\", 1],\n        [\"O\", \"O\", \"o\", 1],    [\"P\", \"P\", \"p\", 1],    [\"{\", \"{\", \"{\", 1],\n        [\"}\", \"}\", \"}\", 1],    [\"|\", \"|\", \"|\", 1.5]\n    ],\n    \"shift_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"A\", \"A\", \"a\", 1],    [\"S\", \"S\", \"s\", 1],\n        [\"D\", \"D\", \"d\", 1],    [\"F\", \"F\", \"f\", 1],    [\"G\", \"G\", \"g\", 1],\n        [\"H\", \"H\", \"h\", 1],    [\"J\", \"J\", \"j\", 1],    [\"K\", \"K\", \"k\", 1],\n        [\"L\", \"L\", \"l\", 1],    [\"=\", \"=\", \"=\", 1],    [\"°\", \"°\", \"°\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"shift_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"Y\", \"Y\", \"y\", 1],    [\"X\", \"X\", \"x\", 1],\n        [\"C\", \"C\", \"c\", 1],    [\"V\", \"V\", \"v\", 1],    [\"B\", \"B\", \"b\", 1],\n        [\"N\", \"N\", \"n\", 1],    [\"M\", \"M\", \"m\", 1],    [\";\", \";\", \";\", 1],\n        [\":\", \":\", \":\", 1],    [\"_\", \"_\", \"_\", 1.5],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"shift_5\": [\n        [\" \", \" \", \"spacebar\", 12], [\"\\u2b12\", null, \"layout\", 1.5], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ]\n}\n"
  },
  {
    "path": "tickeys/kivy/data/settings_kivy.json",
    "content": "[\n\t{\n\t\t\"type\": \"title\",\n\t\t\"title\": \"Windows\"\n\t},\n\t{\n\t\t\"type\": \"bool\",\n\t\t\"title\": \"Fullscreen\",\n\t\t\"desc\": \"Set the window in windowed or fullscreen\",\n\t\t\"section\": \"graphics\",\n\t\t\"key\": \"fullscreen\",\n\t\t\"values\": [\"0\", \"auto\"]\n\t},\n\t{\n\t\t\"type\": \"numeric\",\n\t\t\"title\": \"FPS Limit\",\n\t\t\"desc\": \"Maximum FPS limit if set, 0 for unlimited\",\n\t\t\"section\": \"graphics\",\n\t\t\"key\": \"maxfps\"\n\t},\n\t{\n\t\t\"type\": \"bool\",\n\t\t\"title\": \"Mouse cursor\",\n\t\t\"desc\": \"Show/hide the mouse cursor on the window\",\n\t\t\"section\": \"graphics\",\n\t\t\"key\": \"show_cursor\"\n\t},\n    {\n        \"type\": \"options\",\n        \"title\": \"Rotation\",\n        \"desc\": \"Rotation of the window\",\n        \"section\": \"graphics\",\n        \"key\": \"rotation\",\n        \"options\": [\"0\", \"90\", \"180\", \"270\"]\n    },\n\n\t{\n\t\t\"type\": \"title\",\n\t\t\"title\": \"Logging\"\n\t},\n\t{\n\t\t\"type\": \"bool\",\n\t\t\"title\": \"File logging\",\n\t\t\"desc\": \"If activated, the logging will be stored in a file\",\n\t\t\"section\": \"kivy\",\n\t\t\"key\": \"log_enable\"\n\t},\n\t{\n\t\t\"type\": \"options\",\n\t\t\"title\": \"Log level\",\n\t\t\"desc\": \"Level of logging information\",\n\t\t\"section\": \"kivy\",\n\t\t\"key\": \"log_level\",\n\t\t\"options\": [\"trace\", \"debug\", \"info\", \"warning\", \"error\", \"critical\"]\n\t},\n\n\t{\n\t\t\"type\": \"title\",\n\t\t\"title\": \"Keyboard\"\n\t},\n\t{\n\t\t\"type\": \"options\",\n\t\t\"title\": \"Keyboard mode\",\n\t\t\"desc\": \"Activate the usage of Kivy Virtual Keyboard\",\n\t\t\"section\": \"kivy\",\n\t\t\"key\": \"keyboard_mode\",\n\t\t\"options\": [\"system\", \"dock\", \"multi\", \"systemanddock\", \"systemandmulti\"]\n\t},\n\t{\n\t\t\"type\": \"options\",\n\t\t\"title\": \"Keyboard layout\",\n\t\t\"desc\": \"Select a layout for virtual keyboard\",\n\t\t\"section\": \"kivy\",\n\t\t\"key\": \"keyboard_layout\",\n\t\t\"options\": [\"qwerty\", \"azerty\", \"qwertz\", \"de_CH\", \"fr_CH\", \"en_US\"]\n\t},\n\n\t{\n\t\t\"type\": \"title\",\n\t\t\"title\": \"Input post-processing\"\n\t},\n\t{\n\t\t\"type\": \"numeric\",\n\t\t\"title\": \"Double tap distance\",\n\t\t\"desc\": \"Radius in pixels within a double tap is detected\",\n\t\t\"section\": \"postproc\",\n\t\t\"key\": \"double_tap_distance\"\n\t},\n\t{\n\t\t\"type\": \"numeric\",\n\t\t\"title\": \"Double tap time\",\n\t\t\"desc\": \"Time in milliseconds during a double tap is allowed\",\n\t\t\"section\": \"postproc\",\n\t\t\"key\": \"double_tap_time\"\n\t},\n\t{\n\t\t\"type\": \"numeric\",\n\t\t\"title\": \"Retain distance\",\n\t\t\"desc\": \"Maximum distance to retain the touch\",\n\t\t\"section\": \"postproc\",\n\t\t\"key\": \"retain_distance\"\n\t},\n\t{\n\t\t\"type\": \"numeric\",\n\t\t\"title\": \"Retain time\",\n\t\t\"desc\": \"Time in milliseconds during the touch will be retain\",\n\t\t\"section\": \"postproc\",\n\t\t\"key\": \"retain_distance\"\n\t},\n\t{\n\t\t\"type\": \"numeric\",\n\t\t\"title\": \"Jitter distance\",\n\t\t\"desc\": \"Radius in pixels within the touch moves will be ignored\",\n\t\t\"section\": \"postproc\",\n\t\t\"key\": \"jitter_distance\"\n\t}\n]\n"
  },
  {
    "path": "tickeys/kivy/data/style.kv",
    "content": "#:kivy 1.0\n\n<Label>:\n    canvas:\n        Color:\n            rgba: self.disabled_color if self.disabled else (self.color if not self.markup else (1, 1, 1, 1))\n        Rectangle:\n            texture: self.texture\n            size: self.texture_size\n            pos: int(self.center_x - self.texture_size[0] / 2.), int(self.center_y - self.texture_size[1] / 2.)\n\n<-Button,-ToggleButton>:\n    state_image: self.background_normal if self.state == 'normal' else self.background_down\n    disabled_image: self.background_disabled_normal if self.state == 'normal' else self.background_disabled_down\n    canvas:\n        Color:\n            rgba: self.background_color\n        BorderImage:\n            border: self.border\n            pos: self.pos\n            size: self.size\n            source: self.disabled_image if self.disabled else self.state_image\n        Color:\n            rgba: self.disabled_color if self.disabled else self.color\n        Rectangle:\n            texture: self.texture\n            size: self.texture_size\n            pos: int(self.center_x - self.texture_size[0] / 2.), int(self.center_y - self.texture_size[1] / 2.)\n\n<BubbleContent>\n    opacity: .7 if self.disabled else 1\n    rows: 1\n    canvas:\n        Color:\n            rgba: self.parent.background_color if self.parent else (1, 1, 1, 1)\n        BorderImage:\n            border: self.parent.border if self.parent else (16, 16, 16, 16)\n            texture: root.parent._bk_img.texture if root.parent else None\n            size: self.size\n            pos: self.pos\n\n<BubbleButton>:\n    background_normal: 'atlas://data/images/defaulttheme/bubble_btn'\n    background_down: 'atlas://data/images/defaulttheme/bubble_btn_pressed'\n    background_disabled_normal: 'atlas://data/images/defaulttheme/bubble_btn'\n    background_disabled_down: 'atlas://data/images/defaulttheme/bubble_btn_pressed'\n    border: (0, 0, 0, 0)\n\n<Slider>:\n    canvas:\n        Color:\n            rgb: 1, 1, 1\n        BorderImage:\n            border: (0, 18, 0, 18) if self.orientation == 'horizontal' else (18, 0, 18, 0)\n            pos: (self.x + self.padding, self.center_y - sp(18)) if self.orientation == 'horizontal' else (self.center_x - 18, self.y + self.padding)\n            size: (self.width - self.padding * 2, sp(36)) if self.orientation == 'horizontal' else (sp(36), self.height - self.padding * 2)\n            source: 'atlas://data/images/defaulttheme/slider{}_background{}'.format(self.orientation[0], '_disabled' if self.disabled else '')\n        Rectangle:\n            pos: (self.value_pos[0] - sp(16), self.center_y - sp(17)) if self.orientation == 'horizontal' else (self.center_x - (16), self.value_pos[1] - sp(16))\n            size: (sp(32), sp(32))\n            source: 'atlas://data/images/defaulttheme/slider_cursor{}'.format('_disabled' if self.disabled else '')\n\n<ProgressBar>:\n    canvas:\n        Color:\n            rgb: 1, 1, 1\n        BorderImage:\n            border: (12, 12, 12, 12)\n            pos: self.x, self.center_y - 12\n            size: self.width, 24\n            source: 'atlas://data/images/defaulttheme/progressbar_background'\n        BorderImage:\n            border: [int(min(self.width * (self.value / float(self.max)) if self.max else 0, 12))] * 4\n            pos: self.x, self.center_y - 12\n            size: self.width * (self.value / float(self.max)) if self.max else 0, 24\n            source: 'atlas://data/images/defaulttheme/progressbar'\n\n<SplitterStrip>:\n    border: self.parent.border if self.parent else (3, 3, 3, 3)\n    horizontal: '_h' if self.parent and self.parent.sizable_from[0] in  ('t', 'b') else ''\n    background_normal: 'atlas://data/images/defaulttheme/splitter{}{}'.format('_disabled' if self.disabled else '', self.horizontal)\n    background_down: 'atlas://data/images/defaulttheme/splitter_down{}{}'.format('_disabled' if self.disabled else '', self.horizontal)\n    Image:\n        pos: root.pos\n        size: root.size\n        allow_stretch: True\n        source: 'atlas://data/images/defaulttheme/splitter_grip' + root.horizontal\n\n<Scatter>:\n    canvas.before:\n        PushMatrix\n        MatrixInstruction:\n            matrix: self.transform\n    canvas.after:\n        PopMatrix\n\n\n<RelativeLayout>:\n    canvas.before:\n        PushMatrix\n        Translate:\n            xy: self.pos\n    canvas.after:\n        PopMatrix\n\n<Image,AsyncImage>:\n    canvas:\n        Color:\n            rgba: self.color\n        Rectangle:\n            texture: self.texture\n            size: self.norm_image_size\n            pos: self.center_x - self.norm_image_size[0] / 2., self.center_y - self.norm_image_size[1] / 2.\n\n<EffectWidget>:\n    canvas.before:\n        Translate:\n            xy: -self.x, -self.y\n    canvas:\n        Color:\n            rgba: 1, 1, 1, 1\n        Rectangle:\n            texture: self.texture\n            pos: self.pos\n            size: self.size\n\n<TabbedPanelContent>\n    rows: 1\n    padding: 3\n    canvas:\n        Color:\n            rgba: self.parent.background_color if self.parent else (1, 1, 1, 1)\n        BorderImage:\n            border: self.parent.border if self.parent else (16, 16, 16, 16)\n            source: (root.parent.background_disabled_image if self.disabled else root.parent.background_image) if root.parent else None\n            size: self.size\n            pos: self.pos\n\n<TabbedPanelStrip>\n    rows: 1\n\n<StripLayout>\n    padding: '2dp', '2dp', '2dp', '2dp'\n    canvas.before:\n        BorderImage:\n            pos: self.pos\n            size: self.size\n            border: root.border\n            source: root.background_image\n\n<TabbedPanelHeader>:\n    halign: 'center'\n    valign: 'middle'\n    background_normal: 'atlas://data/images/defaulttheme/tab_btn'\n    background_disabled_normal: 'atlas://data/images/defaulttheme/tab_btn_disabled'\n    background_down: 'atlas://data/images/defaulttheme/tab_btn_pressed'\n    background_disabled_down: 'atlas://data/images/defaulttheme/tab_btn_pressed'\n    border: (8, 8, 8, 8)\n    font_size: '15sp'\n\n<Selector>\n    allow_stretch: True\n\n<TextInput>:\n    canvas.before:\n        Color:\n            rgba: self.background_color\n        BorderImage:\n            border: self.border\n            pos: self.pos\n            size: self.size\n            source: (self.background_disabled_active if self.disabled else self.background_active) if self.focus else (self.background_disabled_normal if self.disabled else self.background_normal)\n        Color:\n            rgba: (self.cursor_color if self.focus and not self.cursor_blink else (0, 0, 0, 0))\n        Rectangle:\n            pos: [int(x) for x in self.cursor_pos]\n            size: 1, -self.line_height\n        Color:\n            rgba: self.disabled_foreground_color if self.disabled else (self.hint_text_color if not self.text and not self.focus else self.foreground_color)\n\n<TextInputCutCopyPaste>:\n    but_cut: cut.__self__\n    but_copy: copy.__self__\n    but_paste: paste.__self__\n    but_selectall: selectall.__self__\n\n    size_hint: None, None\n    size: '150sp', '50sp'\n    BubbleButton:\n        id: cut\n        text: 'Cut'\n        on_release: root.do('cut')\n    BubbleButton:\n        id: copy\n        text: 'Copy'\n        on_release: root.do('copy')\n    BubbleButton:\n        id: paste\n        text: 'Paste'\n        on_release: root.do('paste')\n    BubbleButton:\n        id: selectall\n        text: 'Select All'\n        on_release: root.do('selectall')\n\n<CodeInput>:\n    font_name: 'data/fonts/DroidSansMono.ttf'\n\n\n<TreeViewNode>:\n    canvas.before:\n        Color:\n            rgba: self.color_selected if self.is_selected else self.odd_color if self.odd else self.even_color\n        Rectangle:\n            pos: [self.parent.x, self.y] if self.parent else [0, 0]\n            size: [self.parent.width, self.height] if self.parent else [1, 1]\n        Color:\n            rgba: 1, 1, 1, int(not self.is_leaf)\n        Rectangle:\n            source: 'atlas://data/images/defaulttheme/tree_%s' % ('opened' if self.is_open else 'closed')\n            size: 16, 16\n            pos: self.x - 20, self.center_y - 8\n    canvas.after:\n        Color:\n            rgba: .5, .5, .5, .2\n        Line:\n            points: [self.parent.x, self.y, self.parent.right, self.y] if self.parent else []\n\n\n<TreeViewLabel>:\n    width: self.texture_size[0]\n    height: max(self.texture_size[1] + dp(10), dp(24))\n    text_size: self.width, None\n\n\n<StencilView>:\n    canvas.before:\n        StencilPush\n        Rectangle:\n            pos: self.pos\n            size: self.size\n        StencilUse\n\n    canvas.after:\n        StencilUnUse\n        Rectangle:\n            pos: self.pos\n            size: self.size\n        StencilPop\n\n\n<FileChooserListLayout>:\n    on_entry_added: treeview.add_node(args[1])\n    on_entries_cleared: treeview.root.nodes = []\n    on_subentry_to_entry: not args[2].locked and treeview.add_node(args[1], args[2])\n    on_remove_subentry: args[2].nodes = []\n    BoxLayout:\n        pos: root.pos\n        size: root.size\n        size_hint: None, None\n        orientation: 'vertical'\n        BoxLayout:\n            size_hint_y: None\n            height: 30\n            orientation: 'horizontal'\n            Widget:\n                # Just for spacing\n                width: 10\n                size_hint_x: None\n            Label:\n                text: 'Name'\n                text_size: self.size\n                halign: 'left'\n                bold: True\n            Label:\n                text: 'Size'\n                text_size: self.size\n                size_hint_x: None\n                halign: 'right'\n                bold: True\n            Widget:\n                # Just for spacing\n                width: 10\n                size_hint_x: None\n        ScrollView:\n            id: scrollview\n            do_scroll_x: False\n            Scatter:\n                do_rotation: False\n                do_scale: False\n                do_translation: False\n                size: treeview.size\n                size_hint_y: None\n                TreeView:\n                    id: treeview\n                    hide_root: True\n                    size_hint_y: None\n                    width: scrollview.width\n                    height: self.minimum_height\n                    on_node_expand: root.controller.entry_subselect(args[1])\n                    on_node_collapse: root.controller.close_subselection(args[1])\n\n<FileChooserListView>:\n    layout: layout\n    FileChooserListLayout:\n        id: layout\n        controller: root\n        pos: root.pos\n\n[FileListEntry@FloatLayout+TreeViewNode]:\n    locked: False\n    entries: []\n    path: ctx.path\n    # FIXME: is_selected is actually a read_only treeview property. In this\n    # case, however, we're doing this because treeview only has single-selection\n    # hardcoded in it. The fix to this would be to update treeview to allow\n    # multiple selection.\n    is_selected: self.path in ctx.controller().selection\n\n    orientation: 'horizontal'\n    size_hint_y: None\n    height: '48dp' if dp(1) > 1 else '24dp'\n    # Don't allow expansion of the ../ node\n    is_leaf: not ctx.isdir or ctx.name.endswith('..' + ctx.sep) or self.locked\n    on_touch_down: self.collide_point(*args[1].pos) and ctx.controller().entry_touched(self, args[1])\n    on_touch_up: self.collide_point(*args[1].pos) and ctx.controller().entry_released(self, args[1])\n    BoxLayout:\n        pos: root.pos\n        Label:\n            id: filename\n            text_size: self.width, None\n            halign: 'left'\n            shorten: True\n            text: ctx.name\n        Label:\n            text_size: self.width, None\n            size_hint_x: None\n            halign: 'right'\n            text: '{}'.format(ctx.get_nice_size())\n\n\n<FileChooserIconLayout>:\n    on_entry_added: stacklayout.add_widget(args[1])\n    on_entries_cleared: stacklayout.clear_widgets()\n    ScrollView:\n        id: scrollview\n        pos: root.pos\n        size: root.size\n        size_hint: None, None\n        do_scroll_x: False\n        Scatter:\n            do_rotation: False\n            do_scale: False\n            do_translation: False\n            size_hint_y: None\n            height: stacklayout.height\n            StackLayout:\n                id: stacklayout\n                width: scrollview.width\n                size_hint_y: None\n                height: self.minimum_height\n                spacing: '10dp'\n                padding: '10dp'\n\n<FileChooserIconView>:\n    layout: layout\n    FileChooserIconLayout:\n        id: layout\n        controller: root\n        pos: root.pos\n\n[FileIconEntry@Widget]:\n    locked: False\n    path: ctx.path\n    selected: self.path in ctx.controller().selection\n    size_hint: None, None\n\n    on_touch_down: self.collide_point(*args[1].pos) and ctx.controller().entry_touched(self, args[1])\n    on_touch_up: self.collide_point(*args[1].pos) and ctx.controller().entry_released(self, args[1])\n    size: '100dp', '100dp'\n\n    canvas:\n        Color:\n            rgba: 1, 1, 1, 1 if self.selected else 0\n        BorderImage:\n            border: 8, 8, 8, 8\n            pos: root.pos\n            size: root.size\n            source: 'atlas://data/images/defaulttheme/filechooser_selected'\n\n    Image:\n        size: '48dp', '48dp'\n        source: 'atlas://data/images/defaulttheme/filechooser_%s' % ('folder' if ctx.isdir else 'file')\n        pos: root.x + dp(24), root.y + dp(40)\n    Label:\n        text: ctx.name\n        text_size: (root.width, self.height)\n        halign: 'center'\n        shorten: True\n        size: '100dp', '16dp'\n        pos: root.x, root.y + dp(16)\n\n    Label:\n        text: '{}'.format(ctx.get_nice_size())\n        font_size: '11sp'\n        color: .8, .8, .8, 1\n        size: '100dp', '16sp'\n        pos: root.pos\n        halign: 'center'\n\n<FileChooserProgress>:\n    pos_hint: {'x': 0, 'y': 0}\n    canvas:\n        Color:\n            rgba: 0, 0, 0, .8\n        Rectangle:\n            pos: self.pos\n            size: self.size\n    Label:\n        pos_hint: {'x': .2, 'y': .6}\n        size_hint: .6, .2\n        text: 'Opening %s' % root.path\n    FloatLayout:\n        pos_hint: {'x': .2, 'y': .4}\n        size_hint: .6, .2\n        ProgressBar:\n            id: pb\n            pos_hint: {'x': 0, 'center_y': .5}\n            max: root.total\n            value: root.index\n        Label:\n            pos_hint: {'x': 0}\n            text: '%d / %d' % (root.index, root.total)\n            size_hint_y: None\n            height: self.texture_size[1]\n            y: pb.center_y - self.height - 8\n            font_size: '13sp'\n            color: (.8, .8, .8, .8)\n\n    AnchorLayout:\n        pos_hint: {'x': .2, 'y': .2}\n        size_hint: .6, .2\n\n        Button:\n            text: 'Cancel'\n            size_hint: None, None\n            size: 150, 44\n            on_release: root.cancel()\n\n\n\n# Switch widget\n<Switch>:\n    active_norm_pos: max(0., min(1., (int(self.active) + self.touch_distance / sp(41))))\n    canvas:\n        Color:\n            rgb: 1, 1, 1\n        Rectangle:\n            source: 'atlas://data/images/defaulttheme/switch-background{}'.format('_disabled' if self.disabled else '')\n            size: sp(83), sp(32)\n            pos: int(self.center_x - sp(41)), int(self.center_y - sp(16))\n        Rectangle:\n            source: 'atlas://data/images/defaulttheme/switch-button{}'.format('_disabled' if self.disabled else '')\n            size: sp(43), sp(32)\n            pos: int(self.center_x - sp(41) + self.active_norm_pos * sp(41)), int(self.center_y - sp(16))\n\n\n# ModalView widget\n<ModalView>:\n    canvas:\n        Color:\n            rgba: root.background_color[:3] + [root.background_color[-1] * self._anim_alpha]\n        Rectangle:\n            size: self._window.size if self._window else (0, 0)\n\n        Color:\n            rgb: 1, 1, 1\n        BorderImage:\n            source: root.background\n            border: root.border\n            pos: self.pos\n            size: self.size\n\n\n# Popup widget\n<Popup>:\n    _container: container\n    GridLayout:\n        padding: '12dp'\n        cols: 1\n        size_hint: None, None\n        pos: root.pos\n        size: root.size\n\n        Label:\n            text: root.title\n            color: root.title_color\n            size_hint_y: None\n            height: self.texture_size[1] + dp(16)\n            text_size: self.width - dp(16), None\n            font_size: root.title_size\n            font_name: root.title_font\n            halign: root.title_align\n\n        Widget:\n            size_hint_y: None\n            height: dp(4)\n            canvas:\n                Color:\n                    rgba: root.separator_color\n                Rectangle:\n                    pos: self.x, self.y + root.separator_height / 2.\n                    size: self.width, root.separator_height\n\n        BoxLayout:\n            id: container\n\n# =============================================================================\n# Spinner widget\n# =============================================================================\n\n<SpinnerOption>:\n    size_hint_y: None\n    height: '48dp'\n\n<Spinner>:\n    background_normal: 'atlas://data/images/defaulttheme/spinner'\n    background_disabled_normal: 'atlas://data/images/defaulttheme/spinner_disabled'\n    background_down: 'atlas://data/images/defaulttheme/spinner_pressed'\n\n# =============================================================================\n# ActionBar widget\n# =============================================================================\n\n<ActionBar>:\n    height: '48dp'\n    size_hint_y: None\n    spacing: '4dp'\n    canvas:\n        Color:\n            rgba: self.background_color\n        BorderImage:\n            border: root.border\n            pos: self.pos\n            size: self.size\n            source: self.background_image\n\n<ActionView>:\n    orientation: 'horizontal'\n    canvas:\n        Color:\n            rgba: self.background_color\n        BorderImage:\n            pos: self.pos\n            size: self.size\n            source: self.background_image\n\n<ActionSeparator>:\n    size_hint_x: None\n    minimum_width: '2sp'\n    width: self.minimum_width\n    canvas:\n        Rectangle:\n            pos: self.x, self.y + sp(4)\n            size: self.width, self.height - sp(8)\n            source: self.background_image\n\n<ActionButton,ActionToggleButton>:\n    background_normal: 'atlas://data/images/defaulttheme/' + ('action_bar' if self.inside_group else 'action_item')\n    background_down: 'atlas://data/images/defaulttheme/action_item_down'\n    size_hint_x: None if not root.inside_group else 1\n    width: [dp(48) if (root.icon and not root.inside_group) else max(dp(48), (self.texture_size[0] + dp(32))), self.size_hint_x][0]\n    color: self.color[:3] + [0 if (root.icon and not root.inside_group) else 1]\n\n    Image:\n        allow_stretch: True\n        opacity: 1 if (root.icon and not root.inside_group) else 0\n        source: root.icon\n        mipmap: root.mipmap\n        pos: root.x + dp(4), root.y + dp(4)\n        size: root.width - dp(8), root.height - sp(8)\n\n<ActionGroup>:\n    size_hint_x: None\n    width: self.texture_size[0] + dp(32)\n\n<ActionCheck>:\n    background_normal: 'atlas://data/images/defaulttheme/action_bar' if self.inside_group else 'atlas://data/images/defaulttheme/action_item'\n\n<ActionPreviousImage@Image>:\n    temp_width: 0\n    temp_height: 0\n\n<ActionPrevious>:\n    size_hint_x: 1\n    minimum_width: '100sp'\n    important: True\n    BoxLayout:\n        orientation: 'horizontal'\n        pos: root.pos\n        size: root.size\n        ActionPreviousImage:\n            id: prev_icon_image\n            source: root.previous_image\n            opacity: 1 if root.with_previous else 0\n            allow_stretch: True\n            size_hint_x: None\n            temp_width: root.previous_image_width or dp(prev_icon_image.texture_size[0])\n            temp_height: root.previous_image_height or dp(prev_icon_image.texture_size[1])\n            width:\n                (self.temp_width if self.temp_height <= self.height else \\\n                self.temp_width * (self.height / self.temp_height)) \\\n                if self.texture else dp(8)\n            mipmap: root.mipmap\n        ActionPreviousImage:\n            id: app_icon_image\n            source: root.app_icon\n            allow_stretch: True\n            size_hint_x: None\n            temp_width: root.app_icon_width or dp(app_icon_image.texture_size[0])\n            temp_height: root.app_icon_height or dp(app_icon_image.texture_size[1])\n            width:\n                (self.temp_width if self.temp_height <= self.height else \\\n                self.temp_width * (self.height / self.temp_height)) \\\n                if self.texture else dp(8)\n            mipmap: root.mipmap\n        Widget:\n            size_hint_x: None\n            width: '5sp'\n        Label:\n            text: root.title\n            text_size: self.size\n            color: root.color\n            shorten: True\n            halign: 'left'\n            valign: 'middle'\n\n<ActionGroup>:\n    background_normal: 'atlas://data/images/defaulttheme/action_group'\n    background_down: 'atlas://data/images/defaulttheme/action_group_down'\n    background_disabled_normal: 'atlas://data/images/defaulttheme/action_group_disabled'\n    border: 30, 30, 3, 3\n    ActionSeparator:\n        pos: root.pos\n        size: root.separator_width, root.height\n        opacity: 1 if root.use_separator else 0\n        background_image: root.separator_image if root.use_separator else 'action_view'\n\n<ActionOverflow>:\n    border: 3, 3, 3, 3\n    background_normal: 'atlas://data/images/defaulttheme/action_item'\n    background_down: 'atlas://data/images/defaulttheme/action_item_down'\n    background_disabled_normal: 'atlas://data/images/defaulttheme/button_disabled'\n    size_hint_x: None\n    minimum_width: '48sp'\n    width: self.texture_size[0] if self.texture else self.minimum_width\n    canvas.after:\n        Color:\n            rgb: 1, 1, 1\n        Rectangle:\n            pos: root.center_x - sp(16), root.center_y - sp(16)\n            size: sp(32), sp(32)\n            source: root.overflow_image\n\n<ActionDropDown>:\n    auto_width: False\n\n\n# =============================================================================\n# Accordion widget\n# =============================================================================\n\n[AccordionItemTitle@Label]:\n    text: ctx.title\n    normal_background: ctx.item.background_normal if ctx.item.collapse else ctx.item.background_selected\n    disabled_background: ctx.item.background_disabled_normal if ctx.item.collapse else ctx.item.background_disabled_selected\n    canvas.before:\n        Color:\n            rgba: self.disabled_color if self.disabled else self.color\n        BorderImage:\n            source: self.disabled_background if self.disabled else self.normal_background\n            pos: self.pos\n            size: self.size\n        PushMatrix\n        Translate:\n            xy: self.center_x, self.center_y\n        Rotate:\n            angle: 90 if ctx.item.orientation == 'horizontal' else 0\n            axis: 0, 0, 1\n        Translate:\n            xy: -self.center_x, -self.center_y\n    canvas.after:\n        PopMatrix\n\n\n<AccordionItem>:\n    container: container\n    container_title: container_title\n\n    BoxLayout:\n        orientation: root.orientation\n        pos: root.pos\n        BoxLayout:\n            size_hint_x: None if root.orientation == 'horizontal' else 1\n            size_hint_y: None if root.orientation == 'vertical' else 1\n            width: root.min_space if root.orientation == 'horizontal' else 100\n            height: root.min_space if root.orientation == 'vertical' else 100\n            id: container_title\n\n        StencilView:\n            id: sv\n\n            BoxLayout:\n                id: container\n                pos: sv.pos\n                size: root.content_size\n\n\n# =============================================================================\n# Settings\n# =============================================================================\n\n<SettingSpacer>:\n    size_hint_y: None\n    height: 5\n    canvas:\n        Color:\n            rgb: .2, .2, .2\n        Rectangle:\n            pos: self.x, self.center_y\n            size: self.width, 1\n\n<SettingItem>:\n    size_hint: .25, None\n    height: labellayout.texture_size[1] + dp(10)\n    content: content\n    canvas:\n        Color:\n            rgba: 47 / 255., 167 / 255., 212 / 255., self.selected_alpha\n        Rectangle:\n            pos: self.x, self.y + 1\n            size: self.size\n        Color:\n            rgb: .2, .2, .2\n        Rectangle:\n            pos: self.x, self.y - 2\n            size: self.width, 1\n\n    BoxLayout:\n        pos: root.pos\n\n        Label:\n            size_hint_x: .66\n            id: labellayout\n            markup: True\n            text: u'{0}\\n[size=13sp][color=999999]{1}[/color][/size]'.format(root.title or '', root.desc or '')\n            font_size: '15sp'\n            text_size: self.width - 32, None\n\n        BoxLayout:\n            id: content\n            size_hint_x: .33\n\n\n<SettingBoolean>:\n    Switch:\n        text: 'Boolean'\n        pos: root.pos\n        active: bool(root.values.index(root.value)) if root.value in root.values else False\n        on_active: root.value = root.values[int(args[1])]\n\n<SettingString>:\n    Label:\n        text: root.value or ''\n        pos: root.pos\n        font_size: '15sp'\n\n<SettingPath>:\n    Label:\n        text: root.value or ''\n        pos: root.pos\n        font_size: '15sp'\n\n<SettingOptions>:\n    Label:\n        text: root.value or ''\n        pos: root.pos\n        font_size: '15sp'\n\n<SettingTitle>:\n    text_size: self.width - 32, None\n    size_hint_y: None\n    height: max(dp(20), self.texture_size[1] + dp(20))\n    color: (.9, .9, .9, 1)\n    font_size: '15sp'\n    canvas:\n        Color:\n            rgba: .15, .15, .15, .5\n        Rectangle:\n            pos: self.x, self.y + 2\n            size: self.width, self.height - 2\n        Color:\n            rgb: .2, .2, .2\n        Rectangle:\n            pos: self.x, self.y - 2\n            size: self.width, 1\n\n<SettingSidebarLabel>:\n    size_hint: 1, None\n    text_size: self.width - 32, None\n    height: self.texture_size[1] + dp(20)\n    font_size: '15sp'\n    canvas.before:\n        Color:\n            rgba: 47 / 255., 167 / 255., 212 / 255., int(self.selected)\n        Rectangle:\n            pos: self.pos\n            size: self.size\n\n<SettingsPanel>:\n    spacing: 5\n    padding: 5\n    size_hint_y: None\n    height: self.minimum_height\n\n    Label:\n        size_hint_y: None\n        text: root.title\n        text_size: self.width - 32, None\n        height: max(50, self.texture_size[1] + 20)\n        color: (.5, .5, .5, 1)\n        font_size: '15sp'\n\n        canvas.after:\n            Color:\n                rgb: .2, .2, .2\n            Rectangle:\n                pos: self.x, self.y - 2\n                size: self.width, 1\n\n<Settings>:\n    orientation: 'horizontal'\n    canvas.before:\n        Color:\n            rgb: 0, 0, 0\n        Rectangle:\n            pos: self.pos\n            size: self.size\n\n<InterfaceWithSidebar>:\n    orientation: 'horizontal'\n    menu: menu\n    content: content\n    MenuSidebar:\n        id: menu\n    ContentPanel:\n        id: content\n        current_uid: menu.selected_uid\n\n<InterfaceWithSpinner>:\n    orientation: 'vertical'\n    menu: menu\n    content: content\n    MenuSpinner:\n        id: menu\n    ContentPanel:\n        id: content\n        current_uid: menu.selected_uid\n\n<MenuSpinner>:\n    orientation: 'horizontal'\n    size_hint_y: None\n    height: '50dp'\n    spinner: spinner\n    spinner_text: spinner.text\n    close_button: button\n    Spinner:\n        id: spinner\n    Button:\n        text: 'Close'\n        id: button\n        size_hint_x: None\n        width: min(dp(200), 0.4*root.width)\n        font_size: '15sp'\n\n\n<MenuSidebar>:\n    size_hint_x: None\n    width: '200dp'\n    buttons_layout: menu\n    close_button: button\n    GridLayout:\n        pos: root.pos\n        cols: 1\n        id: menu\n        orientation: 'vertical'\n        padding: 5\n\n        canvas.after:\n            Color:\n                rgb: .2, .2, .2\n            Rectangle:\n                pos: self.right - 1, self.y\n                size: 1, self.height\n\n    Button:\n        text: 'Close'\n        id: button\n        size_hint: None, None\n        width: root.width - dp(20)\n        height: max(50, self.texture_size[1] + dp(20))\n        pos: root.x + dp(10), root.y + dp(10)\n        font_size: '15sp'\n\n<ContentPanel>:\n    do_scroll_x: False\n    container: content\n    GridLayout:\n        id: content\n        cols: 1\n        size_hint_y: None\n        height: self.minimum_height\n\n<InterfaceWithTabbedPanel>:\n    tabbedpanel: tp\n    close_button: button\n    TabbedPanel:\n        id: tp\n        size: root.size\n        pos: root.pos\n        #do_default_tab: False\n        background_color: (0,0,0,1)\n    Button:\n        id: button\n        text: 'Close'\n        size_hint: None, None\n        height: '45dp'\n        width: min(dp(200), 0.3*root.width)\n        x: root.x + root.width - self.width\n        y: root.y + root.height - self.height\n\n\n<ScrollView>:\n    canvas.after:\n        Color:\n            rgba: self._bar_color if (self.do_scroll_y and self.viewport_size[1] > self.height) else [0, 0, 0, 0]\n        Rectangle:\n            pos: (self.right - self.bar_width - self.bar_margin) if self.bar_pos_y == 'right' else (self.x + self.bar_margin), self.y + self.height * self.vbar[0]\n            size: min(self.bar_width, self.width), self.height * self.vbar[1]\n        Color:\n            rgba: self._bar_color if (self.do_scroll_x and self.viewport_size[0] > self.width) else [0, 0, 0, 0]\n        Rectangle:\n            pos: self.x + self.width * self.hbar[0], (self.y + self.bar_margin) if self.bar_pos_x == 'bottom' else (self.top - self.bar_margin - self.bar_width)\n            size: self.width * self.hbar[1], min(self.bar_width, self.height)\n\n\n# =============================================================================\n# Video player\n# =============================================================================\n\n<VideoPlayerPreview>:\n    pos_hint: {'x': 0, 'y': 0}\n    image_overlay_play: 'atlas://data/images/defaulttheme/player-play-overlay'\n    image_loading: 'atlas://data/images/image-loading.gif'\n    Image:\n        source: root.source\n        color: (.5, .5, .5, 1)\n        pos_hint: {'x': 0, 'y': 0}\n    Image:\n        source: root.image_overlay_play if not root.click_done else root.image_loading\n        pos_hint: {'x': 0, 'y': 0}\n\n\n<VideoPlayerAnnotation>:\n    canvas.before:\n        Color:\n            rgba: self.annotation['bgcolor'] if 'bgcolor' in self.annotation else (0, 0, 0, 0.8)\n        BorderImage:\n            pos: self.pos\n            size: self.size\n            source: self.annotation['bgsource'] if 'bgsource' in self.annotation else None\n            border: self.annotation['border'] if 'border' in self.annotation else (0, 0, 0, 0)\n    size_hint: self.annotation['size_hint'] if 'size_hint' in self.annotation else (None, None)\n    size: self.annotation['size'] if 'size' in self.annotation else (self.texture_size[0] + 20, self.texture_size[1] + 20)\n    pos_hint: self.annotation['pos_hint'] if 'pos_hint' in self.annotation else {'center_x': .5, 'y': .05}\n\n<VideoPlayer>:\n    container: container\n    cols: 1\n\n    FloatLayout:\n        cols: 1\n        id: container\n\n    GridLayout:\n        rows: 1\n        size_hint_y: None\n        height: 44\n\n        VideoPlayerStop:\n            size_hint_x: None\n            video: root\n            width: 44\n            source: root.image_stop\n\n        VideoPlayerPlayPause:\n            size_hint_x: None\n            video: root\n            width: 44\n            source: root.image_pause if root.state == 'play' else root.image_play\n\n        VideoPlayerVolume:\n            video: root\n            size_hint_x: None\n            width: 44\n            source: root.image_volumehigh if root.volume > 0.8 else (root.image_volumemedium if root.volume > 0.4 else (root.image_volumelow if root.volume > 0 else root.image_volumemuted))\n\n        Widget:\n            size_hint_x: None\n            width: 5\n\n        VideoPlayerProgressBar:\n            video: root\n            max: max(root.duration, root.position, 1)\n            value: root.position\n\n        Widget:\n            size_hint_x: None\n            width: 10\n\n# =============================================================================\n# Checkbox\n# =============================================================================\n\n<CheckBox>:\n    _checkbox_state_image:\n        self.background_checkbox_down \\\n        if self.active else self.background_checkbox_normal\n    _checkbox_disabled_image:\n        self.background_checkbox_disabled_down \\\n        if self.active else self.background_checkbox_disabled_normal\n    _radio_state_image:\n        self.background_radio_down \\\n        if self.active else self.background_radio_normal\n    _radio_disabled_image:\n        self.background_radio_disabled_down \\\n        if self.active else self.background_radio_disabled_normal\n    _checkbox_image:\n        self._checkbox_disabled_image \\\n        if self.disabled else self._checkbox_state_image\n    _radio_image:\n        self._radio_disabled_image \\\n        if self.disabled else self._radio_state_image\n    canvas:\n        Color:\n            rgb: 1, 1, 1\n        Rectangle:\n            source: self._radio_image if self.group else self._checkbox_image\n            size: sp(32), sp(32)\n            pos: int(self.center_x - sp(16)), int(self.center_y - sp(16))\n\n# =============================================================================\n# Screen Manager\n# =============================================================================\n\n<ScreenManager>:\n    canvas.before:\n        StencilPush\n        Rectangle:\n            pos: self.pos\n            size: self.size\n        StencilUse\n    canvas.after:\n        StencilUnUse\n        Rectangle:\n            pos: self.pos\n            size: self.size\n        StencilPop\n\n# =============================================================================\n# Color Picker\n# =============================================================================\n<ColorPicker_Input@TextInput>\n    multiline: False\n    mroot: None\n    padding: sp(5)\n    border: 4, 9, 4, 9\n\n<ColorPicker_Label@Label>\n    mroot: None\n    size_hint_x: None\n    width: '30sp'\n    text_size: self.size\n    halign: \"center\"\n    valign: \"middle\"\n\n<ColorPicker_Selector@BoxLayout>\n    foreground_color: None\n    text: ''\n    mroot: None\n    mode: 'rgb'\n    color: 0\n    spacing: '2sp'\n    ColorPicker_Label:\n        text: root.text\n        mroot: root.mroot\n        color: root.foreground_color or (1, 1, 1, 1)\n    AnchorLayout:\n        size_hint_x: None\n        width: '50sp'\n        ColorPicker_Input:\n            mroot: root.mroot\n            text: str(int(sldr.value))\n            size_hint_y: None\n            height: '28sp'\n            on_text:\n                root.mroot._trigger_update_clr(root.mode, root.clr_idx, args[1])\n    Slider:\n        id: sldr\n        size_hint: 1, .25\n        pos_hint: {'center_y':.5}\n        range: 0, 255\n        value: root.color * 255\n        on_value:\n            root.mroot._trigger_update_clr(root.mode, root.clr_idx, args[1])\n\n<ColorPicker>:\n    foreground_color: (1, 1, 1, 1) if self.hsv[2] * wheel.a < .5 else (0, 0, 0, 1)\n    wheel: wheel\n    BoxLayout:\n        orientation: 'vertical' if root.width < root.height else 'horizontal'\n        spacing: '5sp'\n        StackLayout:\n            orientation: 'tb-lr'\n            size_hint_y: None if root.width < root.height else 1\n            height: sp(33) * 4 if root.width < root.height else self.height\n            canvas:\n                Color:\n                    rgba: root.color\n                Rectangle:\n                    size: self.size\n                    pos: self.pos\n\n            ColorPicker_Selector:\n                mroot: root\n                text: 'R'\n                clr_idx: 0\n                color: wheel.r\n                foreground_color: root.foreground_color\n                size_hint_y: None if root.width < root.height else 0.125\n                size_hint_x: .5 if root.width < root.height else 1\n                height: '33sp' if root.width < root.height else self.height\n\n            ColorPicker_Selector:\n                mroot: root\n                text: 'G'\n                clr_idx: 1\n                color: wheel.g\n                foreground_color: root.foreground_color\n                size_hint_y: None if root.width < root.height else 0.125\n                size_hint_x: .5 if root.width < root.height else 1\n                height: '33sp' if root.width < root.height else self.height\n\n            ColorPicker_Selector:\n                mroot: root\n                text: 'B'\n                clr_idx: 2\n                color: wheel.b\n                foreground_color: root.foreground_color\n                size_hint_y: None if root.width < root.height else 0.125\n                size_hint_x: .5 if root.width < root.height else 1\n                height: '33sp' if root.width < root.height else self.height\n\n            ColorPicker_Selector:\n                mroot: root\n                text: 'A'\n                clr_idx: 3\n                color: root.color[3]\n                foreground_color: root.foreground_color\n                size_hint_y: None if root.width < root.height else 0.125\n                size_hint_x: .5 if root.width < root.height else 1\n                height: '33sp' if root.width < root.height else self.height\n\n            ColorPicker_Selector:\n                mroot: root\n                mode: 'hsv'\n                text: 'H'\n                clr_idx: 0\n                color: root.hsv[0]\n                foreground_color: root.foreground_color\n                size_hint_y: None if root.width < root.height else 0.125\n                size_hint_x: .5 if root.width < root.height else 1\n                height: '33sp' if root.width < root.height else self.height\n\n            ColorPicker_Selector:\n                mroot: root\n                mode: 'hsv'\n                text: 'S'\n                clr_idx: 1\n                color: root.hsv[1]\n                foreground_color: root.foreground_color\n                size_hint_y: None if root.width < root.height else 0.125\n                size_hint_x: .5 if root.width < root.height else 1\n                height: '33sp' if root.width < root.height else self.height\n\n            ColorPicker_Selector:\n                mroot: root\n                mode: 'hsv'\n                text: 'V'\n                clr_idx: 2\n                color: root.hsv[2]\n                foreground_color: root.foreground_color\n                size_hint_y: None if root.width < root.height else 0.125\n                size_hint_x: .5 if root.width < root.height else 1\n                height: '33sp' if root.width < root.height else self.height\n\n            BoxLayout:\n                size_hint_y: None if root.width < root.height else 0.125\n                size_hint_x: .5 if root.width < root.height else 1\n                height: '33sp' if root.width < root.height else self.height\n\n                spacing: '2sp'\n                ColorPicker_Label:\n                    mroot: root\n                    text: 'X'\n                    color: root.foreground_color\n                AnchorLayout:\n                    ColorPicker_Input:\n                        size_hint_y: None\n                        height: '28sp'\n                        mroot: root\n                        text: str(root.hex_color)\n                        on_text: root._trigger_update_hex(args[1])\n\n\n        ColorWheel:\n            id: wheel\n            _origin: (self.center_x, self.center_y)\n            _radius: 0.45 * min(self.size)\n            color: root.color\n            on_color: root.color[:3] = args[1][:3]\n"
  },
  {
    "path": "tickeys/kivy/effects/__init__.py",
    "content": "'''\nEffects\n=======\n\n.. versionadded:: 1.7.0\n\nEverything starts with the :class:`~kinetic.KineticEffect`, the base class for\ncomputing velocity out of a movement.\n\nThis base class is used to implement the :class:`~scroll.ScrollEffect`, a base\nclass used for our :class:`~kivy.uix.scrollview.ScrollView` widget effect.\nWe have multiple implementations:\n\n- :class:`~kivy.effects.scroll.ScrollEffect`: base class used for implementing\n  an effect. It only calculates the scrolling and the overscroll.\n- :class:`~kivy.effects.dampedscroll.DampedScrollEffect`: uses the overscroll\n  information to allow the user to drag more than expected. Once the user stops\n  the drag, the position is returned to one of the bounds.\n- :class:`~kivy.effects.opacityscroll.OpacityScrollEffect`: uses the overscroll\n  information to reduce the opacity of the scrollview widget. When the user\n  stops the drag, the opacity is set back to 1.\n\n'''\n"
  },
  {
    "path": "tickeys/kivy/effects/dampedscroll.py",
    "content": "'''\nDamped scroll effect\n====================\n\n.. versionadded:: 1.7.0\n\nThis damped scroll effect will use the\n:attr:`~kivy.effects.scroll.ScrollEffect.overscroll` to calculate the scroll\nvalue, and slows going back to the upper or lower limit.\n\n'''\n\n__all__ = ('DampedScrollEffect',)\n\n\nfrom kivy.effects.scroll import ScrollEffect\nfrom kivy.properties import NumericProperty, BooleanProperty\nfrom kivy.metrics import sp\n\n\nclass DampedScrollEffect(ScrollEffect):\n    '''DampedScrollEffect class. See the module documentation for more\n    information.\n    '''\n\n    edge_damping = NumericProperty(0.25)\n    '''Edge damping.\n\n    :attr:`edge_damping` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.25\n    '''\n\n    spring_constant = NumericProperty(2.0)\n    '''Spring constant.\n\n    :attr:`spring_constant` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 2.0\n    '''\n\n    min_overscroll = NumericProperty(.5)\n    '''An overscroll less than this amount will be normalized to 0.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`min_overscroll` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to .5.\n    '''\n\n    round_value = BooleanProperty(True)\n    '''If True, when the motion stops, :attr:`value` is rounded to the nearest\n    integer.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`round_value` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n    def update_velocity(self, dt):\n        if abs(self.velocity) <= self.min_velocity and self.overscroll == 0:\n            self.velocity = 0\n            # why does this need to be rounded? For now refactored it.\n            if self.round_value:\n                self.value = round(self.value)\n            return\n\n        total_force = self.velocity * self.friction\n        if abs(self.overscroll) > self.min_overscroll:\n            total_force += self.velocity * self.edge_damping\n            total_force += self.overscroll * self.spring_constant\n        else:\n            self.overscroll = 0\n\n        stop_overscroll = ''\n        if not self.is_manual:\n            if self.overscroll > 0 and self.velocity < 0:\n                stop_overscroll = 'max'\n            elif self.overscroll < 0 and self.velocity > 0:\n                stop_overscroll = 'min'\n\n        self.velocity = self.velocity - total_force\n        if not self.is_manual:\n            self.apply_distance(self.velocity * dt)\n            if stop_overscroll == 'min' and self.value > self.min:\n                self.value = self.min\n                self.velocity = 0\n                return\n            if stop_overscroll == 'max' and self.value < self.max:\n                self.value = self.max\n                self.velocity = 0\n                return\n        self.trigger_velocity_update()\n\n    def on_value(self, *args):\n        scroll_min = self.min\n        scroll_max = self.max\n        if scroll_min > scroll_max:\n            scroll_min, scroll_max = scroll_max, scroll_min\n        if self.value < scroll_min:\n            self.overscroll = self.value - scroll_min\n        elif self.value > scroll_max:\n            self.overscroll = self.value - scroll_max\n        else:\n            self.overscroll = 0\n        self.scroll = self.value\n\n    def on_overscroll(self, *args):\n        self.trigger_velocity_update()\n\n    def apply_distance(self, distance):\n        os = abs(self.overscroll)\n        if os:\n            distance /= 1. + os / sp(200.)\n        super(DampedScrollEffect, self).apply_distance(distance)\n"
  },
  {
    "path": "tickeys/kivy/effects/kinetic.py",
    "content": "'''\nKinetic effect\n==============\n\n.. versionadded:: 1.7.0\n\nThe :class:`KineticEffect` is the base class that is used to compute the\nvelocity out of a movement. When the movement is finished, the effect will\ncompute the position of the movement according to the velocity, and reduce the\nvelocity with a friction. The movement stop until the velocity is 0.\n\nConceptually, the usage could be::\n\n    >>> effect = KineticEffect()\n    >>> effect.start(10)\n    >>> effect.update(15)\n    >>> effect.update(30)\n    >>> effect.stop(48)\n\nOver the time, you will start a movement of a value, update it, and stop the\nmovement. At this time, you'll get the movement value into\n:attr:`KineticEffect.value`. On the example i've typed manually, the computed\nvelocity will be::\n\n    >>> effect.velocity\n    3.1619100231163046\n\nAfter multiple clock interaction, the velocity will decrease according to\n:attr:`KineticEffect.friction`. The computed value will be stored in\n:attr:`KineticEffect.value`. The output of this `value` could be::\n\n    46.30038145219605\n    54.58302451968686\n    61.9229016256196\n    # ...\n\n'''\n\n__all__ = ('KineticEffect', )\n\n\nfrom time import time\nfrom kivy.event import EventDispatcher\nfrom kivy.properties import NumericProperty, BooleanProperty\nfrom kivy.clock import Clock\n\n\nclass KineticEffect(EventDispatcher):\n    '''Kinetic effect class. See module documentation for more information.\n    '''\n\n    velocity = NumericProperty(0)\n    '''Velocity of the movement.\n\n    :attr:`velocity` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    friction = NumericProperty(0.05)\n    '''Friction to apply on the velocity\n\n    :attr:`velocity` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.05.\n    '''\n\n    value = NumericProperty(0)\n    '''Value (during the movement and computed) of the effect.\n\n    :attr:`velocity` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    is_manual = BooleanProperty(False)\n    '''Indicate if a movement is in progress (True) or not (False).\n\n    :attr:`velocity` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    max_history = NumericProperty(5)\n    '''Save up to `max_history` movement value into the history. This is used\n    for correctly calculating the velocity according to the movement.\n\n    :attr:`max_history` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 5.\n    '''\n    min_distance = NumericProperty(.1)\n    '''The minimal distance for a movement to have nonzero velocity.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`min_distance` is :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.1.\n    '''\n\n    min_velocity = NumericProperty(.5)\n    '''Velocity below this quantity is normalized to 0. In other words,\n    any motion whose velocity falls below this number is stopped.\n\n    .. versionadded::1.8.0\n\n    :attr:`min_velocity` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.5.\n    '''\n\n    def __init__(self, **kwargs):\n        self.history = []\n        self.trigger_velocity_update = Clock.create_trigger(\n            self.update_velocity, 0)\n        super(KineticEffect, self).__init__(**kwargs)\n\n    def apply_distance(self, distance):\n        if abs(distance) < self.min_distance:\n            self.velocity = 0\n        self.value += distance\n\n    def start(self, val, t=None):\n        '''Start the movement.\n\n        :Parameters:\n            `val`: float or int\n                Value of the movement\n            `t`: float, defaults to None\n                Time when the movement happen. If no time is set, it will use\n                time.time()\n        '''\n        self.is_manual = True\n        t = t or time()\n        self.velocity = 0\n        self.history = [(t, val)]\n\n    def update(self, val, t=None):\n        '''Update the movement.\n\n        See :meth:`start` for the arguments.\n        '''\n        t = t or time()\n        distance = val - self.history[-1][1]\n        self.apply_distance(distance)\n        self.history.append((t, val))\n        if len(self.history) > self.max_history:\n            self.history.pop(0)\n\n    def stop(self, val, t=None):\n        '''Stop the movement.\n\n        See :meth:`start` for the arguments.\n        '''\n        self.is_manual = False\n        t = t or time()\n        distance = val - self.history[-1][1]\n        self.apply_distance(distance)\n        newest_sample = (t, val)\n        old_sample = self.history[0]\n        for sample in self.history:\n            if (newest_sample[0] - sample[0]) < 10. / 60.:\n                break\n            old_sample = sample\n        distance = newest_sample[1] - old_sample[1]\n        duration = abs(newest_sample[0] - old_sample[0])\n        self.velocity = (distance / max(duration, 0.0001))\n        self.trigger_velocity_update()\n\n    def cancel(self):\n        '''Cancel a movement. This can be used in case :meth:`stop` cannot be\n        called. It will reset :attr:`is_manual` to False, and compute the\n        movement if the velocity is > 0.\n        '''\n        self.is_manual = False\n        self.trigger_velocity_update()\n\n    def update_velocity(self, dt):\n        '''(internal) Update the velocity according to the frametime and\n        friction.\n        '''\n        if abs(self.velocity) <= self.min_velocity:\n            self.velocity = 0\n            return\n\n        self.velocity -= self.velocity * self.friction\n        self.apply_distance(self.velocity * dt)\n        self.trigger_velocity_update()\n"
  },
  {
    "path": "tickeys/kivy/effects/opacityscroll.py",
    "content": "'''\nOpacity scroll effect\n=====================\n\nBased on the :class:`~kivy.effects.damped.DampedScrollEffect`, this one will\nalso decrease the opacity of the target widget during the overscroll.\n\n'''\n\n__all__ = ('OpacityScrollEffect', )\n\n\nfrom kivy.effects.dampedscroll import DampedScrollEffect\n\n\nclass OpacityScrollEffect(DampedScrollEffect):\n    '''OpacityScrollEffect class. Uses the overscroll\n    information to reduce the opacity of the scrollview widget. When the user\n    stops the drag, the opacity is set back to 1.\n    '''\n\n    def on_overscroll(self, *args):\n        if self.target_widget and self.target_widget.height != 0:\n            alpha = (1.0 -\n                     abs(self.overscroll / float(self.target_widget.height)))\n            self.target_widget.opacity = min(1, alpha)\n        self.trigger_velocity_update()\n"
  },
  {
    "path": "tickeys/kivy/effects/scroll.py",
    "content": "'''\nScroll effect\n=============\n\n.. versionadded:: 1.7.0\n\nBased on the :class:`~kivy.effects.kinetic` effect, the :class:`ScrollEffect`\nwill limit the movement to bounds determined by its :attr:`~ScrollEffect.min`\nand :attr:`~ScrollEffect.max` properties. If the movement exceeds these\nbounds, it will calculate the amount of :attr:`~ScrollEffect.overscroll` and\ntry to return to the value of one of the bounds.\n\nThis is very useful for implementing a scrolling list. We actually use this\nclass as a base effect for our :class:`~kivy.uix.scrollview.ScrollView` widget.\n\n'''\n\n\n__all__ = ('ScrollEffect', )\n\n\nfrom kivy.effects.kinetic import KineticEffect\nfrom kivy.uix.widget import Widget\nfrom kivy.properties import NumericProperty, ObjectProperty\n\n\nclass ScrollEffect(KineticEffect):\n    '''ScrollEffect class. See the module documentation for more informations.\n    '''\n\n    drag_threshold = NumericProperty('20sp')\n    '''Minimum distance to travel before the movement is considered as a drag.\n\n    :attr:`velocity` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 20sp.\n    '''\n\n    min = NumericProperty(0)\n    '''Minimum boundary to use for scrolling.\n\n    :attr:`min` is a :class:`~kivy.properties.NumericProperty` and defaults to\n    0.\n    '''\n\n    max = NumericProperty(0)\n    '''Maximum boundary to use for scrolling.\n\n    :attr:`max` is a :class:`~kivy.properties.NumericProperty` and defaults to\n    0.\n    '''\n\n    scroll = NumericProperty(0)\n    '''Computed value for scrolling. This value is different from\n    :py:attr:`kivy.effects.kinetic.KineticEffect.value`\n    in that it will return to one of the min/max bounds.\n\n    :attr:`scroll` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 0.\n    '''\n\n    overscroll = NumericProperty(0)\n    '''Computed value when the user over-scrolls i.e. goes out of the bounds.\n\n    :attr:`overscroll` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    target_widget = ObjectProperty(None, allownone=True, baseclass=Widget)\n    '''Widget to attach to this effect. Even if this class doesn't make changes\n    to the `target_widget` by default, subclasses can use it to change the\n    graphics or apply custom transformations.\n\n    :attr:`target_widget` is a :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    displacement = NumericProperty(0)\n    '''Cumulative distance of the movement during the interaction. This is used\n    to determine if the movemenent is a drag (more than :attr:`drag_threshold`)\n    or not.\n\n    :attr:`displacement` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    def reset(self, pos):\n        '''(internal) Reset the value and the velocity to the `pos`.\n        Mostly used when the bounds are checked.\n        '''\n        self.value = pos\n        self.velocity = 0\n        if self.history:\n            val = self.history[-1][1]\n            super(ScrollEffect, self).start(val, None)\n\n    def on_value(self, *args):\n        scroll_min = self.min\n        scroll_max = self.max\n        if scroll_min > scroll_max:\n            scroll_min, scroll_max = scroll_max, scroll_min\n        if self.value < scroll_min:\n            self.overscroll = self.value - scroll_min\n            self.reset(scroll_min)\n        elif self.value > scroll_max:\n            self.overscroll = self.value - scroll_max\n            self.reset(scroll_max)\n        else:\n            self.scroll = self.value\n\n    def start(self, val, t=None):\n        self.is_manual = True\n        self.displacement = 0\n        return super(ScrollEffect, self).start(val, t)\n\n    def update(self, val, t=None):\n        self.displacement += abs(val - self.history[-1][1])\n        return super(ScrollEffect, self).update(val, t)\n\n    def stop(self, val, t=None):\n        self.is_manual = False\n        self.displacement += abs(val - self.history[-1][1])\n        if self.displacement <= self.drag_threshold:\n            self.velocity = 0\n            return\n        return super(ScrollEffect, self).stop(val, t)\n"
  },
  {
    "path": "tickeys/kivy/event.py",
    "content": "# This is a \"jumping\" module, required for python-for-android project\n# Because we are putting all the module into the same .so, their can be name\n# conflict. We have one conflict with pygame.event and kivy.event => Both are\n# python extension and have the same \"initevent\" symbol. So right now, just\n# rename this one.\n__all__ = ('EventDispatcher', 'ObjectWithUid', 'Observable')\n\nimport kivy._event\n__doc__ = kivy._event.__doc__\nEventDispatcher = kivy._event.EventDispatcher\nObjectWithUid = kivy._event.ObjectWithUid\nObservable = kivy._event.Observable\n"
  },
  {
    "path": "tickeys/kivy/ext/__init__.py",
    "content": "'''\nExtension Support\n=================\n\nSometimes your application requires functionality that is beyond the scope of\nwhat Kivy can deliver. In those cases it is necessary to resort to external\nsoftware libraries. Given the richness of the Python ecosystem, there is already\na great number of software libraries that you can simply import and use right\naway.\n\nFor some third-party libraries, it's not as easy as that though. Some libraries\nrequire special *wrappers* to be written for them in order to be compatible with\nKivy.\nSome libraries might even need to be patched so that they can be used (e.g. if\nthey open their own OpenGL context to draw in and don't support proper offscreen\nrendering). On those occasions it is often possible to patch the library in\nquestion and to provide a Python wrapper around it that is compatible with Kivy.\nSticking with this example, you can't just use the wrapper with a 'normal'\ninstallation of the library because the patch would be missing.\n\nThat is where Kivy extensions come in handy. A Kivy extension represents a\nsingle third-party library that is provided in a way so that it can simply be\ndownloaded as a single file, put in a special directory and then offers the\nfunctionality of the wrapped library to Kivy applications.\nThese extensions will not pollute the global Python environment (as they might\nbe unusable on their own after potential patches have been applied) because they\nreside in special directories for Kivy that are not accessed by Python by\ndefault.\n\nKivy extensions are provided as ``*.kex`` files. They are really just zip files,\nbut you must not unzip them yourself. Kivy will do that for you as soon as it's\nappropriate to do so.\n\n.. warning::\n\n    Again, do not try to unzip ``*.kex`` files on your own. While unzipping will\n    work, Kivy will not be able to load the extension and will simply ignore it.\n\nWith Kivy's extension system, your application can use specially packaged\nthird-party libraries in a backwards compatible way (by specifying the version\nthat you require) even if the actual third-party library does not guarantee\nbackwards-compatibility. There will be no breakage if newer versions are\ninstalled (as a properly suited old version will still be used). For more\ninformation about that behaviour, consider the documentation of the\n:func:`~kivy.ext.load` function.\n\nIf you want to provide an extension on your own, there is a helper script that\nsets up the initial extension folder structure that Kivy requires for\nextensions. It can be found at kivy/tools/extensions/make-kivyext.py\n'''\n\nimport imp\nfrom glob import glob\nfrom os import listdir, mkdir, sep, environ\nfrom os.path import join, isdir, exists, dirname\nfrom zipfile import ZipFile\nfrom shutil import move\n\nfrom kivy.logger import Logger\n\nif not 'KIVY_DOC' in environ:\n    from kivy import kivy_userexts_dir, kivy_exts_dir\n\n    # The paths where extensions can be put as a .zip file by the user\n    EXTENSION_PATHS = [kivy_exts_dir, kivy_userexts_dir]\n\nNEED_UNZIP = True\n\n\ndef load(extname, version):\n    # XXX platform check?\n    '''Use this function to tell Kivy to load a specific version of the given\n    Extension. This is different from kivy's require() in that it will always\n    use the exact same major version you specify even if a newer (major)\n    version is available. This is because we cannot make the same\n    backwards-compatibility guarantee that we make with Kivy for third-party\n    extensions. You will still get fixes and optimizations that don't break\n    backwards compatibility via minor version upgrades of the extension.\n\n    The function will then return the loaded module as a Python module object\n    and you can bind it to a name of your choosing. This prevents clashes with\n    modules with the same name that might be installed in a system directory.\n\n    Usage example for this function::\n\n        from kivy.ext import load\n        myextension = load('myextension', (2, 1))\n        # You can now use myextension as if you had done ``import myextension``,\n        # but with the added benefit of using the proper version.\n\n    :Parameters:\n        `extname`: str\n            The exact name of the extension that you want to use.\n        `version`: two-tuple of ints\n            A tuple of the form (major, minor), where major and minor are ints\n            that specify the major and minor version number for the extension,\n            e.g. (1, 2) would be akin to 1.2. It is important to note that\n            between minor versions, backwards compatibility is guaranteed, but\n            between major versions it is not. I.e. if you change your extension\n            in a backwards incompatible way, increase the major version number\n            (and reset the minor to 0). If you just do a bug fix or add an\n            optional, backwards-compatible feature, you can just increase the\n            minor version number. If the application then requires version (1,\n            2), every version starting with that version number will be ok and\n            by default the latest version will be choosen.\n            The two ints major and minor can both be in range(0, infinity).\n    '''\n    #\n    global NEED_UNZIP\n    if NEED_UNZIP:\n        unzip_extensions()\n        NEED_UNZIP = False\n\n    # Find the one path that best satisfies the specified criteria, i.e. same\n    # extension name, same major version number, maximum available minor version\n    # number but at least the same as the specified minor version number.\n    majmatch = extname + '_' + str(version[0]) + '.*'\n    best = None\n    bestpath = None\n    globs = []\n    for epath in EXTENSION_PATHS:\n        globs.extend(glob(join(epath, majmatch)))\n    for p in globs:\n        # minmatch\n        cur = int(p.rsplit('.')[-1])\n        if best is None or cur > best:\n            best = cur\n            bestpath = p\n    if best >= version[1]:\n        searchpath = [bestpath]\n    else:\n        # Didn't find a matching extension\n        raise ImportError(\"No extension found that satisfies your criteria: \" +\n                          \"('%s', %s)\" % (extname, version))\n\n    file, pathname, desc = imp.find_module(extname, searchpath)\n    msg = 'Extension found for ' + repr(extname) + ':\\n\\t' + str(file) + \\\n          '\\n\\t' + str(pathname) + '\\n\\t' + str(desc)\n    Logger.debug(msg)\n\n    try:\n        mod = imp.load_module(extname, file, pathname, desc)\n    finally:\n        if file:\n            file.close()\n\n    return mod\n\n\ndef _is_valid_ext_name(name):\n    try:\n        extname, version = name.split('_')\n        major, minor = version.split('.')\n        major, minor = int(major), int(minor)\n    except:\n        print(\"The name '%s' is not a valid extension name.\" % name)\n        return False\n    return (extname, (major, minor))\n\n\ndef unzip_extensions():\n    '''Unzips Kivy extensions. Internal usage only: don't use it yourself unless\n    you know what you're doing and really want to trigger installation of new\n    extensions.\n\n    For your file to be recognized as an extension, it has to fulfil a few\n    requirements:\n\n     * We require that the file has the ``*.kex`` extension to make the\n       distinction between a Kivy extension and an ordinary zip file clear.\n\n     * We require that the ``*.kex`` extension files be put into any of the\n       directories listed in EXTENSION_PATHS which is normally\n       ~/.kivy/extensions and extensions/ inside kivy's base directory. We do\n       not look for extensions on sys.path or elsewhere in the system.\n\n     * We require that the Kivy extension is zipped in a way so that Python's\n       zipfile module can extract it properly.\n\n     * We require that the extension internally obeys the common Kivy extension\n       format, which looks like this::\n\n            |-- myextension/\n                |-- __init__.py\n                |-- data/\n\n       The ``__init__.py`` file is the main entrypoint to the extension. All\n       names that should be usable when the extension is loaded need to be\n       exported (i.e. made available) in the namespace of that file.\n\n       How the extension accesses the code of the library that it wraps (be it\n       pure Python or binary code) is up to the extension. For example there\n       could be another Python module adjacent to the ``__init__.py`` file from\n       which the ``__init__.py`` file imports the usable names that it wants to\n       expose.\n\n     * We require that the version of the extension be specified in the\n       ``setup.py`` file that is created by the Kivy extension wizard and that\n       the version specification format as explained in :func:`~kivy.ext.load`\n       be used.\n    '''\n    Logger.debug('Searching for new extension in %s' % EXTENSION_PATHS)\n\n    for epath in EXTENSION_PATHS:\n        if not isdir(epath):\n            try:\n                mkdir(epath)\n            except OSError:\n                continue\n            files = []\n        else:\n            files = listdir(epath)\n        for zipfn in glob(join(epath, '*.kex')):\n            # ZipFile only became a context manager in python 2.7...\n            # with ZipFile(zipfn, 'r') as zipf:\n            # fail = is_invalid = False\n            try:\n                zipf = ZipFile(zipfn)\n                # /path/to/MyExt-1.0.linux-x86_64.zip\n                # /path/to/MyExt-1.0.macos-10.6-x86_64.zip\n                extname = zipfn.rsplit(sep)[-1][:-4]\n                # MyExt-1.0.linux-x86_64\n                # MyExt-1.0.macosx-10.6-x86_64\n                t = extname.split('-')\n                extname = t[0]\n                version = '-'.join(t[1:])\n                version = '.'.join(version.split('.')[:2])\n\n                extdir = extname + '_' + version\n\n                # is_invalid = not _is_valid_ext_name(extdir)\n            except IOError:\n                Logger.warn(\"Malformed zipfile '%s'! Skipping it.\" % zipfn)\n                continue\n            except Exception as e:\n                Logger.warn(\"Malformed extension '%s'! Skipping it.\" % zipfn)\n                zipf.close()\n                continue\n\n            already_unzipped = False\n            if extdir in files:\n                Logger.trace((\"Extension '%s' has already been \" % extname) +\n                              \"extracted manually, just moving the zip.\")\n                already_unzipped = True\n\n            # Filter the namelist of zipfile to take only the members that start\n            # with the extension name (MyExt/...)\n            members = [x for x in zipf.namelist()\n                       if x.startswith(extname + '/')]\n\n            if not already_unzipped:\n                # Unzip the extension\n                try:\n                    cache_directories = []\n                    mkdir(join(epath, extdir))\n                    # I know that there is zipf.extract() and zipf.extractall(),\n                    # but on OSX, Python 2.6 is the default and in that version,\n                    # both methods have a bug. Fixed in 2.7 only. So use this\n                    # workaround until apple upgrades its python. See\n                    # http://bugs.python.org/issue4710\n                    for member in members:\n                        # In zipfiles, folders always end with '/' regardless\n                        # of the OS\n                        mempath = join(epath, extdir, member)\n                        directory = dirname(mempath)\n                        if not directory in cache_directories:\n                            cache_directories.append(directory)\n                            if not exists(directory):\n                                mkdir(join(epath, extdir, directory))\n                        with open(join(epath, extdir, member), 'wb') as fd:\n                            fd.write(zipf.read(member))\n                except Exception as e:\n                    # Catch any error, e.g. non-writable directory, etc.\n                    Logger.error(\"Failed installing extension \" +\n                                 \"'%s' %s.\" % (extname, e))\n                    return\n                finally:\n                    zipf.close()\n                Logger.info(\"Installed extension '%s'.\" % extname)\n\n            # Move the zip out of the way so that it won't be installed again\n            # The user can just delete it, but we'll keep it around in case the\n            # user needs it again.\n            consumed_dir = join(epath, '_consumed_zips')\n            if not isdir(consumed_dir):\n                mkdir(consumed_dir)\n            move(zipfn, consumed_dir)\n"
  },
  {
    "path": "tickeys/kivy/extras/__init__.py",
    "content": "\n"
  },
  {
    "path": "tickeys/kivy/extras/highlight.py",
    "content": "'''Pygments lexer for kv language\n'''\nfrom pygments.lexer import RegexLexer, bygroups, using\nfrom pygments.lexers.agile import PythonLexer\nfrom pygments import highlight\nfrom pygments.token import *\nfrom pygments.formatters import get_formatter_by_name\nimport sys\n\n\nclass KivyLexer(RegexLexer):\n    name = 'Kivy'\n    aliases = ['kivy', 'kv']\n    filenames = ['*.kv']\n    tokens = {\n        'root': [\n            (r'#:.*?$', Comment.Preproc),\n            (r'#.*?$', using(PythonLexer)),\n            (r'\\s+', Text),\n            (r'<.+>', Name.Namespace),\n            (r'(\\[)(\\s*)(.*?)(\\s*)(@)',\n                bygroups(Punctuation, Text, Name.Class, Text, Operator),\n                'classList'),\n            (r'[A-Za-z][A-Za-z0-9]*$', Name.Attribute),\n            (r'(.*?)(\\s*)(:)(\\s*)$',\n                bygroups(Name.Class, Text, Punctuation, Text)),\n            (r'(.*?)(\\s*)(:)(\\s*)(.*?)$',\n                bygroups(Name.Attribute, Text, Punctuation, Text,\n                using(PythonLexer)))],\n        'classList': [\n            (r'(,)(\\s*)([A-Z][A-Za-z0-9]*)',\n                bygroups(Punctuation, Text, Name.Class)),\n            (r'(\\+)(\\s*)([A-Z][A-Za-z0-9]*)',\n                bygroups(Operator, Text, Name.Class)),\n            (r'\\s+', Text),\n            (r'[A-Z][A-Za-z0-9]*', Name.Class),\n            (r'\\]', Punctuation, '#pop')]}\n\n\nif __name__ == '__main__':\n    ''' This lexer will highlight .kv file. The first argument is the source\n    file, the second argument is the format of the destination and the third\n    argument is the output filename\n    '''\n    if len(sys.argv) is not 4:\n        raise Exception('Three arguments expected, found %s' %\n            (len(sys.argv) - 1))\n    k = KivyLexer()\n    with open(sys.argv[1], 'r') as fd:\n        with open(sys.argv[3], 'w') as out:\n            highlight(fd.read(), k, get_formatter_by_name(sys.argv[2]), out)\n"
  },
  {
    "path": "tickeys/kivy/factory.py",
    "content": "'''\nFactory object\n==============\n\nThe factory can be used to automatically register any class or module\nand instantiate classes from it anywhere in your project. It is an\nimplementation of the\n`Factory Pattern <http://en.wikipedia.org/wiki/Factory_pattern>`_.\n\nThe class list and available modules are automatically generated by setup.py.\n\nExample for registering a class/module::\n\n    >>> from kivy.factory import Factory\n    >>> Factory.register('Widget', module='kivy.uix.widget')\n    >>> Factory.register('Vector', module='kivy.vector')\n\nExample of using the Factory::\n\n    >>> from kivy.factory import Factory\n    >>> widget = Factory.Widget(pos=(456,456))\n    >>> vector = Factory.Vector(9, 2)\n\nExample using a class name::\n\n    >>> from kivy.factory import Factory\n    >>> Factory.register('MyWidget', cls=MyWidget)\n\nBy default, the first classname you register via the factory is permanent.\nIf you wish to change the registered class, you need to unregister the\nclassname before you re-assign it::\n\n    >>> from kivy.factory import Factory\n    >>> Factory.register('MyWidget', cls=MyWidget)\n    >>> widget = Factory.MyWidget()\n    >>> Factory.unregister('MyWidget')\n    >>> Factory.register('MyWidget', cls=CustomWidget)\n    >>> customWidget = Factory.MyWidget()\n'''\n\n__all__ = ('Factory', 'FactoryException')\n\nfrom kivy.logger import Logger\n\n\nclass FactoryException(Exception):\n    pass\n\n\nclass FactoryBase(object):\n\n    def __init__(self):\n        super(FactoryBase, self).__init__()\n        self.classes = {}\n\n    def is_template(self, classname):\n        '''Return True if the classname is a template from the\n        :class:`~kivy.lang.Builder`.\n\n        .. versionadded:: 1.0.5\n        '''\n        if classname in self.classes:\n            return self.classes[classname]['is_template']\n        else:\n            return False\n\n    def register(self, classname, cls=None, module=None, is_template=False,\n                 baseclasses=None, filename=None, warn=False):\n        '''Register a new classname referring to a real class or\n        class definition in a module. Warn, if True will emit a warning message\n        when a class is re-declared.\n\n        .. versionchanged:: 1.9.0\n            `warn` was added.\n\n        .. versionchanged:: 1.7.0\n            :attr:`baseclasses` and :attr:`filename` added\n\n        .. versionchanged:: 1.0.5\n            :attr:`is_template` has been added in 1.0.5.\n        '''\n        if cls is None and module is None and baseclasses is None:\n            raise ValueError(\n                'You must specify either cls= or module= or baseclasses =')\n        if classname in self.classes:\n            if warn:\n                info = self.classes[classname]\n                Logger.warning('Factory: Ignored class \"{}\" re-declaration. '\n                'Current -  module: {}, cls: {}, baseclass: {}, filename: {}. '\n                'Ignored -  module: {}, cls: {}, baseclass: {}, filename: {}.'.\n                format(classname, info['module'], info['cls'],\n                       info['baseclasses'], info['filename'], module, cls,\n                       baseclasses, filename))\n            return\n        self.classes[classname] = {\n            'module': module,\n            'cls': cls,\n            'is_template': is_template,\n            'baseclasses': baseclasses,\n            'filename': filename}\n\n    def unregister(self, *classnames):\n        '''Unregisters the classnames previously registered via the\n        register method. This allows the same classnames to be re-used in\n        different contexts.\n\n        .. versionadded:: 1.7.1\n        '''\n        for classname in classnames:\n            if classname in self.classes:\n                self.classes.pop(classname)\n\n    def unregister_from_filename(self, filename):\n        '''Unregister all the factory objects related to the filename passed in\n        the parameter.\n\n        .. versionadded:: 1.7.0\n        '''\n        to_remove = [x for x in self.classes\n                     if self.classes[x]['filename'] == filename]\n        for name in to_remove:\n            del self.classes[name]\n\n    def __getattr__(self, name):\n        classes = self.classes\n        if name not in classes:\n            if name[0] == name[0].lower():\n                # if trying to access attributes like checking for `bind`\n                # then raise AttributeError\n                raise AttributeError\n            raise FactoryException('Unknown class <%s>' % name)\n\n        item = classes[name]\n        cls = item['cls']\n\n        # No class to return, import the module\n        if cls is None:\n            if item['module']:\n                module = __import__(name=item['module'], fromlist='.')\n                if not hasattr(module, name):\n                    raise FactoryException(\n                        'No class named <%s> in module <%s>' % (\n                            name, item['module']))\n                cls = item['cls'] = getattr(module, name)\n\n            elif item['baseclasses']:\n                rootwidgets = []\n                for basecls in item['baseclasses'].split('+'):\n                    rootwidgets.append(Factory.get(basecls))\n                cls = item['cls'] = type(str(name), tuple(rootwidgets), {})\n\n            else:\n                raise FactoryException('No information to create the class')\n\n        return cls\n\n    get = __getattr__\n\n\n#: Factory instance to use for getting new classes\nFactory = FactoryBase()\n\n# Now import the file with all registers\n# automatically generated by build_factory\nimport kivy.factory_registers  # NOQA\nLogger.info('Factory: %d symbols loaded' % len(Factory.classes))\n\nif __name__ == '__main__':\n    Factory.register('Vector', module='kivy.vector')\n    Factory.register('Widget', module='kivy.uix.widget')\n"
  },
  {
    "path": "tickeys/kivy/factory_registers.py",
    "content": "# Auto-generated file by setup.py build_factory\n\nfrom kivy.factory import Factory\n\nr = Factory.register\nr('Adapter', module='kivy.adapters.adapter')\nr('ListAdapter', module='kivy.adapters.listadapter')\nr('SimpleListAdapter', module='kivy.adapters.simplelistadapter')\nr('DictAdapter', module='kivy.adapters.dictadapter')\nr('SelectableDataItem', module='kivy.adapters.models')\nr('Animation', module='kivy.animation')\nr('AnimationTransition', module='kivy.animation')\nr('ExceptionHandler', module='kivy.base')\nr('Cache', module='kivy.cache')\nr('ClockBase', module='kivy.clock')\nr('ColorPicker', module='kivy.uix.colorpicker')\nr('ColorWheel', module='kivy.uix.colorpicker')\nr('ConfigParser', module='kivy.config')\nr('EventDispatcher', module='kivy.event')\nr('Observable', module='kivy.event')\nr('FactoryException', module='kivy.factory')\nr('Gesture', module='kivy.gesture')\nr('GestureDatabase', module='kivy.gesture')\nr('GesturePoint', module='kivy.gesture')\nr('GestureStroke', module='kivy.gesture')\nr('Parser', module='kivy.lang')\nr('LoaderBase', module='kivy.loader')\nr('ProxyImage', module='kivy.loader')\nr('LoggerHistory', module='kivy.logger')\nr('NumericProperty', module='kivy.properties')\nr('StringProperty', module='kivy.properties')\nr('ListProperty', module='kivy.properties')\nr('ObjectProperty', module='kivy.properties')\nr('BooleanProperty', module='kivy.properties')\nr('BoundedNumericProperty', module='kivy.properties')\nr('OptionProperty', module='kivy.properties')\nr('ReferenceListProperty', module='kivy.properties')\nr('AliasProperty', module='kivy.properties')\nr('NumericProperty', module='kivy.properties')\nr('Property', module='kivy.properties')\nr('SafeList', module='kivy.utils')\nr('Vector', module='kivy.vector')\nr('Color', module='kivy.graphics.context_instructions')\nr('BindTexture', module='kivy.graphics.context_instructions')\nr('PushMatrix', module='kivy.graphics.context_instructions')\nr('PopMatrix', module='kivy.graphics.context_instructions')\nr('Rotate', module='kivy.graphics.context_instructions')\nr('Scale', module='kivy.graphics.context_instructions')\nr('Translate', module='kivy.graphics.context_instructions')\nr('MatrixInstruction', module='kivy.graphics.context_instructions')\nr('Fbo', module='kivy.graphics.fbo')\nr('Instruction', module='kivy.graphics.instructions')\nr('InstructionGroup', module='kivy.graphics.instructions')\nr('ContextInstruction', module='kivy.graphics.instructions')\nr('VertexInstruction', module='kivy.graphics.instructions')\nr('Canvas', module='kivy.graphics.instructions')\nr('CanvasBase', module='kivy.graphics.instructions')\nr('RenderContext', module='kivy.graphics.instructions')\nr('Shader', module='kivy.graphics.shader')\nr('Texture', module='kivy.graphics.texture')\nr('TextureRegion', module='kivy.graphics.texture')\nr('Matrix', module='kivy.graphics.transformation')\nr('VBO', module='kivy.graphics.vbo')\nr('VertexBatch', module='kivy.graphics.vbo')\nr('StencilPush', module='kivy.graphics.stencil_instructions')\nr('StencilPop', module='kivy.graphics.stencil_instructions')\nr('StencilUse', module='kivy.graphics.stencil_instructions')\nr('StencilUnUse', module='kivy.graphics.stencil_instructions')\nr('Triangle', module='kivy.graphics.vertex_instructions')\nr('Quad', module='kivy.graphics.vertex_instructions')\nr('Rectangle', module='kivy.graphics.vertex_instructions')\nr('BorderImage', module='kivy.graphics.vertex_instructions')\nr('Ellipse', module='kivy.graphics.vertex_instructions')\nr('Line', module='kivy.graphics.vertex_instructions')\nr('SmoothLine', module='kivy.graphics.vertex_instructions')\nr('Point', module='kivy.graphics.vertex_instructions')\nr('Bezier', module='kivy.graphics.vertex_instructions')\nr('Mesh', module='kivy.graphics.vertex_instructions')\nr('Svg', module='kivy.graphics.svg')\nr('MotionEventFactory', module='kivy.input.factory')\nr('MotionEventProvider', module='kivy.input.provider')\nr('Shape', module='kivy.input.shape')\nr('ShapeRect', module='kivy.input.shape')\nr('ActionBar', module='kivy.uix.actionbar')\nr('ActionItem', module='kivy.uix.actionbar')\nr('ActionButton', module='kivy.uix.actionbar')\nr('ActionToggleButton', module='kivy.uix.actionbar')\nr('ActionCheck', module='kivy.uix.actionbar')\nr('ActionSeparator', module='kivy.uix.actionbar')\nr('ActionDropDown', module='kivy.uix.actionbar')\nr('ActionGroup', module='kivy.uix.actionbar')\nr('ActionOverflow', module='kivy.uix.actionbar')\nr('ActionView', module='kivy.uix.actionbar')\nr('ContextualActionView', module='kivy.uix.actionbar')\nr('AnchorLayout', module='kivy.uix.anchorlayout')\nr('BoxLayout', module='kivy.uix.boxlayout')\nr('GridLayout', module='kivy.uix.gridlayout')\nr('PageLayout', module='kivy.uix.pagelayout')\nr('Accordion', module='kivy.uix.accordion')\nr('AccordionItem', module='kivy.uix.accordion')\nr('Button', module='kivy.uix.button')\nr('ButtonBehavior', module='kivy.uix.behaviors')\nr('ToggleButtonBehavior', module='kivy.uix.behaviors')\nr('DragBehavior', module='kivy.uix.behaviors')\nr('FocusBehavior', module='kivy.uix.behaviors')\nr('CompoundSelectionBehavior', module='kivy.uix.behaviors')\nr('Bubble', module='kivy.uix.bubble')\nr('BubbleButton', module='kivy.uix.bubble')\nr('Camera', module='kivy.uix.camera')\nr('Carousel', module='kivy.uix.carousel')\nr('CodeInput', module='kivy.uix.codeinput')\nr('CheckBox', module='kivy.uix.checkbox')\nr('DropDown', module='kivy.uix.dropdown')\nr('EffectWidget', module='kivy.uix.effectwidget')\nr('FloatLayout', module='kivy.uix.floatlayout')\nr('RelativeLayout', module='kivy.uix.relativelayout')\nr('ScatterLayout', module='kivy.uix.scatterlayout')\nr('ScatterPlaneLayout', module='kivy.uix.scatterlayout')\nr('FileChooserListView', module='kivy.uix.filechooser')\nr('FileChooserIconView', module='kivy.uix.filechooser')\nr('FileChooser', module='kivy.uix.filechooser')\nr('Image', module='kivy.uix.image')\nr('AsyncImage', module='kivy.uix.image')\nr('Label', module='kivy.uix.label')\nr('Layout', module='kivy.uix.layout')\nr('AbstractView', module='kivy.uix.abstractview')\nr('CompositeListItem', module='kivy.uix.listview')\nr('ListItemButton', module='kivy.uix.listview')\nr('ListItemLabel', module='kivy.uix.listview')\nr('ListView', module='kivy.uix.listview')\nr('SelectableView', module='kivy.uix.listview')\nr('ModalView', module='kivy.uix.modalview')\nr('ProgressBar', module='kivy.uix.progressbar')\nr('Popup', module='kivy.uix.popup')\nr('Scatter', module='kivy.uix.scatter')\nr('ScatterPlane', module='kivy.uix.scatter')\nr('ScrollView', module='kivy.uix.scrollview')\nr('Settings', module='kivy.uix.settings')\nr('Slider', module='kivy.uix.slider')\nr('Screen', module='kivy.uix.screenmanager')\nr('ScreenManager', module='kivy.uix.screenmanager')\nr('Spinner', module='kivy.uix.spinner')\nr('Splitter', module='kivy.uix.splitter')\nr('StackLayout', module='kivy.uix.stacklayout')\nr('StencilView', module='kivy.uix.stencilview')\nr('Switch', module='kivy.uix.switch')\nr('TabbedPanel', module='kivy.uix.tabbedpanel')\nr('TabbedPanelHeader', module='kivy.uix.tabbedpanel')\nr('TextInput', module='kivy.uix.textinput')\nr('ToggleButton', module='kivy.uix.togglebutton')\nr('TreeView', module='kivy.uix.treeview')\nr('TreeViewLabel', module='kivy.uix.treeview')\nr('TreeViewNode', module='kivy.uix.treeview')\nr('ShaderTransition', module='kivy.uix.screenmanager')\nr('SlideTransition', module='kivy.uix.screenmanager')\nr('SwapTransition', module='kivy.uix.screenmanager')\nr('WipeTransition', module='kivy.uix.screenmanager')\nr('FadeTransition', module='kivy.uix.screenmanager')\nr('Sandbox', module='kivy.uix.sandbox')\nr('Video', module='kivy.uix.video')\nr('VideoPlayer', module='kivy.uix.videoplayer')\nr('VideoPlayerVolume', module='kivy.uix.videoplayer')\nr('VideoPlayerStop', module='kivy.uix.videoplayer')\nr('VideoPlayerPlayPause', module='kivy.uix.videoplayer')\nr('VideoPlayerProgressBar', module='kivy.uix.videoplayer')\nr('VKeyboard', module='kivy.uix.vkeyboard')\nr('Widget', module='kivy.uix.widget')\nr('WidgetException', module='kivy.uix.widget')\nr('RstDocument', module='kivy.uix.rst')\nr('KineticEffect', module='kivy.effects.kinetic')\nr('ScrollEffect', module='kivy.effects.scroll')\nr('DampedScrollEffect', module='kivy.effects.dampedscroll')\nr('OpacityScrollEffect', module='kivy.effects.opacityscroll')\nr('Recognizer', module='kivy.multistroke')\nr('MultistrokeGesture', module='kivy.multistroke')\nr('UnistrokeTemplate', module='kivy.multistroke')\nr('ProgressTracker', module='kivy.multistroke')\nr('GestureSurface', module='kivy.uix.gesturesurface')\nr('GestureContainer', module='kivy.uix.gesturesurface')\n"
  },
  {
    "path": "tickeys/kivy/garden/__init__.py",
    "content": "'''\nGarden\n======\n\n.. versionadded:: 1.7.0\n\n.. versionchanged:: 1.8.0\n\nGarden is a project to centralize addons for Kivy maintained by users. You can\nfind more information at `Kivy Garden <http://kivy-garden.github.io/>`_. All\nthe garden packages are centralized on the `kivy-garden Github\n<https://github.com/kivy-garden>`_ repository.\n\nGarden is now distributed as a separate Python module, kivy-garden. You can\ninstall it with pip::\n\n    pip install kivy-garden\n\nThe garden module does not initially include any packages. You can download\nthem with the garden tool installed by the pip package::\n\n    # Installing a garden package\n    garden install graph\n\n    # Upgrade a garden package\n    garden install --upgrade graph\n\n    # Uninstall a garden package\n    garden uninstall graph\n\n    # List all the garden packages installed\n    garden list\n\n    # Search new packages\n    garden search\n\n    # Search all the packages that contain \"graph\"\n    garden search graph\n\n    # Show the help\n    garden --help\n\nAll the garden packages are installed by default in `~/.kivy/garden`.\n\n.. Note:: In previous versions of Kivy, garden was a tool at\n          kivy/tools/garden. This no longer exists, but the\n          kivy-garden module provides exactly the same functionality.\n\nPackaging\n---------\n\nIf you want to include garden packages in your application, you can add `--app`\nto the `install` command. This will create a `libs/garden` directory in your\ncurrent directory which will be used by `kivy.garden`.\n\nFor example::\n\n    cd myapp\n    garden install --app graph\n\n\n'''\n\n__path__ = 'kivy.garden'\n\nimport sys\nimport imp\nfrom os.path import dirname, join, realpath, exists, abspath\nfrom kivy import kivy_home_dir\nimport kivy\n\n#: system path where garden modules can be installed\ngarden_system_dir = join(kivy_home_dir, 'garden')\ngarden_kivy_dir = abspath(join(dirname(kivy.__file__), 'garden'))\n\n#: application path where garden modules can be installed\nif getattr(sys, 'frozen', False) and getattr(sys, '_MEIPASS', False):\n    garden_app_dir = join(realpath(sys._MEIPASS), 'libs', 'garden')\nelse:\n    garden_app_dir = join(realpath(dirname(sys.argv[0])), 'libs', 'garden')\n\n\nclass GardenImporter(object):\n\n    def find_module(self, fullname, path):\n        if path == 'kivy.garden':\n            return self\n\n    def load_module(self, fullname):\n        assert(fullname.startswith('kivy.garden'))\n\n        moddir = join(garden_kivy_dir, fullname.split('.', 2)[-1])\n        if exists(moddir):\n            return self._load_module(fullname, moddir)\n\n        modname = fullname.split('.', 1)[-1]\n        for directory in (garden_app_dir, garden_system_dir):\n            moddir = join(directory, modname)\n            if exists(moddir):\n                return self._load_module(fullname, moddir)\n\n    def _load_module(self, fullname, moddir):\n        mod = imp.load_module(fullname, None, moddir,\n                              ('', '', imp.PKG_DIRECTORY))\n        return mod\n\n\n# insert the garden importer as ultimate importer\nsys.meta_path.append(GardenImporter())\n"
  },
  {
    "path": "tickeys/kivy/geometry.py",
    "content": "'''\nGeometry utilities\n==================\n\nThis module contains some helper functions for geometric calculations.\n'''\n\n__all__ = ('circumcircle', 'minimum_bounding_circle')\n\nfrom kivy.vector import Vector\n\n\ndef circumcircle(a, b, c):\n    '''\n    Computes the circumcircle of a triangle defined by a, b, c.\n    See: http://en.wikipedia.org/wiki/Circumscribed_circle\n\n    :Parameters:\n        `a` : iterable containing at least 2 values (for x and y)\n            The 1st point of the triangle.\n        `b` : iterable containing at least 2 values (for x and y)\n            The 2nd point of the triangle.\n        `c` : iterable containing at least 2 values (for x and y)\n            The 3rd point of the triangle.\n\n    :Return:\n        A tuple that defines the circle :\n         * The first element in the returned tuple is the center as (x, y)\n         * The second is the radius (float)\n    '''\n    P = Vector(a[0], a[1])\n    Q = Vector(b[0], b[1])\n    R = Vector(c[0], c[1])\n\n    mPQ = (P + Q) * .5\n    mQR = (Q + R) * .5\n\n    numer = -(- mPQ.y * R.y + mPQ.y * Q.y + mQR.y * R.y - mQR.y * Q.y\n              - mPQ.x * R.x + mPQ.x * Q.x + mQR.x * R.x - mQR.x * Q.x)\n    denom = (-Q.x * R.y + P.x * R.y - P.x * Q.y +\n             Q.y * R.x - P.y * R.x + P.y * Q.x)\n\n    t = numer / denom\n\n    cx = -t * (Q.y - P.y) + mPQ.x\n    cy = t * (Q.x - P.x) + mPQ.y\n\n    return ((cx, cy), (P - (cx, cy)).length())\n\n\ndef minimum_bounding_circle(points):\n    '''\n    Returns the minimum bounding circle for a set of points.\n\n    For a description of the problem being solved, see the `Smallest Circle\n    Problem <http://en.wikipedia.org/wiki/Smallest_circle_problem>`_.\n\n    The function uses Applet's Algorithm, the runtime is O\\(h^3, \\*n\\),\n    where h is the number of points in the convex hull of the set of points.\n    **But** it runs in linear time in almost all real world cases.\n    See: http://tinyurl.com/6e4n5yb\n\n    :Parameters:\n        `points` : iterable\n            A list of points (2 tuple with x,y coordinates)\n\n    :Return:\n        A tuple that defines the circle:\n            * The first element in the returned tuple is the center (x, y)\n            * The second the radius (float)\n\n    '''\n    points = [Vector(p[0], p[1]) for p in points]\n\n    if len(points) == 1:\n        return (points[0].x, points[0].y), 0.0\n\n    if len(points) == 2:\n        p1, p2 = points\n        return (p1 + p2) * .5, ((p1 - p2) * .5).length()\n\n    # determine a point P with the smallest y value\n    P = min(points, key=lambda p: p.y)\n\n    # find a point Q such that the angle of the line segment\n    # PQ with the x axis is minimal\n    def x_axis_angle(q):\n        if q == P:\n            return 1e10  # max val if the same, to skip\n        return abs((q - P).angle((1, 0)))\n    Q = min(points, key=x_axis_angle)\n\n    for p in points:\n        # find R such that angle PRQ is minimal\n        def angle_pq(r):\n            if r in (P, Q):\n                return 1e10  # max val if the same, to skip\n            return abs((r - P).angle(r - Q))\n        R = min(points, key=angle_pq)\n\n        # check for case 1 (angle PRQ is obtuse), the circle is determined\n        # by two points, P and Q. radius = |(P-Q)/2|, center = (P+Q)/2\n        if angle_pq(R) > 90.0:\n            return (P + Q) * .5, ((P - Q) * .5).length()\n\n        # if angle RPQ is obtuse, make P = R, and try again\n        if abs((R - P).angle(Q - P)) > 90:\n            P = R\n            continue\n\n        # if angle PQR is obtuse, make Q = R, and try again\n        if abs((P - Q).angle(R - Q)) > 90:\n            Q = R\n            continue\n\n        # all angles were acute..we just need the circle through the\n        # two points furthest apart!\n        break\n\n    # find the circumcenter for triangle given by P,Q,R\n    return circumcircle(P, Q, R)\n"
  },
  {
    "path": "tickeys/kivy/gesture.py",
    "content": "'''\nGesture recognition\n===================\n\nThis class allows you to easily create new\ngestures and compare them::\n\n    from kivy.gesture import Gesture, GestureDatabase\n\n    # Create a gesture\n    g = Gesture()\n    g.add_stroke(point_list=[(1,1), (3,4), (2,1)])\n    g.normalize()\n\n    # Add it to the database\n    gdb = GestureDatabase()\n    gdb.add_gesture(g)\n\n    # And for the next gesture, try to find it!\n    g2 = Gesture()\n    # ...\n    gdb.find(g2)\n\n.. warning::\n\n   You don't really want to do this: it's more of an example of how\n   to construct gestures dynamically. Typically, you would\n   need a lot more points, so it's better to record gestures in a file and\n   reload them to compare later. Look in the examples/gestures directory for\n   an example of how to do that.\n\n'''\n\n__all__ = ('Gesture', 'GestureDatabase', 'GesturePoint', 'GestureStroke')\n\nimport pickle\nimport base64\nimport zlib\nimport math\n\nfrom kivy.vector import Vector\n\nfrom io import BytesIO\n\n\nclass GestureDatabase(object):\n    '''Class to handle a gesture database.'''\n\n    def __init__(self):\n        self.db = []\n\n    def add_gesture(self, gesture):\n        '''Add a new gesture to the database.'''\n        self.db.append(gesture)\n\n    def find(self, gesture, minscore=0.9, rotation_invariant=True):\n        '''Find a matching gesture in the database.'''\n        if not gesture:\n            return\n\n        best = None\n        bestscore = minscore\n        for g in self.db:\n            score = g.get_score(gesture, rotation_invariant)\n            if score < bestscore:\n                continue\n            bestscore = score\n            best = g\n        if not best:\n            return\n        return (bestscore, best)\n\n    def gesture_to_str(self, gesture):\n        '''Convert a gesture into a unique string.'''\n        io = BytesIO()\n        p = pickle.Pickler(io)\n        p.dump(gesture)\n        data = base64.b64encode(zlib.compress(io.getvalue(), 9))\n        return data\n\n    def str_to_gesture(self, data):\n        '''Convert a unique string to a gesture.'''\n        io = BytesIO(zlib.decompress(base64.b64decode(data)))\n        p = pickle.Unpickler(io)\n        gesture = p.load()\n        return gesture\n\n\nclass GesturePoint:\n\n    def __init__(self, x, y):\n        '''Stores the x,y coordinates of a point in the gesture.'''\n        self.x = float(x)\n        self.y = float(y)\n\n    def scale(self, factor):\n        ''' Scales the point by the given factor.'''\n        self.x *= factor\n        self.y *= factor\n        return self\n\n    def __repr__(self):\n        return 'Mouse_point: %f,%f' % (self.x, self.y)\n\n\nclass GestureStroke:\n    ''' Gestures can be made up of multiple strokes.'''\n\n    def __init__(self):\n        ''' A stroke in the gesture.'''\n        self.points = list()\n        self.screenpoints = list()\n\n    # These return the min and max coordinates of the stroke\n    @property\n    def max_x(self):\n        if len(self.points) == 0:\n            return 0\n        return max(self.points, key=lambda pt: pt.x).x\n\n    @property\n    def min_x(self):\n        if len(self.points) == 0:\n            return 0\n        return min(self.points, key=lambda pt: pt.x).x\n\n    @property\n    def max_y(self):\n        if len(self.points) == 0:\n            return 0\n        return max(self.points, key=lambda pt: pt.y).y\n\n    @property\n    def min_y(self):\n        if len(self.points) == 0:\n            return 0\n        return min(self.points, key=lambda pt: pt.y).y\n\n    def add_point(self, x, y):\n        '''\n        add_point(x=x_pos, y=y_pos)\n        Adds a point to the stroke.\n        '''\n        self.points.append(GesturePoint(x, y))\n        self.screenpoints.append((x, y))\n\n    def scale_stroke(self, scale_factor):\n        '''\n        scale_stroke(scale_factor=float)\n        Scales the stroke down by scale_factor.\n        '''\n        self.points = [pt.scale(scale_factor) for pt in self.points]\n\n    def points_distance(self, point1, point2):\n        '''\n        points_distance(point1=GesturePoint, point2=GesturePoint)\n        Returns the distance between two GesturePoints.\n        '''\n        x = point1.x - point2.x\n        y = point1.y - point2.y\n        return math.sqrt(x * x + y * y)\n\n    def stroke_length(self, point_list=None):\n        '''Finds the length of the stroke. If a point list is given,\n           finds the length of that list.\n        '''\n        if point_list is None:\n            point_list = self.points\n        gesture_length = 0.0\n        if len(point_list) <= 1:  # If there is only one point -> no length\n            return gesture_length\n        for i in range(len(point_list) - 1):\n            gesture_length += self.points_distance(\n                point_list[i], point_list[i + 1])\n        return gesture_length\n\n    def normalize_stroke(self, sample_points=32):\n        '''Normalizes strokes so that every stroke has a standard number of\n           points. Returns True if stroke is normalized, False if it can't be\n           normalized. sample_points controls the resolution of the stroke.\n        '''\n        # If there is only one point or the length is 0, don't normalize\n        if len(self.points) <= 1 or self.stroke_length(self.points) == 0.0:\n            return False\n\n        # Calculate how long each point should be in the stroke\n        target_stroke_size = \\\n            self.stroke_length(self.points) / float(sample_points)\n        new_points = list()\n        new_points.append(self.points[0])\n\n        # We loop on the points\n        prev = self.points[0]\n        src_distance = 0.0\n        dst_distance = target_stroke_size\n        for curr in self.points[1:]:\n            d = self.points_distance(prev, curr)\n            if d > 0:\n                prev = curr\n                src_distance = src_distance + d\n\n                # The new point need to be inserted into the\n                # segment [prev, curr]\n                while dst_distance < src_distance:\n                    x_dir = curr.x - prev.x\n                    y_dir = curr.y - prev.y\n                    ratio = (src_distance - dst_distance) / d\n                    to_x = x_dir * ratio + prev.x\n                    to_y = y_dir * ratio + prev.y\n                    new_points.append(GesturePoint(to_x, to_y))\n                    dst_distance = self.stroke_length(self.points) / \\\n                        float(sample_points) * len(new_points)\n\n        # If this happens, we are into troubles...\n        if not len(new_points) == sample_points:\n            raise ValueError('Invalid number of strokes points; got '\n                             '%d while it should be %d' %\n                             (len(new_points), sample_points))\n\n        self.points = new_points\n        return True\n\n    def center_stroke(self, offset_x, offset_y):\n        '''Centers the stroke by offseting the points.'''\n        for point in self.points:\n            point.x -= offset_x\n            point.y -= offset_y\n\n\nclass Gesture:\n    '''A python implementation of a gesture recognition algorithm by\n    Oleg Dopertchouk: http://www.gamedev.net/reference/articles/article2039.asp\n\n    Implemented by Jeiel Aranal (chemikhazi@gmail.com),\n    released into the public domain.\n    '''\n\n    # Tolerance for evaluation using the '==' operator\n    DEFAULT_TOLERANCE = 0.1\n\n    def __init__(self, tolerance=None):\n        '''\n        Gesture([tolerance=float])\n        Creates a new gesture with an optional matching tolerance value.\n        '''\n        self.width = 0.\n        self.height = 0.\n        self.gesture_product = 0.\n        self.strokes = list()\n        if tolerance is None:\n            self.tolerance = Gesture.DEFAULT_TOLERANCE\n        else:\n            self.tolerance = tolerance\n\n    def _scale_gesture(self):\n        ''' Scales down the gesture to a unit of 1.'''\n        # map() creates a list of min/max coordinates of the strokes\n        # in the gesture and min()/max() pulls the lowest/highest value\n        min_x = min([stroke.min_x for stroke in self.strokes])\n        max_x = max([stroke.max_x for stroke in self.strokes])\n        min_y = min([stroke.min_y for stroke in self.strokes])\n        max_y = max([stroke.max_y for stroke in self.strokes])\n        x_len = max_x - min_x\n        self.width = x_len\n        y_len = max_y - min_y\n        self.height = y_len\n        scale_factor = max(x_len, y_len)\n        if scale_factor <= 0.0:\n            return False\n        scale_factor = 1.0 / scale_factor\n        for stroke in self.strokes:\n            stroke.scale_stroke(scale_factor)\n        return True\n\n    def _center_gesture(self):\n        ''' Centers the Gesture.points of the gesture.'''\n        total_x = 0.0\n        total_y = 0.0\n        total_points = 0\n\n        for stroke in self.strokes:\n            # adds up all the points inside the stroke\n            stroke_y = sum([pt.y for pt in stroke.points])\n            stroke_x = sum([pt.x for pt in stroke.points])\n            total_y += stroke_y\n            total_x += stroke_x\n            total_points += len(stroke.points)\n        if total_points == 0:\n            return False\n        # Average to get the offset\n        total_x /= total_points\n        total_y /= total_points\n        # Apply the offset to the strokes\n        for stroke in self.strokes:\n            stroke.center_stroke(total_x, total_y)\n        return True\n\n    def add_stroke(self, point_list=None):\n        '''Adds a stroke to the gesture and returns the Stroke instance.\n           Optional point_list argument is a list of the mouse points for\n           the stroke.\n        '''\n        self.strokes.append(GestureStroke())\n        if isinstance(point_list, list) or isinstance(point_list, tuple):\n            for point in point_list:\n                if isinstance(point, GesturePoint):\n                    self.strokes[-1].points.append(point)\n                elif isinstance(point, list) or isinstance(point, tuple):\n                    if len(point) != 2:\n                        raise ValueError(\"Stroke entry must have 2 values max\")\n                    self.strokes[-1].add_point(point[0], point[1])\n                else:\n                    raise TypeError(\"The point list should either be \"\n                                    \"tuples of x and y or a list of \"\n                                    \"GesturePoint objects\")\n        elif point_list is not None:\n            raise ValueError(\"point_list should be a tuple/list\")\n        return self.strokes[-1]\n\n    def normalize(self, stroke_samples=32):\n        '''Runs the gesture normalization algorithm and calculates the dot\n        product with self.\n        '''\n        if not self._scale_gesture() or not self._center_gesture():\n            self.gesture_product = False\n            return False\n        for stroke in self.strokes:\n            stroke.normalize_stroke(stroke_samples)\n        self.gesture_product = self.dot_product(self)\n\n    def get_rigid_rotation(self, dstpts):\n        '''\n        Extract the rotation to apply to a group of points to minimize the\n        distance to a second group of points. The two groups of points are\n        assumed to be centered. This is a simple version that just picks\n        an angle based on the first point of the gesture.\n        '''\n        if len(self.strokes) < 1 or len(self.strokes[0].points) < 1:\n            return 0\n        if len(dstpts.strokes) < 1 or len(dstpts.strokes[0].points) < 1:\n            return 0\n        p = dstpts.strokes[0].points[0]\n        target = Vector([p.x, p.y])\n        source = Vector([p.x, p.y])\n        return source.angle(target)\n\n    def dot_product(self, comparison_gesture):\n        ''' Calculates the dot product of the gesture with another gesture.'''\n        if len(comparison_gesture.strokes) != len(self.strokes):\n            return -1\n        if getattr(comparison_gesture, 'gesture_product', True) is False or \\\n           getattr(self, 'gesture_product', True) is False:\n            return -1\n        dot_product = 0.0\n        for stroke_index, (my_stroke, cmp_stroke) in enumerate(\n                list(zip(self.strokes, comparison_gesture.strokes))):\n            for pt_index, (my_point, cmp_point) in enumerate(\n                    list(zip(my_stroke.points, cmp_stroke.points))):\n                dot_product += (my_point.x * cmp_point.x +\n                                my_point.y * cmp_point.y)\n        return dot_product\n\n    def rotate(self, angle):\n        g = Gesture()\n        for stroke in self.strokes:\n            tmp = []\n            for j in stroke.points:\n                v = Vector([j.x, j.y]).rotate(angle)\n                tmp.append(v)\n            g.add_stroke(tmp)\n        g.gesture_product = g.dot_product(g)\n        return g\n\n    def get_score(self, comparison_gesture, rotation_invariant=True):\n        ''' Returns the matching score of the gesture against another gesture.\n        '''\n        if isinstance(comparison_gesture, Gesture):\n            if rotation_invariant:\n                # get orientation\n                angle = self.get_rigid_rotation(comparison_gesture)\n\n                # rotate the gesture to be in the same frame.\n                comparison_gesture = comparison_gesture.rotate(angle)\n\n            # this is the normal \"orientation\" code.\n            score = self.dot_product(comparison_gesture)\n            if score <= 0:\n                return score\n            score /= math.sqrt(\n                self.gesture_product * comparison_gesture.gesture_product)\n            return score\n\n    def __eq__(self, comparison_gesture):\n        ''' Allows easy comparisons between gesture instances.'''\n        if isinstance(comparison_gesture, Gesture):\n            # If the gestures don't have the same number of strokes, its\n            # definitely not the same gesture\n            score = self.get_score(comparison_gesture)\n            if (score > (1.0 - self.tolerance) and\n                    score < (1.0 + self.tolerance)):\n                return True\n            else:\n                return False\n        else:\n            return NotImplemented\n\n    def __ne__(self, comparison_gesture):\n        result = self.__eq__(comparison_gesture)\n        if result is NotImplemented:\n            return result\n        else:\n            return not result\n\n    def __lt__(self, comparison_gesture):\n        raise TypeError(\"Gesture cannot be evaluated with <\")\n\n    def __gt__(self, comparison_gesture):\n        raise TypeError(\"Gesture cannot be evaluated with >\")\n\n    def __le__(self, comparison_gesture):\n        raise TypeError(\"Gesture cannot be evaluated with <=\")\n\n    def __ge__(self, comparison_gesture):\n        raise TypeError(\"Gesture cannot be evaluated with >=\")\n"
  },
  {
    "path": "tickeys/kivy/graphics/__init__.py",
    "content": "'''\nGraphics\n========\n\nThis package assembles many low level functions used for drawing. The whole\ngraphics package is compatible with OpenGL ES 2.0 and has many rendering\noptimizations.\n\nThe basics\n----------\n\nFor drawing on a screen, you will need :\n\n    1. a :class:`~kivy.graphics.instructions.Canvas` object.\n    2. :class:`~kivy.graphics.instructions.Instruction` objects.\n\nEach :class:`~kivy.uix.widget.Widget`\nin Kivy already has a :class:`Canvas` by default. When you create\na widget, you can create all the instructions needed for drawing. If\n`self` is your current widget, you can do::\n\n    from kivy.graphics import *\n    with self.canvas:\n        # Add a red color\n        Color(1., 0, 0)\n\n        # Add a rectangle\n        Rectangle(pos=(10, 10), size=(500, 500))\n\nThe instructions :class:`Color` and :class:`Rectangle` are automaticly added to\nthe canvas object and will be used when the window is drawn.\n\n.. note::\n\n    Kivy drawing instructions are not automatically relative to the widgets\n    position or size. You therefore you need to consider these factors when\n    drawing. In order to make your drawing instructions relative to the widget,\n    the instructions need either to be\n    declared in the :mod:`KvLang <kivy.lang>` or bound to pos and size changes.\n    Please see :ref:`adding_widget_background` for more detail.\n\nGL Reloading mechanism\n----------------------\n\n.. versionadded:: 1.2.0\n\nDuring the lifetime of the application, the OpenGL context might be lost. This\nhappens:\n\n- when the window is resized on MacOSX or the Windows platform and you're\n  using pygame as a window provider. This is due to SDL 1.2. In the SDL 1.2\n  design, it needs to recreate a GL context everytime the window is\n  resized. This was fixed in SDL 1.3 but pygame is not yet available on it\n  by default.\n\n- when Android releases the app resources: when your application goes to the\n  background, Android might reclaim your opengl context to give the\n  resource to another app. When the user switches back to your application, a\n  newly created gl context is given to your app.\n\nStarting from 1.2.0, we have introduced a mechanism for reloading all the\ngraphics resources using the GPU: Canvas, FBO, Shader, Texture, VBO,\nand VertexBatch:\n\n- VBO and VertexBatch are constructed by our graphics instructions. We have all\n  the data needed to reconstruct when reloading.\n\n- Shader: same as VBO, we store the source and values used in the\n  shader so we are able to recreate the vertex/fragment/program.\n\n- Texture: if the texture has a source (an image file or atlas), the image\n  is reloaded from the source and reuploaded to the GPU.\n\nYou should cover these cases yourself:\n\n- Textures without a source: if you manually created a texture and manually\n  blit data / a buffer to it, you must handle the reloading yourself. Check the\n  :doc:`api-kivy.graphics.texture` to learn how to manage that case. (The text\n  rendering already generates the texture and handles the reloading. You\n  don't need to reload text yourself.)\n\n- FBO: if you added / removed / drew things multiple times on the FBO, we\n  can't reload it. We don't keep a history of the instructions put on it.\n  As for textures without a source, check the :doc:`api-kivy.graphics.fbo` to\n  learn how to manage that case.\n\n'''\n\nfrom kivy.graphics.instructions import Callback, Canvas, CanvasBase, \\\n    ContextInstruction, Instruction, InstructionGroup, RenderContext, \\\n    VertexInstruction\nfrom kivy.graphics.context_instructions import BindTexture, Color, \\\n    PushState, ChangeState, PopState, MatrixInstruction, ApplyContextMatrix, \\\n    PopMatrix, PushMatrix, Rotate, Scale, Translate, LoadIdentity, \\\n    UpdateNormalMatrix, gl_init_resources\nfrom kivy.graphics.vertex_instructions import Bezier, BorderImage, Ellipse, \\\n    GraphicException, Line, Mesh, Point, Quad, Rectangle, Triangle\nfrom kivy.graphics.stencil_instructions import StencilPop, StencilPush, \\\n    StencilUse, StencilUnUse\nfrom kivy.graphics.gl_instructions import ClearColor, ClearBuffers\nfrom kivy.graphics.fbo import Fbo\n\n# very hacky way to avoid pyflakes warning...\n__all__ = (Bezier.__name__, BindTexture.__name__, BorderImage.__name__,\n           Callback.__name__, Canvas.__name__, CanvasBase.__name__,\n           Color.__name__, ContextInstruction.__name__,\n           Ellipse.__name__, Fbo.__name__, GraphicException.__name__,\n           Instruction.__name__, InstructionGroup.__name__,\n           Line.__name__, MatrixInstruction.__name__, Mesh.__name__,\n           Point.__name__, PopMatrix.__name__, PushMatrix.__name__,\n           Quad.__name__, Rectangle.__name__, RenderContext.__name__,\n           Rotate.__name__, Scale.__name__, StencilPop.__name__,\n           StencilPush.__name__, StencilUse.__name__,\n           StencilUnUse.__name__, Translate.__name__, Triangle.__name__,\n           VertexInstruction.__name__, ClearColor.__name__,\n           ClearBuffers.__name__, gl_init_resources.__name__,\n           PushState.__name__, ChangeState.__name__, PopState.__name__,\n           ApplyContextMatrix.__name__, UpdateNormalMatrix.__name__,\n           LoadIdentity.__name__)\n"
  },
  {
    "path": "tickeys/kivy/graphics/buffer.pxd",
    "content": "cdef class Buffer:\n    cdef void *data\n    cdef int *l_free\n    cdef int i_free\n    cdef long block_size\n    cdef long block_count\n\n    cdef void clear(self)\n    cdef void grow(self, long block_count)\n    cdef void add(self, void *blocks, unsigned short *indices, int count)\n    cdef void remove(self, unsigned short *indices, int count)\n    cdef int count(self)\n    cdef long size(self)\n    cdef void *pointer(self)\n    cdef void *offset_pointer(self, int offset)\n    cdef void update(self, int index, void* blocks, int count)\n\n"
  },
  {
    "path": "tickeys/kivy/graphics/c_opengl.pxd",
    "content": "include \"config.pxi\"\n\ncdef extern from \"gl_redirect.h\":\n\n    ctypedef void               GLvoid\n    ctypedef char               GLchar\n    ctypedef unsigned int       GLenum\n    ctypedef unsigned char      GLboolean\n    ctypedef unsigned int       GLbitfield\n    ctypedef short              GLshort\n    ctypedef int                GLint\n    ctypedef int                GLsizei\n    ctypedef unsigned short     GLushort\n    ctypedef unsigned int       GLuint\n\n    #FIXME: figure out correct cross platform tydefs\n    #ctypedef khronos_float_t  GLfloat\n    #ctypedef khronos_float_t  GLclampf\n    #ctypedef khronos_int32_t  GLfixed\n    #ctypedef khronos_intptr_t GLintptr\n    #ctypedef khronos_ssize_t  GLsizeiptr\n    ctypedef signed char        GLbyte\n    ctypedef unsigned char      GLubyte\n    ctypedef float              GLfloat\n    ctypedef float              GLclampf\n    ctypedef int                GLfixed\n    ctypedef signed long int    GLintptr\n    ctypedef signed long int    GLsizeiptr\n\n\n    #int GL_ES_VERSION_2_0\n\n    int GL_DEPTH_BUFFER_BIT\n    int GL_STENCIL_BUFFER_BIT\n    int GL_COLOR_BUFFER_BIT\n\n    int GL_FALSE\n    int GL_TRUE\n\n    int GL_POINTS\n    int GL_LINES\n    int GL_LINE_LOOP\n    int GL_LINE_STRIP\n    int GL_TRIANGLES\n    int GL_TRIANGLE_STRIP\n    int GL_TRIANGLE_FAN\n\n    int GL_ZERO\n    int GL_ONE\n    int GL_SRC_COLOR\n    int GL_ONE_MINUS_SRC_COLOR\n    int GL_SRC_ALPHA\n    int GL_ONE_MINUS_SRC_ALPHA\n    int GL_DST_ALPHA\n    int GL_ONE_MINUS_DST_ALPHA\n\n    int GL_DST_COLOR\n    int GL_ONE_MINUS_DST_COLOR\n    int GL_SRC_ALPHA_SATURATE\n\n    int GL_FUNC_ADD\n    int GL_BLEND_EQUATION\n    int GL_BLEND_EQUATION_RGB\n    int GL_BLEND_EQUATION_ALPHA\n\n    int GL_FUNC_SUBTRACT\n    int GL_FUNC_REVERSE_SUBTRACT\n\n    int GL_BLEND_DST_RGB\n    int GL_BLEND_SRC_RGB\n    int GL_BLEND_DST_ALPHA\n    int GL_BLEND_SRC_ALPHA\n    int GL_ANT_COLOR\n    int GL_ONE_MINUS_ANT_COLOR\n    int GL_ANT_ALPHA\n    int GL_ONE_MINUS_ANT_ALPHA\n    int GL_BLEND_COLOR\n\n    int GL_ARRAY_BUFFER\n    int GL_ELEMENT_ARRAY_BUFFER\n    int GL_ARRAY_BUFFER_BINDING\n    int GL_ELEMENT_ARRAY_BUFFER_BINDING\n\n    int GL_STREAM_DRAW\n    int GL_STATIC_DRAW\n    int GL_DYNAMIC_DRAW\n\n    int GL_BUFFER_SIZE\n    int GL_BUFFER_USAGE\n\n    int GL_CURRENT_VERTEX_ATTRIB\n\n    int GL_FRONT\n    int GL_BACK\n    int GL_FRONT_AND_BACK\n\n    int GL_TEXTURE_2D\n    int GL_CULL_FACE\n    int GL_BLEND\n    int GL_DITHER\n    int GL_STENCIL_TEST\n    int GL_DEPTH_TEST\n    int GL_SCISSOR_TEST\n    int GL_POLYGON_OFFSET_FILL\n    int GL_SAMPLE_ALPHA_TO_COVERAGE\n    int GL_SAMPLE_COVERAGE\n\n    int GL_NO_ERROR\n    int GL_INVALID_ENUM\n    int GL_INVALID_VALUE\n    int GL_INVALID_OPERATION\n    int GL_OUT_OF_MEMORY\n\n    int GL_CW\n    int GL_CCW\n\n    int GL_LINE_WIDTH\n    int GL_ALIASED_POINT_SIZE_RANGE\n    int GL_ALIASED_LINE_WIDTH_RANGE\n    int GL_CULL_FACE_MODE\n    int GL_FRONT_FACE\n    int GL_DEPTH_RANGE\n    int GL_DEPTH_WRITEMASK\n    int GL_DEPTH_CLEAR_VALUE\n    int GL_DEPTH_FUNC\n    int GL_STENCIL_CLEAR_VALUE\n    int GL_STENCIL_FUNC\n    int GL_STENCIL_FAIL\n    int GL_STENCIL_PASS_DEPTH_FAIL\n    int GL_STENCIL_PASS_DEPTH_PASS\n    int GL_STENCIL_REF\n    int GL_STENCIL_VALUE_MASK\n    int GL_STENCIL_WRITEMASK\n    int GL_STENCIL_BACK_FUNC\n    int GL_STENCIL_BACK_FAIL\n    int GL_STENCIL_BACK_PASS_DEPTH_FAIL\n    int GL_STENCIL_BACK_PASS_DEPTH_PASS\n    int GL_STENCIL_BACK_REF\n    int GL_STENCIL_BACK_VALUE_MASK\n    int GL_STENCIL_BACK_WRITEMASK\n    int GL_VIEWPORT\n    int GL_SCISSOR_BOX\n\n    int GL_COLOR_CLEAR_VALUE\n    int GL_COLOR_WRITEMASK\n    int GL_UNPACK_ALIGNMENT\n    int GL_PACK_ALIGNMENT\n    int GL_MAX_TEXTURE_SIZE\n    int GL_MAX_VIEWPORT_DIMS\n    int GL_SUBPIXEL_BITS\n    int GL_RED_BITS\n    int GL_GREEN_BITS\n    int GL_BLUE_BITS\n    int GL_ALPHA_BITS\n    int GL_DEPTH_BITS\n    int GL_STENCIL_BITS\n    int GL_POLYGON_OFFSET_UNITS\n\n    int GL_POLYGON_OFFSET_FACTOR\n    int GL_TEXTURE_BINDING_2D\n    int GL_SAMPLE_BUFFERS\n    int GL_SAMPLES\n    int GL_SAMPLE_COVERAGE_VALUE\n    int GL_SAMPLE_COVERAGE_INVERT\n\n    int GL_NUM_COMPRESSED_TEXTURE_FORMATS\n    int GL_COMPRESSED_TEXTURE_FORMATS\n\n    int GL_DONT_CARE\n    int GL_FASTEST\n    int GL_NICEST\n\n    int GL_GENERATE_MIPMAP_HINT\n\n    int GL_BYTE\n    int GL_UNSIGNED_BYTE\n    int GL_SHORT\n    int GL_UNSIGNED_SHORT\n    int GL_INT\n    int GL_UNSIGNED_INT\n    int GL_FLOAT\n\n    int GL_DEPTH_COMPONENT\n    int GL_ALPHA\n    int GL_RGB\n    int GL_RGBA\n    int GL_LUMINANCE\n    int GL_LUMINANCE_ALPHA\n\n    int GL_UNSIGNED_SHORT_4_4_4_4\n    int GL_UNSIGNED_SHORT_5_5_5_1\n    int GL_UNSIGNED_SHORT_5_6_5\n\n    int GL_FRAGMENT_SHADER\n    int GL_VERTEX_SHADER\n    int GL_MAX_VERTEX_ATTRIBS\n    int GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS\n    int GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS\n    int GL_MAX_TEXTURE_IMAGE_UNITS\n    int GL_SHADER_TYPE\n    int GL_DELETE_STATUS\n    int GL_LINK_STATUS\n    int GL_VALIDATE_STATUS\n    int GL_ATTACHED_SHADERS\n    int GL_ACTIVE_UNIFORMS\n    int GL_ACTIVE_UNIFORM_MAX_LENGTH\n    int GL_ACTIVE_ATTRIBUTES\n    int GL_ACTIVE_ATTRIBUTE_MAX_LENGTH\n    int GL_SHADING_LANGUAGE_VERSION\n    int GL_CURRENT_PROGRAM\n\n    int GL_NEVER\n    int GL_LESS\n    int GL_EQUAL\n    int GL_LEQUAL\n    int GL_GREATER\n    int GL_NOTEQUAL\n    int GL_GEQUAL\n    int GL_ALWAYS\n\n    int GL_KEEP\n    int GL_REPLACE\n    int GL_INCR\n    int GL_DECR\n    int GL_INVERT\n    int GL_INCR_WRAP\n    int GL_DECR_WRAP\n\n    int GL_VENDOR\n    int GL_RENDERER\n    int GL_VERSION\n    int GL_EXTENSIONS\n\n    int GL_NEAREST\n    int GL_LINEAR\n\n    int GL_NEAREST_MIPMAP_NEAREST\n    int GL_LINEAR_MIPMAP_NEAREST\n    int GL_NEAREST_MIPMAP_LINEAR\n    int GL_LINEAR_MIPMAP_LINEAR\n\n    int GL_TEXTURE_MAG_FILTER\n    int GL_TEXTURE_MIN_FILTER\n    int GL_TEXTURE_WRAP_S\n    int GL_TEXTURE_WRAP_T\n\n    int GL_TEXTURE\n\n    int GL_TEXTURE_CUBE_MAP\n    int GL_TEXTURE_BINDING_CUBE_MAP\n    int GL_TEXTURE_CUBE_MAP_POSITIVE_X\n    int GL_TEXTURE_CUBE_MAP_NEGATIVE_X\n    int GL_TEXTURE_CUBE_MAP_POSITIVE_Y\n    int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y\n    int GL_TEXTURE_CUBE_MAP_POSITIVE_Z\n    int GL_TEXTURE_CUBE_MAP_NEGATIVE_Z\n    int GL_MAX_CUBE_MAP_TEXTURE_SIZE\n\n    int GL_TEXTURE0\n    int GL_TEXTURE1\n    int GL_TEXTURE2\n    int GL_TEXTURE3\n    int GL_TEXTURE4\n    int GL_TEXTURE5\n    int GL_TEXTURE6\n    int GL_TEXTURE7\n    int GL_TEXTURE8\n    int GL_TEXTURE9\n    int GL_TEXTURE10\n    int GL_TEXTURE11\n    int GL_TEXTURE12\n    int GL_TEXTURE13\n    int GL_TEXTURE14\n    int GL_TEXTURE15\n    int GL_TEXTURE16\n    int GL_TEXTURE17\n    int GL_TEXTURE18\n    int GL_TEXTURE19\n    int GL_TEXTURE20\n    int GL_TEXTURE21\n    int GL_TEXTURE22\n    int GL_TEXTURE23\n    int GL_TEXTURE24\n    int GL_TEXTURE25\n    int GL_TEXTURE26\n    int GL_TEXTURE27\n    int GL_TEXTURE28\n    int GL_TEXTURE29\n    int GL_TEXTURE30\n    int GL_TEXTURE31\n    int GL_ACTIVE_TEXTURE\n\n\n    int GL_REPEAT\n    int GL_CLAMP_TO_EDGE\n    int GL_MIRRORED_REPEAT\n\n    int GL_FLOAT_VEC2\n    int GL_FLOAT_VEC3\n    int GL_FLOAT_VEC4\n    int GL_INT_VEC2\n    int GL_INT_VEC3\n    int GL_INT_VEC4\n    int GL_BOOL\n    int GL_BOOL_VEC2\n    int GL_BOOL_VEC3\n    int GL_BOOL_VEC4\n    int GL_FLOAT_MAT2\n    int GL_FLOAT_MAT3\n    int GL_FLOAT_MAT4\n    int GL_SAMPLER_2D\n    int GL_SAMPLER_CUBE\n\n    int GL_VERTEX_ATTRIB_ARRAY_ENABLED\n    int GL_VERTEX_ATTRIB_ARRAY_SIZE\n    int GL_VERTEX_ATTRIB_ARRAY_STRIDE\n    int GL_VERTEX_ATTRIB_ARRAY_TYPE\n    int GL_VERTEX_ATTRIB_ARRAY_NORMALIZED\n    int GL_VERTEX_ATTRIB_ARRAY_POINTER\n    int GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING\n\n    int GL_COMPILE_STATUS\n    int GL_INFO_LOG_LENGTH\n    int GL_SHADER_SOURCE_LENGTH\n\n    int GL_SHADER_BINARY_FORMATS\n\n    int GL_FRAMEBUFFER\n    int GL_RENDERBUFFER\n\n    int GL_RGBA4\n    int GL_RGB5_A1\n    int GL_RGB565\n    int GL_DEPTH_COMPONENT16\n    int GL_STENCIL_INDEX8\n\n    int GL_RENDERBUFFER_WIDTH\n    int GL_RENDERBUFFER_HEIGHT\n    int GL_RENDERBUFFER_INTERNAL_FORMAT\n    int GL_RENDERBUFFER_RED_SIZE\n    int GL_RENDERBUFFER_GREEN_SIZE\n    int GL_RENDERBUFFER_BLUE_SIZE\n    int GL_RENDERBUFFER_ALPHA_SIZE\n    int GL_RENDERBUFFER_DEPTH_SIZE\n    int GL_RENDERBUFFER_STENCIL_SIZE\n\n    int GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE\n    int GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME\n    int GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL\n    int GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE\n\n    int GL_COLOR_ATTACHMENT0\n    int GL_DEPTH_ATTACHMENT\n    int GL_STENCIL_ATTACHMENT\n\n    int GL_NONE\n\n    int GL_FRAMEBUFFER_COMPLETE\n    int GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT\n    int GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT\n    int GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS\n    int GL_FRAMEBUFFER_UNSUPPORTED\n\n    int GL_FRAMEBUFFER_BINDING\n    int GL_RENDERBUFFER_BINDING\n    int GL_MAX_RENDERBUFFER_SIZE\n\n    int GL_INVALID_FRAMEBUFFER_OPERATION\n\n    IF USE_OPENGL_ES2:\n        int GL_FIXED\n        int GL_MAX_VERTEX_UNIFORM_VECTORS\n        int GL_MAX_VARYING_VECTORS\n        int GL_MAX_FRAGMENT_UNIFORM_VECTORS\n        int GL_IMPLEMENTATION_COLOR_READ_TYPE\n        int GL_IMPLEMENTATION_COLOR_READ_FORMAT\n        int GL_SHADER_COMPILER\n        int GL_NUM_SHADER_BINARY_FORMATS\n        int GL_LOW_FLOAT\n        int GL_MEDIUM_FLOAT\n        int GL_HIGH_FLOAT\n        int GL_LOW_INT\n        int GL_MEDIUM_INT\n        int GL_HIGH_INT\n\n    cdef void   glActiveTexture(GLenum texture) nogil\n    cdef void   glAttachShader(GLuint program, GLuint shader) nogil\n    cdef void   glBindAttribLocation(GLuint program, GLuint index,  GLchar* name) nogil\n    cdef void   glBindBuffer(GLenum target, GLuint buffer) nogil\n    cdef void   glBindFramebuffer(GLenum target, GLuint framebuffer) nogil\n    cdef void   glBindRenderbuffer(GLenum target, GLuint renderbuffer) nogil\n    cdef void   glBindTexture(GLenum target, GLuint texture) nogil\n    cdef void   glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) nogil\n    cdef void   glBlendEquation( GLenum mode ) nogil\n    cdef void   glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) nogil\n    cdef void   glBlendFunc(GLenum sfactor, GLenum dfactor) nogil\n    cdef void   glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) nogil\n    cdef void   glBufferData(GLenum target, GLsizeiptr size,  GLvoid* data, GLenum usage) nogil\n    cdef void   glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size,  GLvoid* data) nogil\n    cdef GLenum glCheckFramebufferStatus(GLenum target) nogil\n    cdef void   glClear(GLbitfield mask) nogil\n    cdef void   glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) nogil\n    cdef void   glClearDepthf(GLclampf depth) nogil\n    cdef void   glClearStencil(GLint s) nogil\n    cdef void   glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) nogil\n    cdef void   glCompileShader(GLuint shader) nogil\n    cdef void   glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize,  GLvoid* data) nogil\n    cdef void   glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize,  GLvoid* data) nogil\n    cdef void   glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) nogil\n    cdef void   glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) nogil\n    cdef GLuint glCreateProgram() nogil\n    cdef GLuint glCreateShader(GLenum type) nogil\n    cdef void   glCullFace(GLenum mode) nogil\n    cdef void   glDeleteBuffers(GLsizei n,  GLuint* buffers) nogil\n    cdef void   glDeleteFramebuffers(GLsizei n,  GLuint* framebuffers) nogil\n    cdef void   glDeleteProgram(GLuint program) nogil\n    cdef void   glDeleteRenderbuffers(GLsizei n,  GLuint* renderbuffers) nogil\n    cdef void   glDeleteShader(GLuint shader) nogil\n    cdef void   glDeleteTextures(GLsizei n,  GLuint* textures) nogil\n    cdef void   glDepthFunc(GLenum func) nogil\n    cdef void   glDepthMask(GLboolean flag) nogil\n    cdef void   glDepthRangef(GLclampf zNear, GLclampf zFar) nogil\n    cdef void   glDetachShader(GLuint program, GLuint shader) nogil\n    cdef void   glDisable(GLenum cap) nogil\n    cdef void   glDisableVertexAttribArray(GLuint index) nogil\n    cdef void   glDrawArrays(GLenum mode, GLint first, GLsizei count) nogil\n    cdef void   glDrawElements(GLenum mode, GLsizei count, GLenum type,  GLvoid* indices) nogil\n    cdef void   glEnable(GLenum cap) nogil\n    cdef void   glEnableVertexAttribArray(GLuint index) nogil\n    cdef void   glFinish() nogil\n    cdef void   glFlush() nogil\n    cdef void   glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) nogil\n    cdef void   glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) nogil\n    cdef void   glFrontFace(GLenum mode) nogil\n    cdef void   glGenBuffers(GLsizei n, GLuint* buffers) nogil\n    cdef void   glGenerateMipmap(GLenum target) nogil\n    cdef void   glGenFramebuffers(GLsizei n, GLuint* framebuffers) nogil\n    cdef void   glGenRenderbuffers(GLsizei n, GLuint* renderbuffers) nogil\n    cdef void   glGenTextures(GLsizei n, GLuint* textures) nogil\n    cdef void   glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) nogil\n    cdef void   glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) nogil\n    cdef void   glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) nogil\n    cdef int    glGetAttribLocation(GLuint program,  GLchar* name) nogil\n    cdef void   glGetBooleanv(GLenum pname, GLboolean* params) nogil\n    cdef void   glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params) nogil\n    cdef GLenum glGetError() nogil\n    cdef void   glGetFloatv(GLenum pname, GLfloat* params) nogil\n    cdef void   glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params) nogil\n    cdef void   glGetIntegerv(GLenum pname, GLint* params) nogil\n    cdef void   glGetProgramiv(GLuint program, GLenum pname, GLint* params) nogil\n    cdef void   glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog) nogil\n    cdef void   glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) nogil\n    cdef void   glGetShaderiv(GLuint shader, GLenum pname, GLint* params) nogil\n    cdef void   glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog) nogil\n    #cdef void   glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) nogil\n    cdef void   glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) nogil\n    cdef   GLubyte*  glGetString(GLenum name) nogil\n    cdef void   glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) nogil\n    cdef void   glGetTexParameteriv(GLenum target, GLenum pname, GLint* params) nogil\n    cdef void   glGetUniformfv(GLuint program, GLint location, GLfloat* params) nogil\n    cdef void   glGetUniformiv(GLuint program, GLint location, GLint* params) nogil\n    cdef int    glGetUniformLocation(GLuint program,  GLchar* name) nogil\n    cdef void   glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) nogil\n    cdef void   glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params) nogil\n    cdef void   glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer) nogil\n    cdef void   glHint(GLenum target, GLenum mode) nogil\n    cdef GLboolean  glIsBuffer(GLuint buffer) nogil\n    cdef GLboolean  glIsEnabled(GLenum cap) nogil\n    cdef GLboolean  glIsFramebuffer(GLuint framebuffer) nogil\n    cdef GLboolean  glIsProgram(GLuint program) nogil\n    cdef GLboolean  glIsRenderbuffer(GLuint renderbuffer) nogil\n    cdef GLboolean  glIsShader(GLuint shader) nogil\n    cdef GLboolean  glIsTexture(GLuint texture) nogil\n    cdef void  glLineWidth(GLfloat width) nogil\n    cdef void  glLinkProgram(GLuint program) nogil\n    cdef void  glPixelStorei(GLenum pname, GLint param) nogil\n    cdef void  glPolygonOffset(GLfloat factor, GLfloat units) nogil\n    cdef void  glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) nogil\n    # XXX This one is commented out because a) it's not necessary and\n    #\t    \t\t\t\tb) it's breaking on OSX for some reason\n    #cdef void  glReleaseShaderCompiler() nogil\n    cdef void  glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) nogil\n    cdef void  glSampleCoverage(GLclampf value, GLboolean invert) nogil\n    cdef void  glScissor(GLint x, GLint y, GLsizei width, GLsizei height) nogil\n    #cdef void  glShaderBinary(GLsizei n,  GLuint* shaders, GLenum binaryformat,  GLvoid* binary, GLsizei length) nogil\n    cdef void  glShaderSource(GLuint shader, GLsizei count,  GLchar** string,  GLint* length) nogil\n    cdef void  glStencilFunc(GLenum func, GLint ref, GLuint mask) nogil\n    cdef void  glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) nogil\n    cdef void  glStencilMask(GLuint mask) nogil\n    cdef void  glStencilMaskSeparate(GLenum face, GLuint mask) nogil\n    cdef void  glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) nogil\n    cdef void  glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) nogil\n    cdef void  glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type,  GLvoid* pixels) nogil\n    cdef void  glTexParameterf(GLenum target, GLenum pname, GLfloat param) nogil\n    cdef void  glTexParameterfv(GLenum target, GLenum pname,  GLfloat* params) nogil\n    cdef void  glTexParameteri(GLenum target, GLenum pname, GLint param) nogil\n    cdef void  glTexParameteriv(GLenum target, GLenum pname,  GLint* params) nogil\n    cdef void  glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,  GLvoid* pixels) nogil\n    cdef void  glUniform1f(GLint location, GLfloat x) nogil\n    cdef void  glUniform1fv(GLint location, GLsizei count,  GLfloat* v) nogil\n    cdef void  glUniform1i(GLint location, GLint x) nogil\n    cdef void  glUniform1iv(GLint location, GLsizei count,  GLint* v) nogil\n    cdef void  glUniform2f(GLint location, GLfloat x, GLfloat y) nogil\n    cdef void  glUniform2fv(GLint location, GLsizei count,  GLfloat* v) nogil\n    cdef void  glUniform2i(GLint location, GLint x, GLint y) nogil\n    cdef void  glUniform2iv(GLint location, GLsizei count,  GLint* v) nogil\n    cdef void  glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) nogil\n    cdef void  glUniform3fv(GLint location, GLsizei count,  GLfloat* v) nogil\n    cdef void  glUniform3i(GLint location, GLint x, GLint y, GLint z) nogil\n    cdef void  glUniform3iv(GLint location, GLsizei count,  GLint* v) nogil\n    cdef void  glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) nogil\n    cdef void  glUniform4fv(GLint location, GLsizei count,  GLfloat* v) nogil\n    cdef void  glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) nogil\n    cdef void  glUniform4iv(GLint location, GLsizei count,  GLint* v) nogil\n    cdef void  glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose,  GLfloat* value) nogil\n    cdef void  glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose,  GLfloat* value) nogil\n    cdef void  glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose,  GLfloat* value) nogil\n    cdef void  glUseProgram(GLuint program) nogil\n    cdef void  glValidateProgram(GLuint program) nogil\n    cdef void  glVertexAttrib1f(GLuint indx, GLfloat x) nogil\n    cdef void  glVertexAttrib1fv(GLuint indx,  GLfloat* values) nogil\n    cdef void  glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) nogil\n    cdef void  glVertexAttrib2fv(GLuint indx,  GLfloat* values) nogil\n    cdef void  glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z) nogil\n    cdef void  glVertexAttrib3fv(GLuint indx,  GLfloat* values) nogil\n    cdef void  glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) nogil\n    cdef void  glVertexAttrib4fv(GLuint indx,  GLfloat* values) nogil\n    cdef void  glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride,  GLvoid* ptr) nogil\n    cdef void  glViewport(GLint x, GLint y, GLsizei width, GLsizei height) nogil\n"
  },
  {
    "path": "tickeys/kivy/graphics/c_opengl_debug.pxd",
    "content": "ctypedef void               GLvoid\nctypedef char               GLchar\nctypedef unsigned int       GLenum\nctypedef unsigned char      GLboolean\nctypedef unsigned int       GLbitfield\nctypedef short              GLshort\nctypedef int                GLint\nctypedef int                GLsizei\nctypedef unsigned short     GLushort\nctypedef unsigned int       GLuint\nctypedef signed char        GLbyte\nctypedef unsigned char      GLubyte\nctypedef float              GLfloat\nctypedef float              GLclampf\nctypedef int                GLfixed\nctypedef signed long int    GLintptr\nctypedef signed long int    GLsizeiptr\n\ncdef void   glActiveTexture (GLenum texture) with gil\ncdef void   glAttachShader (GLuint program, GLuint shader) with gil\ncdef void   glBindAttribLocation (GLuint program, GLuint index,  GLchar* name) with gil\ncdef void   glBindBuffer (GLenum target, GLuint buffer) with gil\ncdef void   glBindFramebuffer (GLenum target, GLuint framebuffer) with gil\ncdef void   glBindRenderbuffer (GLenum target, GLuint renderbuffer) with gil\ncdef void   glBindTexture (GLenum target, GLuint texture) with gil\ncdef void   glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) with gil\ncdef void   glBlendEquation ( GLenum mode ) with gil\ncdef void   glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha) with gil\ncdef void   glBlendFunc (GLenum sfactor, GLenum dfactor) with gil\ncdef void   glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) with gil\ncdef void   glBufferData (GLenum target, GLsizeiptr size,  GLvoid* data, GLenum usage) with gil\ncdef void   glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size,  GLvoid* data) with gil\ncdef GLenum glCheckFramebufferStatus (GLenum target) with gil\ncdef void   glClear (GLbitfield mask) with gil\ncdef void   glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) with gil\n# crash on android platform\n#cdef void   glClearDepthf (GLclampf depth) with gil\ncdef void   glClearStencil (GLint s) with gil\ncdef void   glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) with gil\ncdef void   glCompileShader (GLuint shader) with gil\ncdef void   glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize,  GLvoid* data) with gil\ncdef void   glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize,  GLvoid* data) with gil\ncdef void   glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) with gil\ncdef void   glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) with gil\ncdef GLuint glCreateProgram () with gil\ncdef GLuint glCreateShader (GLenum type) with gil\ncdef void   glCullFace (GLenum mode) with gil\ncdef void   glDeleteBuffers (GLsizei n,  GLuint* buffers) with gil\ncdef void   glDeleteFramebuffers (GLsizei n,  GLuint* framebuffers) with gil\ncdef void   glDeleteProgram (GLuint program) with gil\ncdef void   glDeleteRenderbuffers (GLsizei n,  GLuint* renderbuffers) with gil\ncdef void   glDeleteShader (GLuint shader) with gil\ncdef void   glDeleteTextures (GLsizei n,  GLuint* textures) with gil\ncdef void   glDepthFunc (GLenum func) with gil\ncdef void   glDepthMask (GLboolean flag) with gil\n# crash on android platform\n#cdef void   glDepthRangef (GLclampf zNear, GLclampf zFar) with gil\ncdef void   glDetachShader (GLuint program, GLuint shader) with gil\ncdef void   glDisable (GLenum cap) with gil\ncdef void   glDisableVertexAttribArray (GLuint index) with gil\ncdef void   glDrawArrays (GLenum mode, GLint first, GLsizei count) with gil\ncdef void   glDrawElements (GLenum mode, GLsizei count, GLenum type,  GLvoid* indices) with gil\ncdef void   glEnable (GLenum cap) with gil\ncdef void   glEnableVertexAttribArray (GLuint index) with gil\ncdef void   glFinish () with gil\ncdef void   glFlush () with gil\ncdef void   glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) with gil\ncdef void   glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) with gil\ncdef void   glFrontFace (GLenum mode) with gil\ncdef void   glGenBuffers (GLsizei n, GLuint* buffers) with gil\ncdef void   glGenerateMipmap (GLenum target) with gil\ncdef void   glGenFramebuffers (GLsizei n, GLuint* framebuffers) with gil\ncdef void   glGenRenderbuffers (GLsizei n, GLuint* renderbuffers) with gil\ncdef void   glGenTextures (GLsizei n, GLuint* textures) with gil\ncdef void   glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) with gil\ncdef void   glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) with gil\ncdef void   glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) with gil\ncdef int    glGetAttribLocation (GLuint program,  GLchar* name) with gil\ncdef void   glGetBooleanv (GLenum pname, GLboolean* params) with gil\ncdef void   glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params) with gil\ncdef GLenum glGetError () with gil\ncdef void   glGetFloatv (GLenum pname, GLfloat* params) with gil\ncdef void   glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params) with gil\ncdef void   glGetIntegerv (GLenum pname, GLint* params) with gil\ncdef void   glGetProgramiv (GLuint program, GLenum pname, GLint* params) with gil\ncdef void   glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog) with gil\ncdef void   glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params) with gil\ncdef void   glGetShaderiv (GLuint shader, GLenum pname, GLint* params) with gil\ncdef void   glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog) with gil\n#cdef void   glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) with gil\ncdef void   glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) with gil\ncdef   GLubyte*  glGetString (GLenum name) with gil\ncdef void   glGetTexParameterfv (GLenum target, GLenum pname, GLfloat* params) with gil\ncdef void   glGetTexParameteriv (GLenum target, GLenum pname, GLint* params) with gil\ncdef void   glGetUniformfv (GLuint program, GLint location, GLfloat* params) with gil\ncdef void   glGetUniformiv (GLuint program, GLint location, GLint* params) with gil\ncdef int    glGetUniformLocation (GLuint program,  GLchar* name) with gil\ncdef void   glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params) with gil\ncdef void   glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params) with gil\ncdef void   glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid** pointer) with gil\ncdef void   glHint (GLenum target, GLenum mode) with gil\ncdef GLboolean  glIsBuffer (GLuint buffer) with gil\ncdef GLboolean  glIsEnabled (GLenum cap) with gil\ncdef GLboolean  glIsFramebuffer (GLuint framebuffer) with gil\ncdef GLboolean  glIsProgram (GLuint program) with gil\ncdef GLboolean  glIsRenderbuffer (GLuint renderbuffer) with gil\ncdef GLboolean  glIsShader (GLuint shader) with gil\ncdef GLboolean  glIsTexture (GLuint texture) with gil\ncdef void  glLineWidth (GLfloat width) with gil\ncdef void  glLinkProgram (GLuint program) with gil\ncdef void  glPixelStorei (GLenum pname, GLint param) with gil\ncdef void  glPolygonOffset (GLfloat factor, GLfloat units) with gil\ncdef void  glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) with gil\n# XXX This one is commented out because a) it's not necessary and\n#\t    \t\t\t\tb) it's breaking on OSX for some reason\n#cdef void  glReleaseShaderCompiler () with gil\ncdef void  glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height) with gil\ncdef void  glSampleCoverage (GLclampf value, GLboolean invert) with gil\ncdef void  glScissor (GLint x, GLint y, GLsizei width, GLsizei height) with gil\n#cdef void  glShaderBinary (GLsizei n,  GLuint* shaders, GLenum binaryformat,  GLvoid* binary, GLsizei length) with gil\ncdef void  glShaderSource (GLuint shader, GLsizei count,  GLchar** string,  GLint* length) with gil\ncdef void  glStencilFunc (GLenum func, GLint ref, GLuint mask) with gil\ncdef void  glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask) with gil\ncdef void  glStencilMask (GLuint mask) with gil\ncdef void  glStencilMaskSeparate (GLenum face, GLuint mask) with gil\ncdef void  glStencilOp (GLenum fail, GLenum zfail, GLenum zpass) with gil\ncdef void  glStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass) with gil\ncdef void  glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type,  GLvoid* pixels) with gil\ncdef void  glTexParameterf (GLenum target, GLenum pname, GLfloat param) with gil\ncdef void  glTexParameterfv (GLenum target, GLenum pname,  GLfloat* params) with gil\ncdef void  glTexParameteri (GLenum target, GLenum pname, GLint param) with gil\ncdef void  glTexParameteriv (GLenum target, GLenum pname,  GLint* params) with gil\ncdef void  glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,  GLvoid* pixels) with gil\ncdef void  glUniform1f (GLint location, GLfloat x) with gil\ncdef void  glUniform1fv (GLint location, GLsizei count,  GLfloat* v) with gil\ncdef void  glUniform1i (GLint location, GLint x) with gil\ncdef void  glUniform1iv (GLint location, GLsizei count,  GLint* v) with gil\ncdef void  glUniform2f (GLint location, GLfloat x, GLfloat y) with gil\ncdef void  glUniform2fv (GLint location, GLsizei count,  GLfloat* v) with gil\ncdef void  glUniform2i (GLint location, GLint x, GLint y) with gil\ncdef void  glUniform2iv (GLint location, GLsizei count,  GLint* v) with gil\ncdef void  glUniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z) with gil\ncdef void  glUniform3fv (GLint location, GLsizei count,  GLfloat* v) with gil\ncdef void  glUniform3i (GLint location, GLint x, GLint y, GLint z) with gil\ncdef void  glUniform3iv (GLint location, GLsizei count,  GLint* v) with gil\ncdef void  glUniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) with gil\ncdef void  glUniform4fv (GLint location, GLsizei count,  GLfloat* v) with gil\ncdef void  glUniform4i (GLint location, GLint x, GLint y, GLint z, GLint w) with gil\ncdef void  glUniform4iv (GLint location, GLsizei count,  GLint* v) with gil\ncdef void  glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose,  GLfloat* value) with gil\ncdef void  glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose,  GLfloat* value) with gil\ncdef void  glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose,  GLfloat* value) with gil\ncdef void  glUseProgram (GLuint program) with gil\ncdef void  glValidateProgram (GLuint program) with gil\ncdef void  glVertexAttrib1f (GLuint indx, GLfloat x) with gil\ncdef void  glVertexAttrib1fv (GLuint indx,  GLfloat* values) with gil\ncdef void  glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y) with gil\ncdef void  glVertexAttrib2fv (GLuint indx,  GLfloat* values) with gil\ncdef void  glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z) with gil\ncdef void  glVertexAttrib3fv (GLuint indx,  GLfloat* values) with gil\ncdef void  glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) with gil\ncdef void  glVertexAttrib4fv (GLuint indx,  GLfloat* values) with gil\ncdef void  glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride,  GLvoid* ptr) with gil\ncdef void  glViewport (GLint x, GLint y, GLsizei width, GLsizei height) with gil\n"
  },
  {
    "path": "tickeys/kivy/graphics/common.pxi",
    "content": "#\n# Common definition\n#\n\nDEF PI2 = 1.5707963267948966\nDEF PI = 3.1415926535897931\n\ncdef extern from *:\n    ctypedef char* const_char_ptr \"const char*\"\n\ncdef double pi = PI\ncdef extern from \"math.h\":\n    double cos(double) nogil\n    double acos(double) nogil\n    double sin(double) nogil\n    double sqrt(double) nogil\n    double pow(double x, double y) nogil\n    double atan2(double y, double x) nogil\n    double tan(double) nogil\n    double fabs(double) nogil\n\ncdef extern from \"stdlib.h\":\n    ctypedef unsigned long size_t\n    void free(void *ptr) nogil\n    void *realloc(void *ptr, size_t size) nogil\n    void *malloc(size_t size) nogil\n    void *calloc(size_t nmemb, size_t size) nogil\n\ncdef extern from \"string.h\":\n    void *memcpy(void *dest, void *src, size_t n) nogil\n    void *memset(void *dest, int c, size_t len)\n"
  },
  {
    "path": "tickeys/kivy/graphics/compiler.pxd",
    "content": "cdef class GraphicsCompiler\n\nfrom instructions cimport InstructionGroup\n\ncdef class GraphicsCompiler:\n    cdef InstructionGroup compile(self, InstructionGroup group)\n"
  },
  {
    "path": "tickeys/kivy/graphics/config.h",
    "content": "// Autogenerated file for Kivy C configuration\n#define __PY3 0\n#define __USE_RPI 0\n#define __USE_OPENGL_ES2 1\n#define __USE_OPENGL_DEBUG 0\n#define __USE_GLEW 0\n#define __USE_SDL2 1\n#define __USE_IOS 0\n#define __USE_MESAGL 0\n#define __USE_X11 0\n#define __USE_GSTREAMER 1\n#define __USE_AVFOUNDATION 0\n#define __USE_OSX_FRAMEWORKS 0\n#if __USE_GLEW && defined(_WIN32)\n#   define GLEW_BUILD\n#endif"
  },
  {
    "path": "tickeys/kivy/graphics/config.pxi",
    "content": "# Autogenerated file for Kivy Cython configuration\nDEF PY3 = 0\nDEF USE_RPI = 0\nDEF USE_OPENGL_ES2 = 1\nDEF USE_OPENGL_DEBUG = 0\nDEF USE_GLEW = 0\nDEF USE_SDL2 = 1\nDEF USE_IOS = 0\nDEF USE_MESAGL = 0\nDEF USE_X11 = 0\nDEF USE_GSTREAMER = 1\nDEF USE_AVFOUNDATION = 0\nDEF USE_OSX_FRAMEWORKS = 0\nDEF DEBUG = False\n"
  },
  {
    "path": "tickeys/kivy/graphics/context.pxd",
    "content": "from kivy.graphics.instructions cimport Instruction, Canvas\nfrom kivy.graphics.texture cimport Texture\nfrom kivy.graphics.vbo cimport VBO, VertexBatch\nfrom kivy.graphics.shader cimport Shader\nfrom kivy.graphics.fbo cimport Fbo\n\ncdef class Context:\n    cdef list observers\n    cdef list observers_before\n    cdef list l_texture\n    cdef list l_canvas\n    cdef list l_fbo\n\n    cdef object lr_texture\n    cdef list lr_canvas\n    cdef object lr_vbo\n    cdef object lr_fbo_rb\n    cdef object lr_fbo_fb\n    cdef object lr_shadersource\n    cdef list lr_shader\n\n    cdef void register_texture(self, Texture texture)\n    cdef void register_canvas(self, Canvas canvas)\n    cdef void register_fbo(self, Fbo fbo)\n\n    cdef void dealloc_texture(self, Texture texture)\n    cdef void dealloc_vbo(self, VBO vbo)\n    cdef void dealloc_vertexbatch(self, VertexBatch vbo)\n    cdef void dealloc_shader(self, Shader shader)\n    cdef void dealloc_shader_source(self, int shader)\n    cdef void dealloc_fbo(self, Fbo fbo)\n\n    cdef object trigger_gl_dealloc\n    cdef void flush(self)\n\ncpdef Context get_context()\n"
  },
  {
    "path": "tickeys/kivy/graphics/context_instructions.pxd",
    "content": "cdef class LineWidth\ncdef class Color\ncdef class BindTexture\n\nfrom transformation cimport Matrix\nfrom instructions cimport ContextInstruction\nfrom texture cimport Texture\n\ncdef class PushState(ContextInstruction):\n    pass\n\ncdef class ChangeState(ContextInstruction):\n    pass\n\ncdef class PopState(ContextInstruction):\n    pass\n\ncdef class LineWidth(ContextInstruction):\n    cdef int apply(self) except -1\n\ncdef class Color(ContextInstruction):\n    cdef int apply(self) except -1\n\ncdef class BindTexture(ContextInstruction):\n    cdef int _index\n    cdef object _source\n    cdef Texture _texture\n    cdef int apply(self) except -1\n\n\ncdef class LoadIdentity(ContextInstruction):\n    pass\n\ncdef class PushMatrix(ContextInstruction):\n    cdef int apply(self) except -1\n\ncdef class PopMatrix(ContextInstruction):\n    cdef int apply(self) except -1\n\ncdef class ApplyContextMatrix(ContextInstruction):\n    cdef object _target_stack\n    cdef object _source_stack\n    cdef int apply(self) except -1\n\ncdef class UpdateNormalMatrix(ContextInstruction):\n    cdef int apply(self) except -1\n\ncdef class MatrixInstruction(ContextInstruction):\n    cdef object _stack\n    cdef Matrix _matrix\n    cdef int apply(self) except -1\n\ncdef class Transform(MatrixInstruction):\n    cpdef transform(self, Matrix trans)\n    cpdef translate(self, float tx, float ty, float tz)\n    cpdef rotate(self, float angle, float ax, float ay, float az)\n    cpdef scale(self, float s)\n    cpdef identity(self)\n\ncdef class Rotate(Transform):\n    cdef float _angle\n    cdef tuple _axis\n    cdef tuple _origin\n    cdef int apply(self) except -1\n    cdef void compute(self)\n\ncdef class Scale(Transform):\n    cdef tuple _origin\n    cdef float _x, _y, _z\n    cdef int apply(self) except -1\n    cdef set_scale(self, double x, double y, double z)\n\ncdef class Translate(Transform):\n    cdef double _x, _y, _z\n    cdef int apply(self) except -1\n    cdef set_translate(self, double x, double y, double z)\n\n"
  },
  {
    "path": "tickeys/kivy/graphics/fbo.pxd",
    "content": "from c_opengl cimport *\nfrom instructions cimport RenderContext, Canvas\nfrom texture cimport Texture\n\ncdef class Fbo(RenderContext):\n    cdef int _width\n    cdef int _height\n    cdef int _depthbuffer_attached\n    cdef int _stencilbuffer_attached\n    cdef int _push_viewport\n    cdef float _clear_color[4]\n    cdef GLuint buffer_id\n    cdef GLuint depthbuffer_id\n    cdef GLuint stencilbuffer_id\n    cdef GLint _viewport[4]\n    cdef Texture _texture\n    cdef int _is_bound\n    cdef list observers\n\n    cpdef clear_buffer(self)\n    cpdef bind(self)\n    cpdef release(self)\n    cpdef get_pixel_color(self, int wx, int wy)\n\n    cdef void create_fbo(self)\n    cdef void delete_fbo(self)\n    cdef int apply(self) except -1\n    cdef void raise_exception(self, str message, int status=?)\n    cdef str resolve_status(self, int status)\n    cdef void reload(self)\n"
  },
  {
    "path": "tickeys/kivy/graphics/img_tools.pxi",
    "content": "from kivy.graphics.opengl_utils cimport (gl_has_texture_native_format,\n    gl_has_texture_conversion)\ncimport cython\nfrom cython cimport view as cyview\nfrom cpython.array cimport array, clone\n\n\n@cython.boundscheck(False)\n@cython.wraparound(False)\ncdef inline convert_to_gl_format(data, fmt):\n    ''' Takes data as a bytes object or an instance that implements the python\n    buffer interface. If the data format is supported by opengl, the data\n    is returned unchanged. Otherwise, the data is converted to a supported\n    format, when possible, and returned as a python array object.\n\n    Note that conversion is currently only supported for bytes data.\n    '''\n    cdef array ret_array\n    cdef char *src_buffer\n    cdef char *dst_buffer\n    cdef char [::1] view\n    cdef int datasize\n    cdef str ret_format\n    cdef int i\n    cdef char c\n\n    # if native support of this format is available, use it\n    if gl_has_texture_native_format(fmt):\n        return data, fmt\n\n    # no native support, can we at least convert it ?\n    if not gl_has_texture_conversion(fmt):\n        raise Exception('Unimplemented texture conversion for {}'.format(fmt))\n\n    # do appropriate conversion, since we accepted it\n    if isinstance(data, bytes):\n        datasize = len(data)\n        ret_array = clone(array('b'), datasize, False)\n        src_buffer = <char *>data\n    else:\n        view = data\n        datasize = view.nbytes\n        ret_array = clone(array('b'), datasize, False)\n        src_buffer = &view[0]\n    dst_buffer = ret_array.data.as_chars\n\n    # BGR -> RGB\n    if fmt == 'bgr':\n        ret_format = 'rgb'\n        memcpy(dst_buffer, src_buffer, datasize)\n        # note, this is the fastest copying method. copying element by element\n        # from a memoryview is slower then copying the whole buffer and then\n        # properly modifying the elements\n        with nogil:\n            for i in range(0, datasize, 3):\n                c = dst_buffer[i]\n                dst_buffer[i] = dst_buffer[i + 2]\n                dst_buffer[i + 2] = c\n\n    # BGRA -> RGBA\n    elif fmt == 'bgra':\n        ret_format = 'rgba'\n        memcpy(dst_buffer, src_buffer, datasize)\n        with nogil:\n            for i in range(0, datasize, 4):\n                c = dst_buffer[i]\n                dst_buffer[i] = dst_buffer[i + 2]\n                dst_buffer[i + 2] = c\n\n    else:\n        assert False, 'Non implemented texture conversion {}'.format(fmt)\n\n    return ret_array, ret_format\n"
  },
  {
    "path": "tickeys/kivy/graphics/instructions.pxd",
    "content": "include \"config.pxi\"\n\ncdef class Instruction\ncdef class InstructionGroup\ncdef class ContextInstruction\ncdef class VertexInstruction\ncdef class CanvasBase\ncdef class Canvas\ncdef class RenderContext\n\nfrom vbo cimport *\nfrom compiler cimport *\nfrom shader cimport *\nfrom texture cimport Texture\nfrom kivy._event cimport ObjectWithUid\n\ncdef void reset_gl_context()\n\ncdef class Instruction\ncdef class InstructionGroup(Instruction)\n\ncdef class Instruction(ObjectWithUid):\n    cdef int flags\n    cdef str group\n    cdef InstructionGroup parent\n    cdef object __weakref__\n    cdef object __proxy_ref\n\n    cdef int apply(self) except -1\n    IF DEBUG:\n        cdef int flag_update(self, int do_parent=?, list _instrs=?) except -1\n    ELSE:\n        cdef void flag_update(self, int do_parent=?)\n    cdef void flag_update_done(self)\n    cdef void set_parent(self, Instruction parent)\n    cdef void reload(self)\n\n    cdef void radd(self, InstructionGroup ig)\n    cdef void rinsert(self, InstructionGroup ig, int index)\n    cdef void rremove(self, InstructionGroup ig)\n\ncdef class InstructionGroup(Instruction):\n    cdef public list children\n    cdef InstructionGroup compiled_children\n    cdef GraphicsCompiler compiler\n    cdef void build(self)\n    cdef void reload(self)\n    cpdef add(self, Instruction c)\n    cpdef insert(self, int index, Instruction c)\n    cpdef remove(self, Instruction c)\n    cpdef clear(self)\n    cpdef remove_group(self, str groupname)\n    cpdef get_group(self, str groupname)\n\ncdef class ContextInstruction(Instruction):\n    cdef dict context_state\n    cdef list context_push\n    cdef list context_pop\n\n    cdef RenderContext get_context(self)\n    cdef int set_state(self, str name, value) except -1\n    cdef int push_state(self, str name) except -1\n    cdef int pop_state(self, str name) except -1\n\n\nfrom context_instructions cimport BindTexture\n\ncdef class VertexInstruction(Instruction):\n    cdef BindTexture texture_binding\n    cdef VertexBatch batch\n    cdef float _tex_coords[8]\n\n    cdef void radd(self, InstructionGroup ig)\n    cdef void rinsert(self, InstructionGroup ig, int index)\n    cdef void rremove(self, InstructionGroup ig)\n\n    cdef void build(self)\n\ncdef class Callback(Instruction):\n    cdef Shader _shader\n    cdef object func\n    cdef int _reset_context\n    cdef int apply(self) except -1\n    cdef int enter(self) except -1\n\n\n\ncdef CanvasBase getActiveCanvas()\n\ncdef class CanvasBase(InstructionGroup):\n    pass\n\ncdef class Canvas(CanvasBase):\n    cdef float _opacity\n    cdef CanvasBase _before\n    cdef CanvasBase _after\n    cdef void reload(self)\n    cpdef clear(self)\n    cpdef add(self, Instruction c)\n    cpdef remove(self, Instruction c)\n    cpdef draw(self)\n    cdef int apply(self) except -1\n\n\ncdef class RenderContext(Canvas):\n    cdef Shader _shader\n    cdef dict state_stacks\n    cdef Texture default_texture\n    cdef dict bind_texture\n    cdef int _use_parent_projection\n    cdef int _use_parent_modelview\n\n    cdef void set_texture(self, int index, Texture texture)\n    cdef void set_state(self, str name, value, int apply_now=?)\n    cdef get_state(self, str name)\n    cdef int set_states(self, dict states) except -1\n    cdef int push_state(self, str name) except -1\n    cdef int push_states(self, list names) except -1\n    cdef int pop_state(self, str name) except -1\n    cdef int pop_states(self, list names) except -1\n    cdef int enter(self) except -1\n    cdef int leave(self) except -1\n    cdef int apply(self) except -1\n    cpdef draw(self)\n    cdef void reload(self)\n\ncdef RenderContext getActiveContext()\n"
  },
  {
    "path": "tickeys/kivy/graphics/opcodes.pxi",
    "content": "cdef int GI_NOOP         = 1 << 0\ncdef int GI_IGNORE       = 1 << 1\ncdef int GI_NEEDS_UPDATE = 1 << 2\ncdef int GI_GROUP        = 1 << 3\ncdef int GI_CONTEXT_MOD  = 1 << 4\ncdef int GI_VERTEX_DATA  = 1 << 5\ncdef int GI_COMPILER\t = 1 << 6\ncdef int GI_NO_APPLY_ONCE = 1 << 7\ncdef int GI_NO_REMOVE    = 1 << 8\n\n"
  },
  {
    "path": "tickeys/kivy/graphics/opengl_utils.pxd",
    "content": "cpdef list gl_get_extensions()\ncpdef int gl_has_extension(name)\ncpdef gl_register_get_size(int constid, int size)\ncpdef int gl_has_capability(int cap)\ncpdef tuple gl_get_texture_formats()\ncpdef int gl_has_texture_native_format(fmt)\ncpdef int gl_has_texture_conversion(fmt)\ncpdef int gl_has_texture_format(fmt)\ncpdef tuple gl_get_version()\ncpdef int gl_get_version_major()\ncpdef int gl_get_version_minor()\n"
  },
  {
    "path": "tickeys/kivy/graphics/opengl_utils_def.pxi",
    "content": "# c definition\ncdef int c_GLCAP_BGRA = 0x0001\ncdef int c_GLCAP_NPOT = 0x0002\ncdef int c_GLCAP_S3TC = 0x0003\ncdef int c_GLCAP_DXT1 = 0x0004\ncdef int c_GLCAP_PVRTC = 0x0005\ncdef int c_GLCAP_ETC1 = 0x0006\ncdef int c_GLCAP_UNPACK_SUBIMAGE = 0x0007\n\n# for python export\nGLCAP_BGRA = c_GLCAP_NPOT\nGLCAP_NPOT = c_GLCAP_NPOT\nGLCAP_S3TC = c_GLCAP_S3TC\nGLCAP_DXT1 = c_GLCAP_DXT1\nGLCAP_PVRTC = c_GLCAP_PVRTC\nGLCAP_ETC1 = c_GLCAP_ETC1\nGLCAP_UNPACK_SUBIMAGE = c_GLCAP_UNPACK_SUBIMAGE\n"
  },
  {
    "path": "tickeys/kivy/graphics/shader.pxd",
    "content": "from c_opengl cimport GLuint\nfrom transformation cimport Matrix\nfrom vertex cimport VertexFormat\n\ncdef class ShaderSource:\n    cdef int shader\n    cdef int shadertype\n    cdef set_source(self, char *source)\n    cdef get_shader_log(self, int shader)\n    cdef void process_message(self, str ctype, message)\n    cdef int is_compiled(self)\n\ncdef class Shader:\n    cdef object __weakref__\n\n    cdef int _success\n    cdef VertexFormat _current_vertex_format\n    cdef unsigned int program\n    cdef ShaderSource vertex_shader\n    cdef ShaderSource fragment_shader\n    cdef object _source\n    cdef object vert_src\n    cdef object frag_src\n    cdef dict uniform_locations\n    cdef dict uniform_values\n\n    cdef void use(self)\n    cdef void stop(self)\n    cdef int set_uniform(self, str name, value) except -1\n    cdef int upload_uniform(self, str name, value) except -1\n    cdef void upload_uniform_matrix(self, int loc, Matrix value)\n    cdef int get_uniform_loc(self, str name) except *\n    cdef int build(self) except -1\n    cdef int build_vertex(self, int link=*) except -1\n    cdef int build_fragment(self, int link=*) except -1\n    cdef int link_program(self) except -1\n    cdef int is_linked(self)\n    cdef ShaderSource compile_shader(self, str source, int shadertype)\n    cdef get_program_log(self, shader)\n    cdef void process_message(self, str ctype, message)\n    cdef void reload(self)\n    cdef void bind_vertex_format(self, VertexFormat vertex_format)\n"
  },
  {
    "path": "tickeys/kivy/graphics/stencil_instructions.pxd",
    "content": "from kivy.graphics.instructions cimport Instruction\n\ncdef class StencilPush(Instruction):\n    cdef int apply(self) except -1 \ncdef class StencilPop(Instruction):\n    cdef int apply(self) except -1\ncdef class StencilUse(Instruction):\n    cdef unsigned int _op\n    cdef int apply(self) except -1\ncdef class StencilUnUse(Instruction):\n    cdef int apply(self) except -1\n"
  },
  {
    "path": "tickeys/kivy/graphics/svg.pxd",
    "content": "cdef class Matrix\ncdef class Svg\n\nfrom cython cimport view\nfrom kivy.graphics.instructions cimport RenderContext\nfrom kivy.graphics.texture cimport Texture\nfrom kivy.graphics.vertex cimport VertexFormat\nfrom kivy.graphics.vertex_instructions cimport StripMesh\nfrom cpython cimport array\nfrom array import array\n\ncdef set COMMANDS\ncdef set UPPERCASE\ncdef object RE_LIST\ncdef object RE_COMMAND\ncdef object RE_FLOAT\ncdef object RE_POLYLINE\ncdef object RE_TRANSFORM\ncdef VertexFormat VERTEX_FORMAT\nctypedef double matrix_t[6]\ncdef list kv_color_to_int_color(color)\ncdef float parse_float(txt)\ncdef list parse_list(string)\ncdef dict parse_style(string)\ncdef parse_color(c, current_color=?)\n\ncdef class Matrix:\n    cdef matrix_t mat\n    cdef void transform(self, float ox, float oy, float *x, float *y)\n    cpdef Matrix inverse(self)\n\ncdef class Svg(RenderContext):\n    cdef public double width\n    cdef public double height\n    cdef float line_width\n    cdef list paths\n    cdef object transform\n    cdef object fill\n    cdef public object current_color\n    cdef object stroke\n    cdef float opacity\n    cdef float x\n    cdef float y\n    cdef int close_index\n    cdef list path\n    cdef array.array loop\n    cdef int bezier_points\n    cdef int circle_points\n    cdef public object gradients\n    cdef view.array bezier_coefficients\n    cdef float anchor_x\n    cdef float anchor_y\n    cdef double last_cx\n    cdef double last_cy\n    cdef Texture line_texture\n    cdef StripMesh last_mesh\n\n    cdef parse_tree(self, tree)\n    cdef parse_element(seld, e)\n    cdef list parse_transform(self, transform_def)\n    cdef parse_path(self, pathdef)\n    cdef void new_path(self)\n    cdef void close_path(self)\n    cdef void set_position(self, float x, float y, int absolute=*)\n    cdef arc_to(self, float rx, float ry, float phi, float large_arc,\n            float sweep, float x, float y)\n    cdef void curve_to(self, float x1, float y1, float x2, float y2,\n            float x, float y)\n    cdef void end_path(self)\n    cdef void push_mesh(self, float[:] path, fill, Matrix transform, mode)\n    cdef void push_strip_mesh(self, float *vertices, int vindex, int count,\n                              int mode=*)\n    cdef void push_line_mesh(self, float[:] path, fill, Matrix transform)\n    cdef void render(self)\n"
  },
  {
    "path": "tickeys/kivy/graphics/tesselator.pxd",
    "content": "cdef class Tesselator:\n    cdef void *tess\n    cdef int element_type\n    cdef int polysize\n    cdef void add_contour_data(self, void *cdata, int count)\n    cdef iterate_vertices(self, int mode)\n    cpdef int tesselate(\n            self, int winding_rule=?,\n            int element_type=?, int polysize=?)\n"
  },
  {
    "path": "tickeys/kivy/graphics/texture.pxd",
    "content": "from c_opengl cimport GLuint\n\ncdef class Texture:\n    cdef object __weakref__\n    cdef unsigned int flags\n\n    cdef object _source\n    cdef float _tex_coords[8]\n    cdef int _width\n    cdef int _height\n    cdef GLuint _target\n    cdef GLuint _id\n    cdef int _mipmap\n    cdef object _wrap\n    cdef object _min_filter\n    cdef object _mag_filter\n    cdef int _rectangle\n    cdef object _colorfmt\n    cdef object _icolorfmt\n    cdef object _bufferfmt\n    cdef float _uvx\n    cdef float _uvy\n    cdef float _uvw\n    cdef float _uvh\n    cdef int _is_allocated\n    cdef int _nofree\n    cdef list observers\n    cdef object _proxyimage\n    cdef object _callback\n\n    cdef void update_tex_coords(self)\n    cdef void set_min_filter(self, x)\n    cdef void set_mag_filter(self, x)\n    cdef void set_wrap(self, x)\n    cdef void reload(self)\n    cdef void _reload_propagate(self, Texture texture)\n    cdef void allocate(self)\n\n    cpdef flip_vertical(self)\n    cpdef flip_horizontal(self)\n    cpdef get_region(self, x, y, width, height)\n    cpdef bind(self)\n\ncdef class TextureRegion(Texture):\n    cdef int x\n    cdef int y\n    cdef Texture owner\n    cdef void reload(self)\n    cpdef bind(self)\n"
  },
  {
    "path": "tickeys/kivy/graphics/transformation.pxd",
    "content": "ctypedef double matrix_t[16]\n\ncdef class Matrix:\n    cdef matrix_t mat\n\n    cpdef Matrix identity(self)\n\n    cpdef Matrix inverse(self)\n\n    cpdef Matrix transpose(self)\n\n    cpdef Matrix multiply(Matrix self, Matrix mb)\n\n    cpdef Matrix scale(Matrix self, double x, double y, double z)\n\n    cpdef Matrix translate(Matrix self, double x, double y, double z)\n\n    cpdef Matrix rotate(Matrix self,\n            double angle, double x, double y, double z)\n\n    cpdef Matrix view_clip(Matrix self, double left, double right,\n            double bottom, double top,\n            double near, double far, int perspective)\n\n    cpdef Matrix perspective(Matrix self, double fovy, double aspect,\n            double zNear, double zFar)\n\n    cpdef look_at(Matrix self, double eyex, double eyey, double eyez,\n            double centerx, double centery, double centerz,\n            double upx, double upy, double upz)\n\n    cpdef Matrix normal_matrix(self)\n\n    cpdef tuple transform_point(Matrix self, double x, double y, double z,\n            t=?)\n\n    cpdef project(Matrix self, double objx, double objy, double objz, Matrix model, Matrix proj,\n            double vx, double vy, double vw, double vh)\n"
  },
  {
    "path": "tickeys/kivy/graphics/vbo.pxd",
    "content": "from buffer cimport Buffer\nfrom c_opengl cimport GLuint\nfrom vertex cimport vertex_t, vertex_attr_t, VertexFormat\n\ncdef VertexFormat default_vertex\n\ncdef class VBO:\n    cdef object __weakref__\n\n    cdef GLuint id\n    cdef int usage\n    cdef int target\n    cdef vertex_attr_t *format\n    cdef long format_count\n    cdef long format_size\n    cdef Buffer data\n    cdef short flags\n    cdef long vbo_size\n    cdef VertexFormat vertex_format\n\n    cdef void update_buffer(self)\n    cdef void bind(self)\n    cdef void unbind(self)\n    cdef void add_vertex_data(self, void *v, unsigned short* indices, int count)\n    cdef void update_vertex_data(self, int index, void* v, int count)\n    cdef void remove_vertex_data(self, unsigned short* indices, int count)\n    cdef void reload(self)\n    cdef int have_id(self)\n\n\ncdef class VertexBatch:\n    cdef object __weakref__\n\n    cdef VBO vbo\n    cdef Buffer elements\n    cdef Buffer vbo_index\n    cdef GLuint mode\n    cdef str mode_str\n    cdef GLuint id\n    cdef int usage\n    cdef short flags\n    cdef long elements_size\n\n    cdef void clear_data(self)\n    cdef void set_data(self, void *vertices, int vertices_count,\n                       unsigned short *indices, int indices_count)\n    cdef void append_data(self, void *vertices, int vertices_count,\n                          unsigned short *indices, int indices_count)\n    cdef void draw(self)\n    cdef void set_mode(self, str mode)\n    cdef str get_mode(self)\n    cdef int count(self)\n    cdef void reload(self)\n    cdef int have_id(self)\n"
  },
  {
    "path": "tickeys/kivy/graphics/vertex.pxd",
    "content": "from c_opengl cimport GLuint\n\ncdef struct vertex_t:\n    float x, y\n    float s0, t0\n\nctypedef struct vertex_attr_t:\n    char *name\n    unsigned int index\n    unsigned int size\n    GLuint type\n    unsigned int bytesize\n    int per_vertex\n\ncdef class VertexFormat:\n    cdef vertex_attr_t *vattr\n    cdef long vattr_count\n    cdef unsigned int vsize\n    cdef unsigned int vbytesize\n    cdef object last_shader\n\n"
  },
  {
    "path": "tickeys/kivy/graphics/vertex_instructions.pxd",
    "content": "from kivy.graphics.instructions cimport VertexInstruction\nfrom kivy.graphics.vertex cimport VertexFormat\n\n\ncdef class Bezier(VertexInstruction):\n    cdef list _points\n    cdef int _segments\n    cdef bint _loop\n    cdef int _dash_offset, _dash_length\n\n    cdef void build(self)\n\n\ncdef class StripMesh(VertexInstruction):\n    cdef int icount\n    cdef int li, lic\n    cdef int add_triangle_strip(self, float *vertices, int vcount, int icount,\n            int mode)\n\n\ncdef class Mesh(VertexInstruction):\n    cdef list _vertices\n    cdef list _indices\n    cdef VertexFormat vertex_format\n    cdef int is_built\n\n    cdef void build_triangle_fan(self, float *vertices, int vcount, int icount)\n    cdef void build(self)\n"
  },
  {
    "path": "tickeys/kivy/graphics/vertex_instructions_line.pxi",
    "content": "DEF LINE_CAP_NONE = 0\nDEF LINE_CAP_SQUARE = 1\nDEF LINE_CAP_ROUND = 2\n\nDEF LINE_JOINT_NONE = 0\nDEF LINE_JOINT_MITER = 1\nDEF LINE_JOINT_BEVEL = 2\nDEF LINE_JOINT_ROUND = 3\n\nDEF LINE_MODE_POINTS = 0\nDEF LINE_MODE_ELLIPSE = 1\nDEF LINE_MODE_CIRCLE = 2\nDEF LINE_MODE_RECTANGLE = 3\nDEF LINE_MODE_ROUNDED_RECTANGLE = 4\nDEF LINE_MODE_BEZIER = 5\n\nfrom kivy.graphics.stencil_instructions cimport StencilUse, StencilUnUse, StencilPush, StencilPop\n\ncdef float PI = 3.1415926535\n\ncdef inline int line_intersection(double x1, double y1, double x2, double y2,\n        double x3, double y3, double x4, double y4, double *px, double *py):\n    cdef double u = (x1 * y2 - y1 * x2)\n    cdef double v = (x3 * y4 - y3 * x4)\n    cdef double denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)\n    if denom == 0:\n        return 0\n    px[0] = (u * (x3 - x4) - (x1 - x2) * v) / denom\n    py[0] = (u * (y3 - y4) - (y1 - y2) * v) / denom\n    return 1\n\ncdef class Line(VertexInstruction):\n    '''A 2d line.\n\n    Drawing a line can be done easily::\n\n        with self.canvas:\n            Line(points=[100, 100, 200, 100, 100, 200], width=10)\n\n    The line has 3 internal drawing modes that you should be aware of\n    for optimal results:\n\n    #. If the :attr:`width` is 1.0, then the standard GL_LINE drawing from\n       OpenGL will be used. :attr:`dash_length` and :attr:`dash_offset` will\n       work, while properties for cap and joint have no meaning here.\n    #. If the :attr:`width` is > 1.0, then a custom drawing method will be used,\n       based on triangles. :attr:`dash_length` and :attr:`dash_offset` do not\n       work in this mode.\n       Additionally, if the current color has an alpha < 1.0, a stencil will be\n       used internally to draw the line.\n\n    .. image:: images/line-instruction.png\n        :align: center\n\n    :Parameters:\n        `points`: list\n            List of points in the format (x1, y1, x2, y2...)\n        `dash_length`: int\n            Length of a segment (if dashed), defaults to 1.\n        `dash_offset`: int\n            Offset between the end of a segments and the begining of the\n            next one, defaults to 0. Changing this makes it dashed.\n        `width`: float\n            Width of the line, defaults to 1.0.\n        `cap`: str, defaults to 'round'\n            See :attr:`cap` for more information.\n        `joint`: str, defaults to 'round'\n            See :attr:`joint` for more information.\n        `cap_precision`: int, defaults to 10\n            See :attr:`cap_precision` for more information\n        `joint_precision`: int, defaults to 10\n            See :attr:`joint_precision` for more information\n            See :attr:`cap_precision` for more information.\n        `joint_precision`: int, defaults to 10\n            See :attr:`joint_precision` for more information.\n        `close`: bool, defaults to False\n            If True, the line will be closed.\n        `circle`: list\n            If set, the :attr:`points` will be set to build a circle. Check\n            :attr:`circle` for more information.\n        `ellipse`: list\n            If set, the :attr:`points` will be set to build an ellipse. Check\n            :attr:`ellipse` for more information.\n        `rectangle`: list\n            If set, the :attr:`points` will be set to build a rectangle. Check\n            :attr:`rectangle` for more information.\n        `bezier`: list\n            If set, the :attr:`points` will be set to build a bezier line. Check\n            :attr:`bezier` for more information.\n        `bezier_precision`: int, defaults to 180\n            Precision of the Bezier drawing.\n\n    .. versionchanged:: 1.0.8\n        `dash_offset` and `dash_length` have been added\n\n    .. versionchanged:: 1.4.1\n        `width`, `cap`, `joint`, `cap_precision`, `joint_precision`, `close`,\n        `ellipse`, `rectangle` have been added.\n\n    .. versionchanged:: 1.4.1\n        `bezier`, `bezier_precision` have been added.\n\n    '''\n    cdef int _cap\n    cdef int _cap_precision\n    cdef int _joint_precision\n    cdef int _bezier_precision\n    cdef int _joint\n    cdef list _points\n    cdef float _width\n    cdef int _dash_offset, _dash_length\n    cdef int _use_stencil\n    cdef int _close\n    cdef int _mode\n    cdef Instruction _stencil_rect\n    cdef Instruction _stencil_push\n    cdef Instruction _stencil_use\n    cdef Instruction _stencil_unuse\n    cdef Instruction _stencil_pop\n    cdef double _bxmin, _bxmax, _bymin, _bymax\n    cdef tuple _mode_args\n\n    def __init__(self, **kwargs):\n        VertexInstruction.__init__(self, **kwargs)\n        v = kwargs.get('points')\n        self.points = v if v is not None else []\n        self.batch.set_mode('line_strip')\n        self._dash_length = kwargs.get('dash_length') or 1\n        self._dash_offset = kwargs.get('dash_offset') or 0\n        self._width = kwargs.get('width') or 1.0\n        self.joint = kwargs.get('joint') or 'round'\n        self.cap = kwargs.get('cap') or 'round'\n        self._cap_precision = kwargs.get('cap_precision') or 10\n        self._joint_precision = kwargs.get('joint_precision') or 10\n        self._bezier_precision = kwargs.get('bezier_precision') or 180\n        self._close = int(bool(kwargs.get('close', 0)))\n        self._stencil_rect = None\n        self._stencil_push = None\n        self._stencil_use = None\n        self._stencil_unuse = None\n        self._stencil_pop = None\n        self._use_stencil = 0\n\n        if 'ellipse' in kwargs:\n            self.ellipse = kwargs['ellipse']\n        if 'circle' in kwargs:\n            self.circle = kwargs['circle']\n        if 'rectangle' in kwargs:\n            self.rectangle = kwargs['rectangle']\n        if 'bezier' in kwargs:\n            self.bezier = kwargs['bezier']\n\n    cdef void build(self):\n        if self._mode == LINE_MODE_ELLIPSE:\n            self.prebuild_ellipse()\n        elif self._mode == LINE_MODE_CIRCLE:\n            self.prebuild_circle()\n        elif self._mode == LINE_MODE_RECTANGLE:\n            self.prebuild_rectangle()\n        elif self._mode == LINE_MODE_ROUNDED_RECTANGLE:\n            self.prebuild_rounded_rectangle()\n        elif self._mode == LINE_MODE_BEZIER:\n            self.prebuild_bezier()\n        if self._width == 1.0:\n            self.build_legacy()\n        else:\n            self.build_extended()\n\n    cdef void ensure_stencil(self):\n        if self._stencil_rect == None:\n            self._stencil_rect = Rectangle()\n            self._stencil_push = StencilPush()\n            self._stencil_pop = StencilPop()\n            self._stencil_use = StencilUse(op='lequal')\n            self._stencil_unuse = StencilUnUse()\n\n    cdef int apply(self) except -1:\n        if self._width == 1.:\n            VertexInstruction.apply(self)\n            return 0\n\n        cdef double alpha = getActiveContext()['color'][-1]\n        self._use_stencil = alpha < 1\n        if self._use_stencil:\n            self.ensure_stencil()\n\n            self._stencil_push.apply()\n            VertexInstruction.apply(self)\n            self._stencil_use.apply()\n            self._stencil_rect.pos = self._bxmin, self._bymin\n            self._stencil_rect.size = self._bxmax - self._bxmin, self._bymax - self._bymin\n            self._stencil_rect.apply()\n            self._stencil_unuse.apply()\n            VertexInstruction.apply(self)\n            self._stencil_pop.apply()\n        else:\n            VertexInstruction.apply(self)\n        return 0\n\n    cdef void build_legacy(self):\n        cdef int i\n        cdef long count = len(self.points) / 2\n        cdef list p = self.points\n        cdef vertex_t *vertices = NULL\n        cdef unsigned short *indices = NULL\n        cdef float tex_x\n        cdef char *buf = NULL\n        cdef Texture texture = self.texture\n\n        if count < 2:\n            self.batch.clear_data()\n            return\n\n        if self._close:\n            p = p + [p[0], p[1]]\n            count += 1\n\n        self.batch.set_mode('line_strip')\n        if self._dash_offset != 0:\n            if texture is None or texture._width != \\\n                (self._dash_length + self._dash_offset) or \\\n                texture._height != 1:\n\n                self.texture = texture = Texture.create(\n                        size=(self._dash_length + self._dash_offset, 1))\n                texture.wrap = 'repeat'\n\n            # create a buffer to fill our texture\n            buf = <char *>malloc(4 * (self._dash_length + self._dash_offset))\n            memset(buf, 255, self._dash_length * 4)\n            memset(buf + self._dash_length * 4, 0, self._dash_offset * 4)\n            p_str = buf[:(self._dash_length + self._dash_offset) * 4]\n\n            self.texture.blit_buffer(p_str, colorfmt='rgba', bufferfmt='ubyte')\n            free(buf)\n\n        elif texture is not None:\n            self.texture = None\n\n        vertices = <vertex_t *>malloc(count * sizeof(vertex_t))\n        if vertices == NULL:\n            raise MemoryError('vertices')\n\n        indices = <unsigned short *>malloc(count * sizeof(unsigned short))\n        if indices == NULL:\n            free(vertices)\n            raise MemoryError('indices')\n\n        tex_x = 0\n        for i in xrange(count):\n            if self._dash_offset != 0 and i > 0:\n                tex_x += sqrt(\n                        pow(p[i * 2]     - p[(i - 1) * 2], 2)  +\n                        pow(p[i * 2 + 1] - p[(i - 1) * 2 + 1], 2)) / (\n                                self._dash_length + self._dash_offset)\n\n                vertices[i].s0 = tex_x\n                vertices[i].t0 = 0\n\n            vertices[i].x = p[i * 2]\n            vertices[i].y = p[i * 2 + 1]\n            indices[i] = i\n\n        self.batch.set_data(vertices, <int>count, indices, <int>count)\n\n        free(vertices)\n        free(indices)\n\n    cdef void build_extended(self):\n        cdef int i, j\n        cdef long count = len(self.points) / 2\n        cdef list p = self.points\n        cdef vertex_t *vertices = NULL\n        cdef unsigned short *indices = NULL\n        cdef float tex_x\n        cdef int cap\n        cdef char *buf = NULL\n        cdef Texture texture = self.texture\n\n        self._bxmin = 999999999\n        self._bymin = 999999999\n        self._bxmax = -999999999\n        self._bymax = -999999999\n\n        if count < 2:\n            self.batch.clear_data()\n            return\n\n        cap = self._cap\n        if self._close and count > 2:\n            p = p + p[0:4]\n            count += 2\n            cap = LINE_CAP_NONE\n\n        self.batch.set_mode('triangles')\n        cdef unsigned long vertices_count = (count - 1) * 4\n        cdef unsigned long indices_count = (count - 1) * 6\n        cdef unsigned int iv = 0, ii = 0\n\n        if self._joint == LINE_JOINT_BEVEL:\n            indices_count += (count - 2) * 3\n            vertices_count += (count - 2)\n        elif self._joint == LINE_JOINT_ROUND:\n            indices_count += (self._joint_precision * 3) * (count - 2)\n            vertices_count += (self._joint_precision) * (count - 2)\n        elif self._joint == LINE_JOINT_MITER:\n            indices_count += (count - 2) * 6\n            vertices_count += (count - 2) * 2\n\n        if cap == LINE_CAP_SQUARE:\n            indices_count += 12\n            vertices_count += 4\n        elif cap == LINE_CAP_ROUND:\n            indices_count += (self._cap_precision * 3) * 2\n            vertices_count += (self._cap_precision) * 2\n\n        vertices = <vertex_t *>malloc(vertices_count * sizeof(vertex_t))\n        if vertices == NULL:\n            raise MemoryError('vertices')\n\n        indices = <unsigned short *>malloc(indices_count * sizeof(unsigned short))\n        if indices == NULL:\n            free(vertices)\n            raise MemoryError('indices')\n\n        cdef double ax, ay, bx, _by, cx, cy, angle, a1, a2\n        cdef double x1, y1, x2, y2, x3, y3, x4, y4\n        cdef double sx1, sy1, sx4, sy4, sangle\n        cdef double pcx, pcy, px1, py1, px2, py2, px3, py3, px4, py4, pangle, pangle2\n        cdef double w = self._width\n        cdef double ix, iy\n        cdef unsigned int piv, pii2, piv2\n        cdef double jangle\n        angle = sangle = 0\n        piv = pcx = pcy = cx = cy = ii = iv = ix = iy = 0\n        px1 = px2 = px3 = px4 = py1 = py2 = py3 = py4 = 0\n        sx1 = sy1 = sx4 = sy4 = 0\n        x1 = x2 = x3 = x4 = y1 = y2 = y3 = y4 = 0\n        cdef double cos1 = 0, cos2 = 0, sin1 = 0, sin2 = 0\n        for i in range(0, count - 1):\n            ax = p[i * 2]\n            ay = p[i * 2 + 1]\n            bx = p[i * 2 + 2]\n            _by = p[i * 2 + 3]\n\n            if i > 0 and self._joint != LINE_JOINT_NONE:\n                pcx = cx\n                pcy = cy\n                px1 = x1\n                px2 = x2\n                px3 = x3\n                px4 = x4\n                py1 = y1\n                py2 = y2\n                py3 = y3\n                py4 = y4\n\n            piv2 = piv\n            piv = iv\n            pangle2 = pangle\n            pangle = angle\n\n            # calculate the orientation of the segment, between pi and -pi\n            cx = bx - ax\n            cy = _by - ay\n            angle = atan2(cy, cx)\n            a1 = angle - PI2\n            a2 = angle + PI2\n\n            # calculate the position of the segment\n            cos1 = cos(a1) * w\n            sin1 = sin(a1) * w\n            cos2 = cos(a2) * w\n            sin2 = sin(a2) * w\n            x1 = ax + cos1\n            y1 = ay + sin1\n            x4 = ax + cos2\n            y4 = ay + sin2\n            x2 = bx + cos1\n            y2 = _by + sin1\n            x3 = bx + cos2\n            y3 = _by + sin2\n\n            if i == 0:\n                sx1 = x1\n                sy1 = y1\n                sx4 = x4\n                sy4 = y4\n                sangle = angle\n\n            indices[ii    ] = iv\n            indices[ii + 1] = iv + 1\n            indices[ii + 2] = iv + 2\n            indices[ii + 3] = iv\n            indices[ii + 4] = iv + 2\n            indices[ii + 5] = iv + 3\n            ii += 6\n\n            vertices[iv].x = x1\n            vertices[iv].y = y1\n            vertices[iv].s0 = 0\n            vertices[iv].t0 = 0\n            iv += 1\n            vertices[iv].x = x2\n            vertices[iv].y = y2\n            vertices[iv].s0 = 1\n            vertices[iv].t0 = 0\n            iv += 1\n            vertices[iv].x = x3\n            vertices[iv].y = y3\n            vertices[iv].s0 = 1\n            vertices[iv].t0 = 1\n            iv += 1\n            vertices[iv].x = x4\n            vertices[iv].y = y4\n            vertices[iv].s0 = 0\n            vertices[iv].t0 = 1\n            iv += 1\n\n            # joint generation\n            if i == 0 or self._joint == LINE_JOINT_NONE:\n                continue\n\n            # calculate the angle of the previous and current segment\n            jangle = atan2(\n                cx * pcy - cy * pcx,\n                cx * pcx + cy * pcy)\n\n            # in case of the angle is NULL, avoid the generation\n            if jangle == 0:\n                if self._joint == LINE_JOINT_ROUND:\n                    vertices_count -= self._joint_precision\n                    indices_count -= self._joint_precision * 3\n                elif self._joint == LINE_JOINT_BEVEL:\n                    vertices_count -= 1\n                    indices_count -= 3\n                elif self._joint == LINE_JOINT_MITER:\n                    vertices_count -= 2\n                    indices_count -= 6\n                continue\n\n            if self._joint == LINE_JOINT_BEVEL:\n                vertices[iv].x = ax\n                vertices[iv].y = ay\n                vertices[iv].s0 = 0\n                vertices[iv].t0 = 0\n                if jangle < 0:\n                    indices[ii] = piv2 + 1\n                    indices[ii + 1] = piv\n                    indices[ii + 2] = iv\n                else:\n                    indices[ii] = piv2 + 2\n                    indices[ii + 1] = piv + 3\n                    indices[ii + 2] = iv\n                ii += 3\n                iv += 1\n\n            elif self._joint == LINE_JOINT_MITER:\n                vertices[iv].x = ax\n                vertices[iv].y = ay\n                vertices[iv].s0 = 0\n                vertices[iv].t0 = 0\n                if jangle < 0:\n                    if line_intersection(px1, py1, px2, py2, x1, y1, x2, y2, &ix, &iy) == 0:\n                        vertices_count -= 2\n                        indices_count -= 6\n                        continue\n                    vertices[iv + 1].x = ix\n                    vertices[iv + 1].y = iy\n                    vertices[iv + 1].s0 = 0\n                    vertices[iv + 1].t0 = 0\n                    indices[ii] = iv\n                    indices[ii + 1] = iv + 1\n                    indices[ii + 2] = piv2 + 1\n                    indices[ii + 3] = iv\n                    indices[ii + 4] = piv\n                    indices[ii + 5] = iv + 1\n                    ii += 6\n                    iv += 2\n                else:\n                    if line_intersection(px3, py3, px4, py4, x3, y3, x4, y4, &ix, &iy) == 0:\n                        vertices_count -= 2\n                        indices_count -= 6\n                        continue\n                    vertices[iv + 1].x = ix\n                    vertices[iv + 1].y = iy\n                    vertices[iv + 1].s0 = 0\n                    vertices[iv + 1].t0 = 0\n                    indices[ii] = iv\n                    indices[ii + 1] = iv + 1\n                    indices[ii + 2] = piv2 + 2\n                    indices[ii + 3] = iv\n                    indices[ii + 4] = piv + 3\n                    indices[ii + 5] = iv + 1\n                    ii += 6\n                    iv += 2\n\n\n\n            elif self._joint == LINE_JOINT_ROUND:\n\n                # cap end\n                if jangle < 0:\n                    a1 = pangle2 - PI2\n                    a2 = angle + PI2\n                    a0 = a2\n                    step = (abs(jangle)) / float(self._joint_precision)\n                    pivstart = piv + 3\n                    pivend = piv2 + 1\n                else:\n                    a1 = angle - PI2\n                    a2 = pangle2 + PI2\n                    a0 = a1\n                    step = -(abs(jangle)) / float(self._joint_precision)\n                    pivstart = piv\n                    pivend = piv2 + 2\n                siv = iv\n                vertices[iv].x = ax\n                vertices[iv].y = ay\n                vertices[iv].s0 = 0\n                vertices[iv].t0 = 0\n                iv += 1\n                for j in xrange(0, self._joint_precision - 1):\n                    vertices[iv].x = ax - cos(a0 - step * j) * w\n                    vertices[iv].y = ay - sin(a0 - step * j) * w\n                    vertices[iv].s0 = 0\n                    vertices[iv].t0 = 0\n                    if j == 0:\n                        indices[ii] = siv\n                        indices[ii + 1] = pivstart\n                        indices[ii + 2] = iv\n                    else:\n                        indices[ii] = siv\n                        indices[ii + 1] = iv - 1\n                        indices[ii + 2] = iv\n                    iv += 1\n                    ii += 3\n                indices[ii] = siv\n                indices[ii + 1] = iv - 1\n                indices[ii + 2] = pivend\n                ii += 3\n\n        # caps\n        if cap == LINE_CAP_SQUARE:\n            vertices[iv].x = x2 + cos(angle) * w\n            vertices[iv].y = y2 + sin(angle) * w\n            vertices[iv].s0 = 0\n            vertices[iv].t0 = 0\n            vertices[iv + 1].x = x3 + cos(angle) * w\n            vertices[iv + 1].y = y3 + sin(angle) * w\n            vertices[iv + 1].s0 = 0\n            vertices[iv + 1].t0 = 0\n            indices[ii] = piv + 1\n            indices[ii + 1] = piv + 2\n            indices[ii + 2] = iv + 1\n            indices[ii + 3] = piv + 1\n            indices[ii + 4] = iv\n            indices[ii + 5] = iv + 1\n            ii += 6\n            iv += 2\n            vertices[iv].x = sx1 - cos(sangle) * w\n            vertices[iv].y = sy1 - sin(sangle) * w\n            vertices[iv].s0 = 0\n            vertices[iv].t0 = 0\n            vertices[iv + 1].x = sx4 - cos(sangle) * w\n            vertices[iv + 1].y = sy4 - sin(sangle) * w\n            vertices[iv + 1].s0 = 0\n            vertices[iv + 1].t0 = 0\n            indices[ii] = 0\n            indices[ii + 1] = 3\n            indices[ii + 2] = iv + 1\n            indices[ii + 3] = 0\n            indices[ii + 4] = iv\n            indices[ii + 5] = iv + 1\n            ii += 6\n            iv += 2\n\n        elif cap == LINE_CAP_ROUND:\n\n            # cap start\n            a1 = sangle - PI2\n            a2 = sangle + PI2\n            step = (a1 - a2) / float(self._cap_precision)\n            siv = iv\n            cx = p[0]\n            cy = p[1]\n            vertices[iv].x = cx\n            vertices[iv].y = cy\n            vertices[iv].s0 = 0\n            vertices[iv].t0 = 0\n            iv += 1\n            for i in xrange(0, self._cap_precision - 1):\n                vertices[iv].x = cx + cos(a1 + step * i) * w\n                vertices[iv].y = cy + sin(a1 + step * i) * w\n                vertices[iv].s0 = 1\n                vertices[iv].t0 = 1\n                if i == 0:\n                    indices[ii] = siv\n                    indices[ii + 1] = 0\n                    indices[ii + 2] = iv\n                else:\n                    indices[ii] = siv\n                    indices[ii + 1] = iv - 1\n                    indices[ii + 2] = iv\n                iv += 1\n                ii += 3\n            indices[ii] = siv\n            indices[ii + 1] = iv - 1\n            indices[ii + 2] = 3\n            ii += 3\n\n            # cap end\n            a1 = angle - PI2\n            a2 = angle + PI2\n            step = (a2 - a1) / float(self._cap_precision)\n            siv = iv\n            cx = p[-2]\n            cy = p[-1]\n            vertices[iv].x = cx\n            vertices[iv].y = cy\n            vertices[iv].s0 = 0\n            vertices[iv].t0 = 0\n            iv += 1\n            for i in xrange(0, self._cap_precision - 1):\n                vertices[iv].x = cx + cos(a1 + step * i) * w\n                vertices[iv].y = cy + sin(a1 + step * i) * w\n                vertices[iv].s0 = 0\n                vertices[iv].t0 = 0\n                if i == 0:\n                    indices[ii] = siv\n                    indices[ii + 1] = piv + 1\n                    indices[ii + 2] = iv\n                else:\n                    indices[ii] = siv\n                    indices[ii + 1] = iv - 1\n                    indices[ii + 2] = iv\n                iv += 1\n                ii += 3\n            indices[ii] = siv\n            indices[ii + 1] = iv - 1\n            indices[ii + 2] = piv + 2\n            ii += 3\n\n        # compute bbox\n        for i in xrange(vertices_count):\n            if vertices[i].x < self._bxmin:\n                self._bxmin = vertices[i].x\n            if vertices[i].x > self._bxmax:\n                self._bxmax = vertices[i].x\n            if vertices[i].y < self._bymin:\n                self._bymin = vertices[i].y\n            if vertices[i].y > self._bymax:\n                self._bymax = vertices[i].y\n\n        self.batch.set_data(vertices, <int>vertices_count,\n                           indices, <int>indices_count)\n\n        free(vertices)\n        free(indices)\n\n\n\n    property points:\n        '''Property for getting/settings points of the line\n\n        .. warning::\n\n            This will always reconstruct the whole graphics from the new points\n            list. It can be very CPU expensive.\n        '''\n        def __get__(self):\n            return self._points\n        def __set__(self, points):\n            self._points = list(points)\n            self.flag_update()\n\n    property dash_length:\n        '''Property for getting/setting the length of the dashes in the curve\n\n        .. versionadded:: 1.0.8\n        '''\n        def __get__(self):\n            return self._dash_length\n\n        def __set__(self, value):\n            if value < 0:\n                raise GraphicException('Invalid dash_length value, must be >= 0')\n            self._dash_length = value\n            self.flag_update()\n\n    property dash_offset:\n        '''Property for getting/setting the offset between the dashes in the curve\n\n        .. versionadded:: 1.0.8\n        '''\n        def __get__(self):\n            return self._dash_offset\n\n        def __set__(self, value):\n            if value < 0:\n                raise GraphicException('Invalid dash_offset value, must be >= 0')\n            self._dash_offset = value\n            self.flag_update()\n\n    property width:\n        '''Determine the width of the line, defaults to 1.0.\n\n        .. versionadded:: 1.4.1\n        '''\n        def __get__(self):\n            return self._width\n\n        def __set__(self, value):\n            if value <= 0:\n                raise GraphicException('Invalid width value, must be > 0')\n            self._width = value\n            self.flag_update()\n\n    property cap:\n        '''Determine the cap of the line, defaults to 'round'. Can be one of\n        'none', 'square' or 'round'\n\n        .. versionadded:: 1.4.1\n        '''\n        def __get__(self):\n            if self._cap == LINE_CAP_SQUARE:\n                return 'square'\n            elif self._cap == LINE_CAP_ROUND:\n                return 'round'\n            return 'none'\n\n        def __set__(self, value):\n            if value not in ('none', 'square', 'round'):\n                raise GraphicException('Invalid cap, must be one of '\n                        '\"none\", \"square\", \"round\"')\n            if value == 'square':\n                self._cap = LINE_CAP_SQUARE\n            elif value == 'round':\n                self._cap = LINE_CAP_ROUND\n            else:\n                self._cap = LINE_CAP_NONE\n            self.flag_update()\n\n    property joint:\n        '''Determine the join of the line, defaults to 'round'. Can be one of\n        'none', 'round', 'bevel', 'miter'.\n\n        .. versionadded:: 1.4.1\n        '''\n\n        def __get__(self):\n            if self._joint == LINE_JOINT_ROUND:\n                return 'round'\n            elif self._joint == LINE_JOINT_BEVEL:\n                return 'bevel'\n            elif self._joint == LINE_JOINT_MITER:\n                return 'miter'\n            return 'none'\n\n        def __set__(self, value):\n            if value not in ('none', 'miter', 'bevel', 'round'):\n                raise GraphicException('Invalid joint, must be one of '\n                    '\"none\", \"miter\", \"bevel\", \"round\"')\n            if value == 'round':\n                self._joint = LINE_JOINT_ROUND\n            elif value == 'bevel':\n                self._joint = LINE_JOINT_BEVEL\n            elif value == 'miter':\n                self._joint = LINE_JOINT_MITER\n            else:\n                self._joint = LINE_JOINT_NONE\n            self.flag_update()\n\n    property cap_precision:\n        '''Number of iteration for drawing the \"round\" cap, defaults to 10.\n        The cap_precision must be at least 1.\n\n        .. versionadded:: 1.4.1\n        '''\n\n        def __get__(self):\n            return self._cap_precision\n\n        def __set__(self, value):\n            if value < 1:\n                raise GraphicException('Invalid cap_precision value, must be >= 1')\n            self._cap_precision = int(value)\n            self.flag_update()\n\n    property joint_precision:\n        '''Number of iteration for drawing the \"round\" joint, defaults to 10.\n        The joint_precision must be at least 1.\n\n        .. versionadded:: 1.4.1\n        '''\n\n        def __get__(self):\n            return self._joint_precision\n\n        def __set__(self, value):\n            if value < 1:\n                raise GraphicException('Invalid joint_precision value, must be >= 1')\n            self._joint_precision = int(value)\n            self.flag_update()\n\n    property close:\n        '''If True, the line will be closed.\n\n        .. versionadded:: 1.4.1\n        '''\n\n        def __get__(self):\n            return self._close\n\n        def __set__(self, value):\n            self._close = int(bool(value))\n            self.flag_update()\n\n    property ellipse:\n        '''Use this property to build an ellipse, without calculating the\n        :attr:`points`. You can only set this property, not get it.\n\n        The argument must be a tuple of (x, y, width, height, angle_start,\n        angle_end, segments):\n\n        * x and y represent the bottom left of the ellipse\n        * width and height represent the size of the ellipse\n        * (optional) angle_start and angle_end are in degree. The default\n            value is 0 and 360.\n        * (optional) segments is the precision of the ellipse. The default\n            value is calculated from the range between angle.\n\n        Note that it's up to you to :attr:`close` the ellipse or not.\n\n        For example, for building a simple ellipse, in python::\n\n            # simple ellipse\n            Line(ellipse=(0, 0, 150, 150))\n\n            # only from 90 to 180 degrees\n            Line(ellipse=(0, 0, 150, 150, 90, 180))\n\n            # only from 90 to 180 degrees, with few segments\n            Line(ellipse=(0, 0, 150, 150, 90, 180, 20))\n\n        .. versionadded:: 1.4.1\n        '''\n\n        def __set__(self, args):\n            if args == None:\n                raise GraphicException(\n                        'Invalid ellipse value: {0!r}'.format(args))\n            if len(args) not in (4, 6, 7):\n                raise GraphicException('Invalid number of arguments: '\n                        '{0} instead of 4, 6 or 7.'.format(len(args)))\n            self._mode_args = tuple(args)\n            self._mode = LINE_MODE_ELLIPSE\n            self.flag_update()\n\n    cdef void prebuild_ellipse(self):\n        cdef double x, y, w, h, angle_start = 0, angle_end = 360\n        cdef int angle_dir, segments = 0\n        cdef double angle_range\n        cdef tuple args = self._mode_args\n\n        if len(args) == 4:\n            x, y, w, h = args\n        elif len(args) == 6:\n            x, y, w, h, angle_start, angle_end = args\n        elif len(args) == 7:\n            x, y, w, h, angle_start, angle_end, segments = args\n            segments += 2\n        else:\n            x = y = w = h = 0\n            assert(0)\n\n        if angle_end > angle_start:\n            angle_dir = 1\n        else:\n            angle_dir = -1\n        if segments == 0:\n            segments = int(abs(angle_end - angle_start) / 2) + 3\n            if segments % 2 == 1:\n                segments += 1\n        # rad = deg * (pi / 180), where pi/180 = 0.0174...\n        angle_start = angle_start * 0.017453292519943295\n        angle_end = angle_end * 0.017453292519943295\n        angle_range = abs(angle_end - angle_start) / (segments - 2)\n\n        cdef list points = [0, ] * segments\n        cdef double angle\n        cdef double rx = w * 0.5\n        cdef double ry = h * 0.5\n        for i in xrange(0, segments, 2):\n            angle = angle_start + (angle_dir * (i - 1) * angle_range)\n            points[i] = (x + rx) + (rx * sin(angle))\n            points[i + 1] = (y + ry) + (ry * cos(angle))\n\n        self._points = points\n\n\n    property circle:\n        '''Use this property to build a circle, without calculate the\n        :attr:`points`. You can only set this property, not get it.\n\n        The argument must be a tuple of (center_x, center_y, radius, angle_start,\n        angle_end, segments):\n\n        * center_x and center_y represent the center of the circle\n        * radius represent the radius of the circle\n        * (optional) angle_start and angle_end are in degree. The default\n            value is 0 and 360.\n        * (optional) segments is the precision of the ellipse. The default\n            value is calculated from the range between angle.\n\n        Note that it's up to you to :attr:`close` the circle or not.\n\n        For example, for building a simple ellipse, in python::\n\n            # simple circle\n            Line(circle=(150, 150, 50))\n\n            # only from 90 to 180 degrees\n            Line(circle=(150, 150, 50, 90, 180))\n\n            # only from 90 to 180 degrees, with few segments\n            Line(circle=(150, 150, 50, 90, 180, 20))\n\n        .. versionadded:: 1.4.1\n        '''\n\n        def __set__(self, args):\n            if args == None:\n                raise GraphicException(\n                        'Invalid circle value: {0!r}'.format(args))\n            if len(args) not in (3, 5, 6):\n                raise GraphicException('Invalid number of arguments: '\n                        '{0} instead of 3, 5 or 6.'.format(len(args)))\n            self._mode_args = tuple(args)\n            self._mode = LINE_MODE_CIRCLE\n            self.flag_update()\n\n    cdef void prebuild_circle(self):\n        cdef double x, y, r, angle_start = 0, angle_end = 360\n        cdef int angle_dir, segments = 0\n        cdef double angle_range\n        cdef tuple args = self._mode_args\n\n        if len(args) == 3:\n            x, y, r = args\n        elif len(args) == 5:\n            x, y, r, angle_start, angle_end = args\n        elif len(args) == 6:\n            x, y, r, angle_start, angle_end, segments = args\n            segments += 1\n        else:\n            x = y = r = 0\n            assert(0)\n\n        if angle_end > angle_start:\n            angle_dir = 1\n        else:\n            angle_dir = -1\n        if segments == 0:\n            segments = int(abs(angle_end - angle_start) / 2) + 3\n        \n        segmentpoints = segments * 2\n        \n        # rad = deg * (pi / 180), where pi/180 = 0.0174...\n        angle_start = angle_start * 0.017453292519943295\n        angle_end = angle_end * 0.017453292519943295\n        angle_range = abs(angle_end - angle_start) / (segmentpoints - 2)\n\n        cdef list points = [0, ] * segmentpoints\n        cdef double angle\n        for i in xrange(0, segmentpoints, 2):\n            angle = angle_start + (angle_dir * i * angle_range)\n            points[i] = x + (r * sin(angle))\n            points[i + 1] = y + (r * cos(angle))\n        self._points = points\n\n    property rectangle:\n        '''Use this property to build a rectangle, without calculating the\n        :attr:`points`. You can only set this property, not get it.\n\n        The argument must be a tuple of (x, y, width, height)\n        angle_end, segments):\n\n        * x and y represent the bottom-left position of the rectangle\n        * width and height represent the size\n\n        The line is automatically closed.\n\n        Usage::\n\n            Line(rectangle=(0, 0, 200, 200))\n\n        .. versionadded:: 1.4.1\n        '''\n\n        def __set__(self, args):\n            if args == None:\n                raise GraphicException(\n                        'Invalid rectangle value: {0!r}'.format(args))\n            if len(args) != 4:\n                raise GraphicException('Invalid number of arguments: '\n                        '{0} instead of 4.'.format(len(args)))\n            self._mode_args = tuple(args)\n            self._mode = LINE_MODE_RECTANGLE\n            self.flag_update()\n\n    cdef void prebuild_rectangle(self):\n        cdef double x, y, width, height\n        cdef int angle_dir, segments = 0\n        cdef double angle_range\n        cdef tuple args = self._mode_args\n\n        if args == None:\n            raise GraphicException(\n                    'Invalid ellipse value: {0!r}'.format(args))\n\n        if len(args) == 4:\n            x, y, width, height = args\n        else:\n            x = y = width = height = 0\n            assert(0)\n\n        self._points = [x, y, x + width, y, x + width, y + height, x, y + height]\n        self._close = 1\n\n    property rounded_rectangle:\n        '''Use this property to build a rectangle, without calculating the\n        :attr:`points`. You can only set this property, not get it.\n\n        The argument must be a tuple of one of the following forms:\n\n        * (x, y, width, height, corner_radius)\n        * (x, y, width, height, corner_radius, resolution)\n        * (x, y, width, height, corner_radius1, corner_radius2, corner_radius3, corner_radius4)\n        * (x, y, width, height, corner_radius1, corner_radius2, corner_radius3, corner_radius4, resolution)\n\n        * x and y represent the bottom-left position of the rectangle\n        * width and height represent the size\n        * corner_radius is the number of pixels between two borders and the center of the circle arc joining them\n        * resolution is the numper of line segment that will be used to draw the circle arc at each corner (defaults to 30)\n\n        The line is automatically closed.\n\n        Usage::\n\n            Line(rounded_rectangle=(0, 0, 200, 200, 10, 20, 30, 40, 100))\n\n        .. versionadded:: 1.9.0\n        '''\n        def __set__(self, args):\n            if args == None:\n                raise GraphicException(\n                    'Invlid rounded rectangle value: {0!r}'.format(args))\n            if len(args) not in (5, 6, 8, 9):\n                raise GraphicException('invalid number of arguments:'\n                        '{0} not in (5, 6, 8, 9)'.format(len(args)))\n            self._mode_args = tuple(args)\n            self._mode = LINE_MODE_ROUNDED_RECTANGLE\n            self.flag_update()\n\n    cdef void prebuild_rounded_rectangle(self):\n        cdef float a, px, py, x, y, w, h, c1, c2, c3, c4\n        cdef resolution = 30\n        cdef int l = len(self._mode_args)\n\n        self._points = []\n        a = -PI\n        x, y, w, h = self._mode_args [:4]\n\n        if l == 5:\n            c1 = c2 = c3 = c4 = self._mode_args[4]\n        elif l == 6:\n            c1 = c2 = c3 = c4 = self._mode_args[4]\n            resolution = self._mode_args[5]\n        elif l == 8:\n            c1, c2, c3, c4 = self._mode_args[4:]\n        else:  # l == 9, but else make the compiler happy about uninitialization\n            c1, c2, c3, c4 = self._mode_args[4:8]\n            resolution = self._mode_args[8]\n\n        px = x + c1\n        py = y + c1\n\n        while a < - PI / 2.:\n            a += pi / resolution\n            self._points.extend([\n                px + cos(a) * c1,\n                py + sin(a) * c1])\n\n        px = x + w - c2\n        py = y + c2\n\n        while a < 0:\n            a += PI / resolution\n            self._points.extend([\n                px + cos(a) * c2,\n                py + sin(a) * c2])\n\n        px = x + w - c3\n        py = y + h - c3\n\n        while a < PI / 2.:\n            a += PI / resolution\n            self._points.extend([\n                px + cos(a) * c3,\n                py + sin(a) * c3])\n\n        px = x + c4\n        py = y + h - c4\n\n        while a < PI:\n            a += PI / resolution\n            self._points.extend([\n                px + cos(a) * c4,\n                py + sin(a) * c4])\n\n        self._close = 1\n\n    property bezier:\n        '''Use this property to build a bezier line, without calculating the\n        :attr:`points`. You can only set this property, not get it.\n\n        The argument must be a tuple of 2n elements, n being the number of points.\n\n        Usage::\n\n            Line(bezier=(x1, y1, x2, y2, x3, y3)\n\n        .. versionadded:: 1.4.2\n\n        .. note:: Bezier lines calculations are inexpensive for a low number of\n            points, but complexity is quadratic, so lines with a lot of points\n            can be very expensive to build, use with care!\n        '''\n\n        def __set__(self, args):\n            if args == None or len(args) % 2:\n                raise GraphicException(\n                        'Invalid bezier value: {0!r}'.format(args))\n            self._mode_args = tuple(args)\n            self._mode = LINE_MODE_BEZIER\n            self.flag_update()\n\n    cdef void prebuild_bezier(self):\n        cdef double x, y, l\n        cdef int segments = self._bezier_precision\n        cdef list T = list(self._mode_args)[:]\n\n        self._points = []\n        for x in xrange(segments):\n            l = x / (1.0 * segments)\n            # http://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm\n            # as the list is in the form of (x1, y1, x2, y2...) iteration is\n            # done on each item and the current item (xn or yn) in the list is\n            # replaced with a calculation of \"xn + x(n+1) - xn\" x(n+1) is\n            # placed at n+2. Each iteration makes the list one item shorter\n            for i in range(1, len(T)):\n                for j in xrange(len(T) - 2*i):\n                    T[j] = T[j] + (T[j+2] - T[j]) * l\n\n            # we got the coordinates of the point in T[0] and T[1]\n            self._points.append(T[0])\n            self._points.append(T[1])\n\n        # add one last point to join the curve to the end\n        self._points.append(T[-2])\n        self._points.append(T[-1])\n\n    property bezier_precision:\n        '''Number of iteration for drawing the bezier between 2 segments,\n        defaults to 180. The bezier_precision must be at least 1.\n\n        .. versionadded:: 1.4.2\n        '''\n\n        def __get__(self):\n            return self._bezier_precision\n\n        def __set__(self, value):\n            if value < 1:\n                raise GraphicException('Invalid bezier_precision value, must be >= 1')\n            self._bezier_precision = int(value)\n            self.flag_update()\n\n\ncdef class SmoothLine(Line):\n    '''Experimental line using over-draw method to get better antialiasing\n    results. It has few drawbacks:\n\n    - drawing line with alpha will unlikely doesn't give the intended result if\n      the line cross itself\n    - no cap or joint are supported\n    - it use a custom texture with premultiplied alpha\n    - dash is not supported\n    - line under 1px width are not supported, it will look the same\n\n    .. warning::\n\n        This is an unfinished work, experimental, subject to crash.\n\n    .. versionadded:: 1.9.0\n    '''\n\n    cdef float _owidth\n\n    def __init__(self, **kwargs):\n        VertexInstruction.__init__(self, **kwargs)\n        self._owidth = kwargs.get(\"overdraw_width\") or 1.2\n        self.batch.set_mode(\"triangles\")\n        self.texture = self.premultiplied_texture()\n\n    def premultiplied_texture(self):\n        texture = Texture.create(size=(4, 1), colorfmt=\"rgba\")\n        texture.add_reload_observer(self._smooth_reload_observer)\n        self._smooth_reload_observer(texture)\n        return texture\n\n    cpdef _smooth_reload_observer(self, texture):\n        cdef bytes GRADIENT_DATA = (\n            b\"\\xff\\xff\\xff\\x00\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x00\")\n        texture.blit_buffer(GRADIENT_DATA, colorfmt=\"rgba\")\n\n    cdef void build(self):\n        if self._mode == LINE_MODE_ELLIPSE:\n            self.prebuild_ellipse()\n        elif self._mode == LINE_MODE_CIRCLE:\n            self.prebuild_circle()\n        elif self._mode == LINE_MODE_RECTANGLE:\n            self.prebuild_rectangle()\n        elif self._mode == LINE_MODE_ROUNDED_RECTANGLE:\n            self.prebuild_rounded_rectangle()\n        elif self._mode == LINE_MODE_BEZIER:\n            self.prebuild_bezier()\n\n        self.build_smooth()\n\n    cdef int apply(self) except -1:\n        VertexInstruction.apply(self)\n        return 0\n\n    cdef void build_smooth(self):\n        cdef:\n            list p = self.points\n            float width = max(0, (self._width - 1.))\n            float owidth = width + self._owidth\n            vertex_t *vertices = NULL\n            unsigned short *indices = NULL\n            unsigned short *tindices = NULL\n            double ax, ay, bx = 0., by = 0., rx = 0., ry = 0., last_angle = 0., angle, av_angle\n            float cos1, sin1, cos2, sin2, ocos1, ocos2, osin1, osin2\n            long index, vindex, vcount, icount, iv, ii, max_vindex, count\n            unsigned short i0, i1, i2, i3, i4, i5, i6, i7\n\n        iv = vindex = 0\n        count = len(p) / 2\n        if count < 2:\n            self.batch.clear_data()\n            return\n\n        vcount = count * 4\n        icount = (count - 1) * 18\n        if self._close:\n            icount += 18\n\n        vertices = <vertex_t *>malloc(vcount * sizeof(vertex_t))\n        if vertices == NULL:\n            raise MemoryError(\"vertices\")\n\n        indices = <unsigned short *>malloc(icount * sizeof(unsigned short))\n        if indices == NULL:\n            free(vertices)\n            raise MemoryError(\"indices\")\n\n        if self._close:\n            ax = p[-2]\n            ay = p[-1]\n            bx = p[0]\n            by = p[1]\n            rx = bx - ax\n            ry = by - ay\n            last_angle = atan2(ry, rx)\n\n        max_index = len(p)\n        for index in range(0, max_index, 2):\n            ax = p[index]\n            ay = p[index + 1]\n            if index < max_index - 2:\n                bx = p[index + 2]\n                by = p[index + 3]\n                rx = bx - ax\n                ry = by - ay\n                angle = atan2(ry, rx)\n            else:\n                angle = last_angle\n\n            if index == 0 and not self._close:\n                av_angle = angle\n                ad_angle = pi\n            else:\n                av_angle = atan2(\n                        sin(angle) + sin(last_angle),\n                        cos(angle) + cos(last_angle))\n\n                ad_angle = abs(pi - abs(angle - last_angle))\n\n            a1 = av_angle - PI2\n            a2 = av_angle + PI2\n            '''\n            cos1 = cos(a1) * width\n            sin1 = sin(a1) * width\n            cos2 = cos(a2) * width\n            sin2 = sin(a2) * width\n            ocos1 = cos(a1) * owidth\n            osin1 = sin(a1) * owidth\n            ocos2 = cos(a2) * owidth\n            osin2 = sin(a2) * owidth\n            print 'angle diff', ad_angle\n            '''\n            #l = width\n            #ol = owidth\n\n            if index == 0 or index >= max_index - 2:\n                l = width\n                ol = owidth\n            else:\n                la1 = last_angle - PI2\n                la2 = angle - PI2\n                ra1 = last_angle + PI2\n                ra2 = angle + PI2\n                ox = p[index - 2]\n                oy = p[index - 1]\n                if line_intersection(\n                    ox + cos(la1) * width,\n                    oy + sin(la1) * width,\n                    ax + cos(la1) * width,\n                    ay + sin(la1) * width,\n                    ax + cos(la2) * width,\n                    ay + sin(la2) * width,\n                    bx + cos(la2) * width,\n                    by + sin(la2) * width,\n                    &rx, &ry) == 0:\n                    #print 'ERROR LINE INTERSECTION 1'\n                    pass\n\n                l = sqrt((ax - rx) ** 2 + (ay - ry) ** 2)\n\n                if line_intersection(\n                    ox + cos(ra1) * owidth,\n                    oy + sin(ra1) * owidth,\n                    ax + cos(ra1) * owidth,\n                    ay + sin(ra1) * owidth,\n                    ax + cos(ra2) * owidth,\n                    ay + sin(ra2) * owidth,\n                    bx + cos(ra2) * owidth,\n                    by + sin(ra2) * owidth,\n                    &rx, &ry) == 0:\n                    #print 'ERROR LINE INTERSECTION 2'\n                    pass\n\n                ol = sqrt((ax - rx) ** 2 + (ay - ry) ** 2)\n\n            last_angle = angle\n\n            #l = sqrt(width ** 2 * (1. / sin(av_angle)) ** 2)\n            #l = width / tan(av_angle / 2.)\n            #l = width * sqrt(1 + 1 / (av_angle / 2.))\n            #l = 2 * (width * width * sin(av_angle))\n            #l = 2 * (cos(av_angle / 2.) * width)\n            #l = width / abs(cos(PI2 - 1.5 * ad_angle))\n            cos1 = cos(a1) * l\n            sin1 = sin(a1) * l\n            cos2 = cos(a2) * l\n            sin2 = sin(a2) * l\n\n            #ol = sqrt(owidth ** 2 * (1. / sin(av_angle)) ** 2)\n            #ol = owidth / tan(av_angle / 2.)\n            #ol = owidth * sqrt(1 + 1 / (av_angle / 2.))\n            #ol = 2 * (owidth * owidth * sin(av_angle))\n            #ol = 2 * (cos(av_angle / 2.) * owidth)\n            #ol = owidth / abs(cos(PI2 - 1.5 * ad_angle))\n            ocos1 = cos(a1) * ol\n            osin1 = sin(a1) * ol\n            ocos2 = cos(a2) * ol\n            osin2 = sin(a2) * ol\n\n            x1 = ax + cos1\n            y1 = ay + sin1\n            x2 = ax + cos2\n            y2 = ay + sin2\n\n            ox1 = ax + ocos1\n            oy1 = ay + osin1\n            ox2 = ax + ocos2\n            oy2 = ay + osin2\n\n            vertices[iv].x = x1\n            vertices[iv].y = y1\n            vertices[iv].s0 = 0.5\n            vertices[iv].t0 = 0.25\n            iv += 1\n            vertices[iv].x = x2\n            vertices[iv].y = y2\n            vertices[iv].s0 = 0.5\n            vertices[iv].t0 = 0.75\n            iv += 1\n            vertices[iv].x = ox1\n            vertices[iv].y = oy1\n            vertices[iv].s0 = 1\n            vertices[iv].t0 = 0\n            iv += 1\n            vertices[iv].x = ox2\n            vertices[iv].y = oy2\n            vertices[iv].s0 = 1\n            vertices[iv].t0 = 1\n            iv += 1\n\n        tindices = indices\n        for vindex in range(0, vcount - 4, 4):\n            tindices[0] = vindex\n            tindices[1] = vindex + 2\n            tindices[2] = vindex + 6\n            tindices[3] = vindex\n            tindices[4] = vindex + 6\n            tindices[5] = vindex + 4\n            tindices[6] = vindex + 1\n            tindices[7] = vindex\n            tindices[8] = vindex + 4\n            tindices[9] = vindex + 1\n            tindices[10] = vindex + 4\n            tindices[11] = vindex + 5\n            tindices[12] = vindex + 3\n            tindices[13] = vindex + 1\n            tindices[14] = vindex + 5\n            tindices[15] = vindex + 3\n            tindices[16] = vindex + 5\n            tindices[17] = vindex + 7\n            tindices = tindices + 18\n\n        if self._close:\n            vindex = vcount - 4\n            i0 = vindex\n            i1 = vindex + 1\n            i2 = vindex + 2\n            i3 = vindex + 3\n            i4 = 0\n            i5 = 1\n            i6 = 2\n            i7 = 3\n            tindices[0] = i0\n            tindices[1] = i2\n            tindices[2] = i6\n            tindices[3] = i0\n            tindices[4] = i6\n            tindices[5] = i4\n            tindices[6] = i1\n            tindices[7] = i0\n            tindices[8] = i4\n            tindices[9] = i1\n            tindices[10] = i4\n            tindices[11] = i5\n            tindices[12] = i3\n            tindices[13] = i1\n            tindices[14] = i5\n            tindices[15] = i3\n            tindices[16] = i5\n            tindices[17] = i7\n            tindices = tindices + 18\n\n        #print 'tindices', <long>tindices, <long>indices, (<long>tindices - <long>indices) / sizeof(unsigned short)\n\n\n        self.batch.set_data(vertices, <int>vcount, indices, <int>icount)\n\n        #free(vertices)\n        #free(indices)\n\n\n    property overdraw_width:\n        '''Determine the overdraw width of the line, defaults to 1.2\n        '''\n        def __get__(self):\n            return self._owidth\n\n        def __set__(self, value):\n            if value <= 0:\n                raise GraphicException('Invalid width value, must be > 0')\n            self._owidth = value\n            self.flag_update()\n\n"
  },
  {
    "path": "tickeys/kivy/input/__init__.py",
    "content": "# pylint: disable=W0611\n'''\nInput management\n================\n\nOur input system is wide and simple at the same time. We are currently able to\nnatively support :\n\n* Windows multitouch events (pencil and finger)\n* MacOSX touchpads\n* Linux multitouch events (kernel and mtdev)\n* Linux wacom drivers (pencil and finger)\n* TUIO\n\nAll the input management is configurable in the Kivy :mod:`~kivy.config`. You\ncan easily use many multitouch devices in one Kivy application.\n\nWhen the events have been read from the devices, they are dispatched through\na post processing module before being sent to your application. We also have\nseveral default modules for :\n\n* Double tap detection\n* Decreasing jittering\n* Decreasing the inaccuracy of touch on \"bad\" DIY hardware\n* Ignoring regions\n'''\n\n\nfrom kivy.input.motionevent import MotionEvent\nfrom kivy.input.postproc import kivy_postproc_modules\nfrom kivy.input.provider import MotionEventProvider\nfrom kivy.input.factory import MotionEventFactory\nimport kivy.input.providers\n\n__all__ = (\n    MotionEvent.__name__,\n    MotionEventProvider.__name__,\n    MotionEventFactory.__name__,\n    'kivy_postproc_modules')\n"
  },
  {
    "path": "tickeys/kivy/input/factory.py",
    "content": "'''\nMotion Event Factory\n====================\n\nFactory of :class:`~kivy.input.motionevent.MotionEvent` providers.\n'''\n\n__all__ = ('MotionEventFactory', )\n\n\nclass MotionEventFactory:\n    '''MotionEvent factory is a class that registers all availables input\n    factories. If you create a new input factory, you need to register\n    it here::\n\n        MotionEventFactory.register('myproviderid', MyInputProvider)\n\n    '''\n    __providers__ = {}\n\n    @staticmethod\n    def register(name, classname):\n        '''Register a input provider in the database'''\n        MotionEventFactory.__providers__[name] = classname\n\n    @staticmethod\n    def list():\n        '''Get a list of all available providers'''\n        return MotionEventFactory.__providers__\n\n    @staticmethod\n    def get(name):\n        '''Get a provider class from the provider id'''\n        if name in MotionEventFactory.__providers__:\n            return MotionEventFactory.__providers__[name]\n        return None\n"
  },
  {
    "path": "tickeys/kivy/input/motionevent.py",
    "content": "'''\n.. _motionevent:\n\nMotion Event\n============\n\nThe :class:`MotionEvent` is the base class used for every touch and non-touch\nevent. This class defines all the properties and methods needed to\nhandle 2D and 3D movements but has many more capabilities.\n\n.. note::\n\n    You never create the :class:`MotionEvent` yourself: this is the role of the\n    :mod:`~kivy.input.providers`.\n\nMotion Event and Touch\n----------------------\n\nWe differentiate between a Motion Event and Touch event. A Touch event is a\n:class:`MotionEvent` with the `pos` profile. Only these events are dispatched\nthroughout the widget tree.\n\n1. The :class:`MotionEvent` 's are gathered from input providers.\n2. All the :class:`MotionEvent` 's are dispatched from\n    :meth:`~kivy.core.window.WindowBase.on_motion`.\n3. If a :class:`MotionEvent` has a `pos` profile, we dispatch it through\n    :meth:`~kivy.core.window.WindowBase.on_touch_down`,\n    :meth:`~kivy.core.window.WindowBase.on_touch_move` and\n    :meth:`~kivy.core.window.WindowBase.on_touch_up`.\n\nListening to a Motion Event\n---------------------------\n\nIf you want to receive all MotionEvents, Touch or not, you can bind the\nMotionEvent from the :class:`~kivy.core.window.Window` to your own callback::\n\n    def on_motion(self, etype, motionevent):\n        # will receive all motion events.\n        pass\n\n    Window.bind(on_motion=on_motion)\n\nYou can also listen to changes of the mouse position by watching\n:attr:`~kivy.core.window.WindowBase.mouse_pos`.\n\nProfiles\n--------\n\nA capability is the ability of a :class:`MotionEvent` to store new\ninformation or a way to indicate what is supported by the MotionEvent.\nFor example, you can receive a MotionEvent that has an angle, a fiducial\nID, or even a shape. You can check the :attr:`~MotionEvent.profile`\nattribute to check what is currently supported by the MotionEvent and\nhow to access it.\n\nThis is a tiny list of the supported profiles by default. Check other input\nproviders to see if there are other profiles available.\n\n============== ================================================================\nProfile name   Description\n-------------- ----------------------------------------------------------------\nangle          2D angle. Use property `a`\nbutton         Mouse button (left, right, middle, scrollup, scrolldown)\n               Use property `button`\nmarkerid       Marker or Fiducial ID. Use property `fid`\npos            2D position. Use properties `x`, `y` or `pos``\npos3d          3D position. Use properties `x`, `y`, `z`\npressure       Pressure of the contact. Use property `pressure`\nshape          Contact shape. Use property `shape`\n============== ================================================================\n\nIf you want to know whether the current :class:`MotionEvent` has an angle::\n\n    def on_touch_move(self, touch):\n        if 'angle' in touch.profile:\n            print('The touch angle is', touch.a)\n\nIf you want to select only the fiducials::\n\n    def on_touch_move(self, touch):\n        if 'markerid' not in touch.profile:\n            return\n\n'''\n\n__all__ = ('MotionEvent', )\n\nimport weakref\nfrom inspect import isroutine\nfrom copy import copy\nfrom time import time\nfrom kivy.vector import Vector\n\n\nclass EnhancedDictionary(dict):\n\n    def __getattr__(self, attr):\n        try:\n            return self.__getitem__(attr)\n        except KeyError:\n            return super(EnhancedDictionary, self).__getattr__(attr)\n\n    def __setattr__(self, attr, value):\n        self.__setitem__(attr, value)\n\n\nclass MotionEventMetaclass(type):\n\n    def __new__(mcs, name, bases, attrs):\n        __attrs__ = []\n        for base in bases:\n            if hasattr(base, '__attrs__'):\n                __attrs__.extend(base.__attrs__)\n        if '__attrs__' in attrs:\n            __attrs__.extend(attrs['__attrs__'])\n        attrs['__attrs__'] = tuple(__attrs__)\n        return super(MotionEventMetaclass, mcs).__new__(mcs, name,\n                                                        bases, attrs)\n\n\nMotionEventBase = MotionEventMetaclass('MotionEvent', (object, ), {})\n\n\nclass MotionEvent(MotionEventBase):\n    '''Abstract class to represent a touch and non-touch object.\n\n    :Parameters:\n        `id` : str\n            unique ID of the MotionEvent\n        `args` : list\n            list of parameters, passed to the depack() function\n    '''\n\n    __uniq_id = 0\n    __attrs__ = \\\n        ('device', 'push_attrs', 'push_attrs_stack',\n         'is_touch', 'id', 'shape', 'profile',\n         # current position, in 0-1 range\n         'sx', 'sy', 'sz',\n         # first position set, in 0-1 range\n         'osx', 'osy', 'osz',\n         # last position set, in 0-1 range\n         'psx', 'psy', 'psz',\n         # delta from the last position and current one, in 0-1 range\n         'dsx', 'dsy', 'dsz',\n         # current position, in screen range\n         'x', 'y', 'z',\n         # first position set, in screen range\n         'ox', 'oy', 'oz',\n         # last position set, in 0-1 range\n         'px', 'py', 'pz',\n         # delta from the last position and current one, in screen range\n         'dx', 'dy', 'dz',\n         'time_start',\n         'is_double_tap', 'double_tap_time',\n         'is_triple_tap', 'triple_tap_time',\n         'ud')\n\n    def __init__(self, device, id, args):\n        if self.__class__ == MotionEvent:\n            raise NotImplementedError('class MotionEvent is abstract')\n        MotionEvent.__uniq_id += 1\n\n        #: True if the Motion Event is a Touch. Can be also verified is\n        #: `pos` is :attr:`profile`.\n        self.is_touch = False\n\n        #: Attributes to push by default, when we use :meth:`push` : x, y, z,\n        #: dx, dy, dz, ox, oy, oz, px, py, pz.\n        self.push_attrs_stack = []\n        self.push_attrs = ('x', 'y', 'z', 'dx', 'dy', 'dz', 'ox', 'oy', 'oz',\n                           'px', 'py', 'pz', 'pos')\n\n        #: Uniq ID of the touch. You can safely use this property, it will be\n        #: never the same accross all existing touches.\n        self.uid = MotionEvent.__uniq_id\n\n        #: Device used for creating this touch\n        self.device = device\n\n        # For grab\n        self.grab_list = []\n        self.grab_exclusive_class = None\n        self.grab_state = False\n\n        #: Used to determine which widget the touch is being dispatched to.\n        #: Check the :meth:`grab` function for more information.\n        self.grab_current = None\n\n        #: Profiles currently used in the touch\n        self.profile = []\n\n        #: Id of the touch, not uniq. This is generally the Id set by the input\n        #: provider, like ID in TUIO. If you have multiple TUIO source,\n        #: the same id can be used. Prefer to use :attr:`uid` attribute\n        #: instead.\n        self.id = id\n\n        #: Shape of the touch, subclass of\n        #: :class:`~kivy.input.shape.Shape`.\n        #: By default, the property is set to None\n        self.shape = None\n\n        #: X position, in 0-1 range\n        self.sx = 0.0\n        #: Y position, in 0-1 range\n        self.sy = 0.0\n        #: Z position, in 0-1 range\n        self.sz = 0.0\n        #: Origin X position, in 0-1 range.\n        self.osx = None\n        #: Origin Y position, in 0-1 range.\n        self.osy = None\n        #: Origin Z position, in 0-1 range.\n        self.osz = None\n        #: Previous X position, in 0-1 range.\n        self.psx = None\n        #: Previous Y position, in 0-1 range.\n        self.psy = None\n        #: Previous Z position, in 0-1 range.\n        self.psz = None\n        #: Delta between self.sx and self.psx, in 0-1 range.\n        self.dsx = None\n        #: Delta between self.sy and self.psy, in 0-1 range.\n        self.dsy = None\n        #: Delta between self.sz and self.psz, in 0-1 range.\n        self.dsz = None\n        #: X position, in window range\n        self.x = 0.0\n        #: Y position, in window range\n        self.y = 0.0\n        #: Z position, in window range\n        self.z = 0.0\n        #: Origin X position, in window range\n        self.ox = None\n        #: Origin Y position, in window range\n        self.oy = None\n        #: Origin Z position, in window range\n        self.oz = None\n        #: Previous X position, in window range\n        self.px = None\n        #: Previous Y position, in window range\n        self.py = None\n        #: Previous Z position, in window range\n        self.pz = None\n        #: Delta between self.x and self.px, in window range\n        self.dx = None\n        #: Delta between self.y and self.py, in window range\n        self.dy = None\n        #: Delta between self.z and self.pz, in window range\n        self.dz = None\n        #: Position (X, Y), in window range\n        self.pos = (0.0, 0.0)\n\n        #: Initial time of the touch creation\n        self.time_start = time()\n\n        #: Time of the last update\n        self.time_update = self.time_start\n\n        #: Time of the end event (last touch usage)\n        self.time_end = -1\n\n        #: Indicate if the touch is a double tap or not\n        self.is_double_tap = False\n\n        #: Indicate if the touch is a triple tap or not\n        #:\n        #: .. versionadded:: 1.7.0\n        self.is_triple_tap = False\n\n        #: If the touch is a :attr:`is_double_tap`, this is the time\n        #: between the previous tap and the current touch.\n        self.double_tap_time = 0\n\n        #: If the touch is a :attr:`is_triple_tap`, this is the time\n        #: between the first tap and the current touch.\n        #:\n        #: .. versionadded:: 1.7.0\n        self.triple_tap_time = 0\n\n        #: User data dictionary. Use this dictionary to save your own data on\n        #: the touch.\n        self.ud = EnhancedDictionary()\n\n        self.depack(args)\n\n    def depack(self, args):\n        '''Depack `args` into attributes of the class'''\n        # set initial position and last position\n        if self.osx is None:\n            self.psx = self.osx = self.sx\n            self.psy = self.osy = self.sy\n            self.psz = self.osz = self.sz\n        # update the delta\n        self.dsx = self.sx - self.psx\n        self.dsy = self.sy - self.psy\n        self.dsz = self.sz - self.psz\n\n    def grab(self, class_instance, exclusive=False):\n        '''Grab this motion event. You can grab a touch if you absolutly\n        want to receive on_touch_move() and on_touch_up(), even if the\n        touch is not dispatched by your parent::\n\n            def on_touch_down(self, touch):\n                touch.grab(self)\n\n            def on_touch_move(self, touch):\n                if touch.grab_current is self:\n                    # I received my grabbed touch\n                else:\n                    # it's a normal touch\n\n            def on_touch_up(self, touch):\n                if touch.grab_current is self:\n                    # I receive my grabbed touch, I must ungrab it!\n                    touch.ungrab(self)\n                else:\n                    # it's a normal touch\n                    pass\n        '''\n        if not self.is_touch:\n            raise Exception('Grab works only for Touch MotionEvents.')\n        if self.grab_exclusive_class is not None:\n            raise Exception('Cannot grab the touch, touch is exclusive')\n        class_instance = weakref.ref(class_instance.__self__)\n        if exclusive:\n            self.grab_exclusive_class = class_instance\n        self.grab_list.append(class_instance)\n\n    def ungrab(self, class_instance):\n        '''Ungrab a previously grabbed touch\n        '''\n        class_instance = weakref.ref(class_instance.__self__)\n        if self.grab_exclusive_class == class_instance:\n            self.grab_exclusive_class = None\n        if class_instance in self.grab_list:\n            self.grab_list.remove(class_instance)\n\n    def move(self, args):\n        '''Move the touch to another position\n        '''\n        self.px = self.x\n        self.py = self.y\n        self.pz = self.z\n        self.psx = self.sx\n        self.psy = self.sy\n        self.psz = self.sz\n        self.time_update = time()\n        self.depack(args)\n\n    def scale_for_screen(self, w, h, p=None, rotation=0,\n                         smode='None', kheight=0):\n        '''Scale position for the screen\n        '''\n        sx, sy = self.sx, self.sy\n        if rotation == 0:\n            self.x = sx * float(w)\n            self.y = sy * float(h)\n        elif rotation == 90:\n            sx, sy = sy, 1 - sx\n            self.x = sx * float(h)\n            self.y = sy * float(w)\n        elif rotation == 180:\n            sx, sy = 1 - sx, 1 - sy\n            self.x = sx * float(w)\n            self.y = sy * float(h)\n        elif rotation == 270:\n            sx, sy = 1 - sy, sx\n            self.x = sx * float(h)\n            self.y = sy * float(w)\n\n        if p:\n            self.z = self.sz * float(p)\n\n        if smode:\n            if smode == 'pan':\n                self.y -= kheight\n            elif smode == 'scale':\n                self.y += (kheight * (\n                    (self.y - kheight) / (h - kheight))) - kheight\n\n        if self.ox is None:\n            self.px = self.ox = self.x\n            self.py = self.oy = self.y\n            self.pz = self.oz = self.z\n\n        self.dx = self.x - self.px\n        self.dy = self.y - self.py\n        self.dz = self.z - self.pz\n\n        # cache position\n        self.pos = self.x, self.y\n\n    def push(self, attrs=None):\n        '''Push attribute values in `attrs` onto the stack\n        '''\n        if attrs is None:\n            attrs = self.push_attrs\n        values = [getattr(self, x) for x in attrs]\n        self.push_attrs_stack.append((attrs, values))\n\n    def pop(self):\n        '''Pop attributes values from the stack\n        '''\n        attrs, values = self.push_attrs_stack.pop()\n        for i in range(len(attrs)):\n            setattr(self, attrs[i], values[i])\n\n    def apply_transform_2d(self, transform):\n        '''Apply a transformation on x, y, z, px, py, pz,\n        ox, oy, oz, dx, dy, dz\n        '''\n        self.x, self.y = self.pos = transform(self.x, self.y)\n        self.px, self.py = transform(self.px, self.py)\n        self.ox, self.oy = transform(self.ox, self.oy)\n        self.dx = self.x - self.px\n        self.dy = self.y - self.py\n\n    def copy_to(self, to):\n        '''Copy some attribute to another touch object.'''\n        for attr in self.__attrs__:\n            to.__setattr__(attr, copy(self.__getattribute__(attr)))\n\n    def distance(self, other_touch):\n        '''Return the distance between the current touch and another touch.\n        '''\n        return Vector(self.pos).distance(other_touch.pos)\n\n    def update_time_end(self):\n        self.time_end = time()\n\n    # facilities\n    @property\n    def dpos(self):\n        '''Return delta between last position and current position, in the\n        screen coordinate system (self.dx, self.dy)'''\n        return self.dx, self.dy\n\n    @property\n    def opos(self):\n        '''Return the initial position of the touch in the screen\n        coordinate system (self.ox, self.oy)'''\n        return self.ox, self.oy\n\n    @property\n    def ppos(self):\n        '''Return the previous position of the touch in the screen\n        coordinate system (self.px, self.py)'''\n        return self.px, self.py\n\n    @property\n    def spos(self):\n        '''Return the position in the 0-1 coordinate system\n        (self.sx, self.sy)'''\n        return self.sx, self.sy\n\n    def __str__(self):\n        basename = str(self.__class__)\n        classname = basename.split('.')[-1].replace('>', '').replace('\\'', '')\n        return '<%s spos=%s pos=%s>' % (classname, self.spos, self.pos)\n\n    def __repr__(self):\n        out = []\n        for x in dir(self):\n            v = getattr(self, x)\n            if x[0] == '_':\n                continue\n            if isroutine(v):\n                continue\n            out.append('%s=\"%s\"' % (x, v))\n        return '<%s %s>' % (\n            self.__class__.__name__,\n            ' '.join(out))\n\n    @property\n    def is_mouse_scrolling(self, *args):\n        '''Returns True if the touch is a mousewheel scrolling\n\n        .. versionadded:: 1.6.0\n        '''\n        return 'button' in self.profile and 'scroll' in self.button\n"
  },
  {
    "path": "tickeys/kivy/input/postproc/__init__.py",
    "content": "'''\nInput Postprocessing\n====================\n\n'''\n\n__all__ = ('kivy_postproc_modules', )\n\nimport os\nfrom kivy.input.postproc.doubletap import InputPostprocDoubleTap\nfrom kivy.input.postproc.tripletap import InputPostprocTripleTap\nfrom kivy.input.postproc.ignorelist import InputPostprocIgnoreList\nfrom kivy.input.postproc.retaintouch import InputPostprocRetainTouch\nfrom kivy.input.postproc.dejitter import InputPostprocDejitter\nfrom kivy.input.postproc.calibration import InputPostprocCalibration\n\n# Mapping of ID to module\nkivy_postproc_modules = {}\n\n# Don't go further if we generate documentation\nif 'KIVY_DOC' not in os.environ:\n    kivy_postproc_modules['calibration'] = InputPostprocCalibration()\n    kivy_postproc_modules['retaintouch'] = InputPostprocRetainTouch()\n    kivy_postproc_modules['ignorelist'] = InputPostprocIgnoreList()\n    kivy_postproc_modules['doubletap'] = InputPostprocDoubleTap()\n    kivy_postproc_modules['tripletap'] = InputPostprocTripleTap()\n    kivy_postproc_modules['dejitter'] = InputPostprocDejitter()\n"
  },
  {
    "path": "tickeys/kivy/input/postproc/calibration.py",
    "content": "'''\nCalibration\n===========\n\n.. versionadded:: 1.9.0\n\nRecalibrate input device to a specific range / offset.\n\nLet's say you have 3 1080p displays, the 2 firsts are multitouch. By default,\nboth will have mixed touch, the range will conflict with each others: the 0-1\nrange will goes to 0-5760 px (remember, 3 * 1920 = 5760.)\n\nTo fix it, you need to manually reference them. For example::\n\n    [input]\n    left = mtdev,/dev/input/event17\n    middle = mtdev,/dev/input/event15\n    # the right screen is just a display.\n\nThen, you can use the calibration postproc module::\n\n    [postproc:calibration]\n    left = xratio=0.3333\n    middle = xratio=0.3333,xoffset=0.3333\n\nNow, the touches from the left screen will be within 0-0.3333 range, and the\ntouches from the middle screen will be within 0.3333-0.6666 range.\n\n'''\n\n__all__ = ('InputPostprocCalibration', )\n\nfrom kivy.config import Config\nfrom kivy.logger import Logger\n\n\nclass InputPostprocCalibration(object):\n    '''Recalibrate the inputs.\n\n    The configuration must go within a section named `postproc:calibration`.\n    Within the section, you must have line like::\n\n        devicename = param=value,param=value\n\n    :Parameters:\n        `xratio`: float\n            Value to multiply X\n        `yratio`: float\n            Value to multiply Y\n        `xoffset`: float\n            Value to add to X\n        `yoffset`: float\n            Value to add to Y\n\n    '''\n\n    def __init__(self):\n        super(InputPostprocCalibration, self).__init__()\n        self.devices = {}\n        self.frame = 0\n        if not Config.has_section('postproc:calibration'):\n            return\n        default_params = {'xoffset': 0, 'yoffset': 0, 'xratio': 1, 'yratio': 1}\n        for device_key, params_str in Config.items('postproc:calibration'):\n            params = default_params.copy()\n            for param in params_str.split(','):\n                param = param.strip()\n                if not param:\n                    continue\n                key, value = param.split('=', 1)\n                if key not in ('xoffset', 'yoffset', 'xratio', 'yratio'):\n                    Logger.error(\n                        'Calibration: invalid key provided: {}'.format(key))\n                params[key] = float(value)\n            self.devices[device_key] = params\n\n    def process(self, events):\n        # avoid doing any processing if there is no device to calibrate at all.\n        if not self.devices:\n            return events\n\n        self.frame += 1\n        frame = self.frame\n        for etype, event in events:\n            if event.device not in self.devices:\n                continue\n            # some providers use the same event to update and end\n            if 'calibration:frame' not in event.ud:\n                event.ud['calibration:frame'] = frame\n            elif event.ud['calibration:frame'] == frame:\n                continue\n            params = self.devices[event.device]\n            event.sx = event.sx * params['xratio'] + params['xoffset']\n            event.sy = event.sy * params['yratio'] + params['yoffset']\n            event.ud['calibration:frame'] = frame\n        return events\n\n"
  },
  {
    "path": "tickeys/kivy/input/postproc/dejitter.py",
    "content": "'''\nDejitter\n========\n\nPrevent blob jittering.\n\nA problem that is often faced (esp. in optical MT setups) is that of\njitterish BLOBs caused by bad camera characteristics. With this module\nyou can get rid of that jitter. You just define a threshold\n`jitter_distance` in your config, and all touch movements that move\nthe touch by less than the jitter distance are considered 'bad'\nmovements caused by jitter and will be discarded.\n'''\n\n__all__ = ('InputPostprocDejitter', )\n\nfrom kivy.config import Config\n\n\nclass InputPostprocDejitter(object):\n    '''\n    Get rid of jitterish BLOBs.\n    Example::\n\n        [postproc]\n        jitter_distance = 0.004\n        jitter_ignore_devices = mouse,mactouch\n\n    :Configuration:\n        `jitter_distance`: float\n            A float in range 0-1.\n        `jitter_ignore_devices`: string\n            A comma-seperated list of device identifiers that\n            should not be processed by dejitter (because they're\n            very precise already).\n    '''\n\n    def __init__(self):\n        self.jitterdist = Config.getfloat('postproc', 'jitter_distance')\n        ignore_devices = Config.get('postproc', 'jitter_ignore_devices')\n        self.ignore_devices = ignore_devices.split(',')\n        self.last_touches = {}\n\n    def taxicab_distance(self, p, q):\n        # Get the taxicab/manhattan/citiblock distance for efficiency reasons\n        return abs(p[0] - q[0]) + abs(p[1] - q[1])\n\n    def process(self, events):\n        if not self.jitterdist:\n            return events\n        processed = []\n        for etype, touch in events:\n            if not touch.is_touch:\n                continue\n            if touch.device in self.ignore_devices:\n                processed.append((etype, touch))\n                continue\n            if etype == 'begin':\n                self.last_touches[touch.id] = touch.spos\n            if etype == 'end':\n                del self.last_touches[touch.id]\n            if etype != 'update':\n                processed.append((etype, touch))\n                continue\n            # Check whether the touch moved more than the jitter distance\n            last_spos = self.last_touches[touch.id]\n            dist = self.taxicab_distance(last_spos, touch.spos)\n            if dist > self.jitterdist:\n                # Only if the touch has moved more than the jitter dist we take\n                # it into account and dispatch it. Otherwise suppress it.\n                self.last_touches[touch.id] = touch.spos\n                processed.append((etype, touch))\n        return processed\n"
  },
  {
    "path": "tickeys/kivy/input/postproc/doubletap.py",
    "content": "'''\nDouble Tap\n==========\n\nSearch touch for a double tap\n'''\n\n__all__ = ('InputPostprocDoubleTap', )\n\nfrom time import time\nfrom kivy.config import Config\nfrom kivy.vector import Vector\n\n\nclass InputPostprocDoubleTap(object):\n    '''\n    InputPostProcDoubleTap is a post-processor to check if\n    a touch is a double tap or not.\n    Double tap can be configured in the Kivy config file::\n\n        [postproc]\n        double_tap_time = 250\n        double_tap_distance = 20\n\n    Distance parameter is in the range 0-1000 and time is in milliseconds.\n    '''\n\n    def __init__(self):\n        dist = Config.getint('postproc', 'double_tap_distance')\n        self.double_tap_distance = dist / 1000.0\n        tap_time = Config.getint('postproc', 'double_tap_time')\n        self.double_tap_time = tap_time / 1000.0\n        self.touches = {}\n\n    def find_double_tap(self, ref):\n        '''Find a double tap touch within self.touches.\n        The touch must be not a previous double tap and the distance must be\n        within the specified threshold. Additionally, the touch profiles\n        must be the same kind of touch.\n        '''\n        ref_button = None\n        if 'button' in ref.profile:\n            ref_button = ref.button\n\n        for touchid in self.touches:\n            if ref.uid == touchid:\n                continue\n            etype, touch = self.touches[touchid]\n            if etype != 'end':\n                continue\n            if touch.is_double_tap:\n                continue\n            distance = Vector.distance(\n                Vector(ref.sx, ref.sy),\n                Vector(touch.osx, touch.osy))\n            if distance > self.double_tap_distance:\n                continue\n            if touch.is_mouse_scrolling or ref.is_mouse_scrolling:\n                continue\n            touch_button = None\n            if 'button' in touch.profile:\n                touch_button = touch.button\n            if touch_button != ref_button:\n                continue\n            touch.double_tap_distance = distance\n            return touch\n        return None\n\n    def process(self, events):\n        if self.double_tap_distance == 0 or self.double_tap_time == 0:\n            return events\n        # first, check if a touch down have a double tap\n        for etype, touch in events:\n            if not touch.is_touch:\n                continue\n            if etype == 'begin':\n                double_tap = self.find_double_tap(touch)\n                if double_tap:\n                    touch.is_double_tap = True\n                    tap_time = touch.time_start - double_tap.time_start\n                    touch.double_tap_time = tap_time\n                    distance = double_tap.double_tap_distance\n                    touch.double_tap_distance = distance\n\n            # add the touch internaly\n            self.touches[touch.uid] = (etype, touch)\n\n        # second, check if up-touch is timeout for double tap\n        time_current = time()\n        to_delete = []\n        for touchid in self.touches.keys():\n            etype, touch = self.touches[touchid]\n            if etype != 'end':\n                continue\n            if time_current - touch.time_start < self.double_tap_time:\n                continue\n            to_delete.append(touchid)\n\n        for touchid in to_delete:\n            del self.touches[touchid]\n\n        return events\n"
  },
  {
    "path": "tickeys/kivy/input/postproc/ignorelist.py",
    "content": "'''\nIgnore list\n===========\n\nIgnore touch on some areas of the screen\n'''\n\n__all__ = ('InputPostprocIgnoreList', )\n\nfrom kivy.config import Config\nfrom kivy.utils import strtotuple\n\n\nclass InputPostprocIgnoreList(object):\n    '''\n    InputPostprocIgnoreList is a post-processor which removes touches in the\n    Ignore list. The Ignore list can be configured in the Kivy config file::\n\n        [postproc]\n        # Format: [(xmin, ymin, xmax, ymax), ...]\n        ignore = [(0.1, 0.1, 0.15, 0.15)]\n\n    The Ignore list coordinates are in the range 0-1, not in screen pixels.\n    '''\n\n    def __init__(self):\n        self.ignore_list = strtotuple(Config.get('postproc', 'ignore'))\n\n    def collide_ignore(self, touch):\n        x, y = touch.sx, touch.sy\n        for l in self.ignore_list:\n            xmin, ymin, xmax, ymax = l\n            if x > xmin and x < xmax and y > ymin and y < ymax:\n                return True\n\n    def process(self, events):\n        if not len(self.ignore_list):\n            return events\n        for etype, touch in events:\n            if not touch.is_touch:\n                continue\n            if etype != 'begin':\n                continue\n            if self.collide_ignore(touch):\n                touch.ud.__pp_ignore__ = True\n        return [(etype, touch) for etype, touch in events\n                if not '__pp_ignore__' in touch.ud]\n"
  },
  {
    "path": "tickeys/kivy/input/postproc/retaintouch.py",
    "content": "'''\nRetain Touch\n============\n\nReuse touch to counter lost finger behavior\n'''\n\n__all__ = ('InputPostprocRetainTouch', )\n\nfrom kivy.config import Config\nfrom kivy.vector import Vector\nimport time\n\n\nclass InputPostprocRetainTouch(object):\n    '''\n    InputPostprocRetainTouch is a post-processor to delay the 'up' event of a\n    touch, to reuse it under certains conditions. This module is designed to\n    prevent lost finger touches on some hardware/setups.\n\n    Retain touch can be configured in the Kivy config file::\n\n        [postproc]\n            retain_time = 100\n            retain_distance = 50\n\n    The distance parameter is in the range 0-1000 and time is in milliseconds.\n    '''\n\n    def __init__(self):\n        self.timeout = Config.getint('postproc', 'retain_time') / 1000.0\n        self.distance = Config.getint('postproc', 'retain_distance') / 1000.0\n        self._available = []\n        self._links = {}\n\n    def process(self, events):\n        # check if module is disabled\n        if self.timeout == 0:\n            return events\n\n        d = time.time()\n        for etype, touch in events[:]:\n            if not touch.is_touch:\n                continue\n            if etype == 'end':\n                events.remove((etype, touch))\n                if touch.uid in self._links:\n                    selection = self._links[touch.uid]\n                    selection.ud.__pp_retain_time__ = d\n                    self._available.append(selection)\n                    del self._links[touch.uid]\n                else:\n                    touch.ud.__pp_retain_time__ = d\n                    self._available.append(touch)\n            elif etype == 'update':\n                if touch.uid in self._links:\n                    selection = self._links[touch.uid]\n                    selection.x = touch.x\n                    selection.y = touch.y\n                    selection.sx = touch.sx\n                    selection.sy = touch.sy\n                    events.remove((etype, touch))\n                    events.append((etype, selection))\n                else:\n                    pass\n            elif etype == 'begin':\n                # new touch, found the nearest one\n                selection = None\n                selection_distance = 99999\n                for touch2 in self._available:\n                    touch_distance = Vector(touch2.spos).distance(touch.spos)\n                    if touch_distance > self.distance:\n                        continue\n                    if touch2.__class__ != touch.__class__:\n                        continue\n                    if touch_distance < selection_distance:\n                        # eligible for continuation\n                        selection_distance = touch_distance\n                        selection = touch2\n                if selection is None:\n                    continue\n\n                self._links[touch.uid] = selection\n                self._available.remove(selection)\n                events.remove((etype, touch))\n\n        for touch in self._available[:]:\n            t = touch.ud.__pp_retain_time__\n            if d - t > self.timeout:\n                self._available.remove(touch)\n                events.append(('end', touch))\n\n        return events\n"
  },
  {
    "path": "tickeys/kivy/input/postproc/tripletap.py",
    "content": "'''\nTriple Tap\n==========\n\n.. versionadded:: 1.7.0\n\nSearch touch for a triple tap\n'''\n\n__all__ = ('InputPostprocTripleTap', )\n\nfrom time import time\nfrom kivy.config import Config\nfrom kivy.vector import Vector\nfrom kivy.clock import Clock\n\n\nclass InputPostprocTripleTap(object):\n    '''\n    InputPostProcTripleTap is a post-processor to check if\n    a touch is a triple tap or not.\n    Triple tap can be configured in the Kivy config file::\n\n        [postproc]\n        triple_tap_time = 250\n        triple_tap_distance = 20\n\n    The distance parameter is in the range 0-1000 and time is in milliseconds.\n    '''\n\n    def __init__(self):\n        dist = Config.getint('postproc', 'triple_tap_distance')\n        self.triple_tap_distance = dist / 1000.0\n        time = Config.getint('postproc', 'triple_tap_time')\n        self.triple_tap_time = time / 1000.0\n        self.touches = {}\n\n    def find_triple_tap(self, ref):\n        '''Find a triple tap touch within *self.touches*.\n        The touch must be not be a previous triple tap and the distance\n        must be be within the bounds specified. Additionally, the touch profile\n        must be the same kind of touch.\n        '''\n        ref_button = None\n        if 'button' in ref.profile:\n            ref_button = ref.button\n\n        for touchid in self.touches:\n            if ref.uid == touchid:\n                continue\n            etype, touch = self.touches[touchid]\n            if not touch.is_double_tap:\n                continue\n            if etype != 'end':\n                continue\n            if touch.is_triple_tap:\n                continue\n            distance = Vector.distance(\n                Vector(ref.sx, ref.sy),\n                Vector(touch.osx, touch.osy))\n            if distance > self.triple_tap_distance:\n                continue\n            if touch.is_mouse_scrolling or ref.is_mouse_scrolling:\n                continue\n            touch_button = None\n            if 'button' in touch.profile:\n                touch_button = touch.button\n            if touch_button != ref_button:\n                continue\n            touch.triple_tap_distance = distance\n            return touch\n        return None\n\n    def process(self, events):\n        if self.triple_tap_distance == 0 or self.triple_tap_time == 0:\n            return events\n        # first, check if a touch down have a triple tap\n        for etype, touch in events:\n            if not touch.is_touch:\n                continue\n            if etype == 'begin':\n                triple_tap = self.find_triple_tap(touch)\n                if triple_tap:\n                    touch.is_double_tap = False\n                    touch.is_triple_tap = True\n                    tap_time = touch.time_start - triple_tap.time_start\n                    touch.triple_tap_time = tap_time\n                    distance = triple_tap.triple_tap_distance\n                    touch.triple_tap_distance = distance\n\n            # add the touch internaly\n            self.touches[touch.uid] = (etype, touch)\n\n        # second, check if up-touch is timeout for triple tap\n        time_current = time()\n        to_delete = []\n        for touchid in self.touches.keys():\n            etype, touch = self.touches[touchid]\n            if etype != 'end':\n                continue\n            if time_current - touch.time_start < self.triple_tap_time:\n                continue\n            to_delete.append(touchid)\n\n        for touchid in to_delete:\n            del self.touches[touchid]\n\n        return events\n"
  },
  {
    "path": "tickeys/kivy/input/provider.py",
    "content": "'''\nMotion Event Provider\n=====================\n\nAbstract class for the implemention of a\n:class:`~kivy.input.motionevent.MotionEvent`\nprovider. The implementation must support the\n:meth:`~MotionEventProvider.start`, :meth:`~MotionEventProvider.stop` and\n:meth:`~MotionEventProvider.update` methods.\n'''\n\n__all__ = ('MotionEventProvider', )\n\n\nclass MotionEventProvider(object):\n    '''Base class for a provider.\n    '''\n\n    def __init__(self, device, args):\n        self.device = device\n        if self.__class__ == MotionEventProvider:\n            raise NotImplementedError('class MotionEventProvider is abstract')\n\n    def start(self):\n        '''Start the provider. This method is automatically called when the\n        application is started and if the configuration uses the current\n        provider.\n        '''\n        pass\n\n    def stop(self):\n        '''Stop the provider.\n        '''\n        pass\n\n    def update(self, dispatch_fn):\n        '''Update the provider and dispatch all the new touch events though the\n        `dispatch_fn` argument.\n        '''\n        pass\n"
  },
  {
    "path": "tickeys/kivy/input/providers/__init__.py",
    "content": "# pylint: disable=W0611\n'''\nProviders\n=========\n\n'''\n\nimport os\n\nfrom kivy.utils import platform as core_platform\nfrom kivy.logger import Logger\n\nimport kivy.input.providers.tuio\nimport kivy.input.providers.mouse\n\nplatform = core_platform\n\nif platform == 'win' or 'KIVY_DOC' in os.environ:\n    try:\n        import kivy.input.providers.wm_touch\n        import kivy.input.providers.wm_pen\n    except:\n        err = 'Input: WM_Touch/WM_Pen not supported by your version of Windows'\n        Logger.warning(err)\n\nif platform == 'macosx' or 'KIVY_DOC' in os.environ:\n    try:\n        import kivy.input.providers.mactouch\n    except:\n        err = 'Input: MacMultitouchSupport is not supported by your system'\n        Logger.exception(err)\n\nif platform == 'linux' or 'KIVY_DOC' in os.environ:\n    try:\n        import kivy.input.providers.probesysfs\n    except:\n        err = 'Input: ProbeSysfs is not supported by your version of linux'\n        Logger.exception(err)\n    try:\n        import kivy.input.providers.mtdev\n    except:\n        err = 'Input: MTDev is not supported by your version of linux'\n        Logger.exception(err)\n    try:\n        import kivy.input.providers.hidinput\n    except:\n        err = 'Input: HIDInput is not supported by your version of linux'\n        Logger.exception(err)\n    try:\n        import kivy.input.providers.linuxwacom\n    except:\n        err = 'Input: LinuxWacom is not supported by your version of linux'\n        Logger.exception(err)\n\nif platform == 'android' or 'KIVY_DOC' in os.environ:\n    try:\n        import kivy.input.providers.androidjoystick\n    except:\n        err = 'Input: AndroidJoystick is not supported by your version ' \\\n              'of linux'\n        Logger.exception(err)\n\ntry:\n    import kivy.input.providers.leapfinger  # NOQA\nexcept:\n    err = 'Input: LeapFinger is not available on your system'\n    Logger.exception(err)\n"
  },
  {
    "path": "tickeys/kivy/input/providers/androidjoystick.py",
    "content": "# pylint: disable=W0611\n'''\nAndroid Joystick Input Provider\n===============================\n\nThis module is based on the PyGame JoyStick Input Provider. For more\ninformation, please refer to\n`<http://www.pygame.org/docs/ref/joystick.html>`_\n\n\n'''\n__all__ = ('AndroidMotionEventProvider', )\n\nimport os\n\ntry:\n    import android  # NOQA\nexcept ImportError:\n    if 'KIVY_DOC' not in os.environ:\n        raise Exception('android lib not found.')\n\nfrom kivy.logger import Logger\nfrom kivy.input.provider import MotionEventProvider\nfrom kivy.input.factory import MotionEventFactory\nfrom kivy.input.shape import ShapeRect\nfrom kivy.input.motionevent import MotionEvent\nimport pygame.joystick\n\n\nclass AndroidMotionEvent(MotionEvent):\n\n    def depack(self, args):\n        self.is_touch = True\n        self.profile = ['pos', 'pressure', 'shape']\n        self.sx, self.sy, self.pressure, radius = args\n        self.shape = ShapeRect()\n        self.shape.width = radius\n        self.shape.height = radius\n        super(AndroidMotionEvent, self).depack(args)\n\n\nclass AndroidMotionEventProvider(MotionEventProvider):\n\n    def __init__(self, device, args):\n        super(AndroidMotionEventProvider, self).__init__(device, args)\n        self.joysticks = []\n        self.touches = {}\n        self.uid = 0\n        self.window = None\n\n    def create_joystick(self, index):\n        Logger.info('Android: create joystick <%d>' % index)\n        js = pygame.joystick.Joystick(index)\n        js.init()\n        if js.get_numbuttons() == 0:\n            Logger.info('Android: discard joystick <%d> cause no button' %\n                        index)\n            return\n        self.joysticks.append(js)\n\n    def start(self):\n        pygame.joystick.init()\n        Logger.info('Android: found %d joystick' % pygame.joystick.get_count())\n        for i in range(pygame.joystick.get_count()):\n            self.create_joystick(i)\n\n    def stop(self):\n        self.joysticks = []\n\n    def update(self, dispatch_fn):\n        if not self.window:\n            from kivy.core.window import Window\n            self.window = Window\n        w, h = self.window.system_size\n        touches = self.touches\n        for joy in self.joysticks:\n            jid = joy.get_id()\n            pressed = joy.get_button(0)\n            if pressed or jid in touches:\n                x = joy.get_axis(0) * 32768. / w\n                y = 1. - (joy.get_axis(1) * 32768. / h)\n\n                # python for android do * 1000.\n                pressure = joy.get_axis(2) / 1000.\n                radius = joy.get_axis(3) / 1000.\n\n                # new touche ?\n                if pressed and jid not in touches:\n                    self.uid += 1\n                    touch = AndroidMotionEvent(self.device, self.uid,\n                                            [x, y, pressure, radius])\n                    touches[jid] = touch\n                    dispatch_fn('begin', touch)\n                # update touch\n                elif pressed:\n                    touch = touches[jid]\n                    # avoid same touch position\n                    if (touch.sx == x and touch.sy == y\n                        and touch.pressure == pressure):\n                        continue\n                    touch.move([x, y, pressure, radius])\n                    dispatch_fn('update', touch)\n                # disapear\n                elif not pressed and jid in touches:\n                    touch = touches[jid]\n                    touch.move([x, y, pressure, radius])\n                    touch.update_time_end()\n                    dispatch_fn('end', touch)\n                    touches.pop(jid)\n\nMotionEventFactory.register('android', AndroidMotionEventProvider)\n"
  },
  {
    "path": "tickeys/kivy/input/providers/hidinput.py",
    "content": "# coding utf-8\n'''\nNative support for HID input from the linux kernel\n==================================================\n\nSupport starts from 2.6.32-ubuntu, or 2.6.34.\n\nTo configure HIDInput, add this to your configuration::\n\n    [input]\n    # devicename = hidinput,/dev/input/eventXX\n    # example with Stantum MTP4.3\" screen\n    stantum = hidinput,/dev/input/event2\n\n.. note::\n    You must have read access to the input event.\n\nYou can use a custom range for the X, Y and pressure values.\nFor some drivers, the range reported is invalid.\nTo fix that, you can add these options to the argument line:\n\n* invert_x : 1 to invert X axis\n* invert_y : 1 to invert Y axis\n* min_position_x : X minimum\n* max_position_x : X maximum\n* min_position_y : Y minimum\n* max_position_y : Y maximum\n* min_pressure : pressure minimum\n* max_pressure : pressure maximum\n* rotation : rotate the input coordinate (0, 90, 180, 270)\n\nFor example, on the Asus T101M, the touchscreen reports a range from 0-4095 for\nthe X and Y values, but the real values are in a range from 0-32768. To correct\nthis, you can add the following to the configuration::\n\n    [input]\n    t101m = hidinput,/dev/input/event7,max_position_x=32768,\\\nmax_position_y=32768\n\n.. versionadded:: 1.9.1\n\n    `rotation` configuration token added.\n\n'''\n\n__all__ = ('HIDInputMotionEventProvider', 'HIDMotionEvent')\n\nimport os\nfrom kivy.input.motionevent import MotionEvent\nfrom kivy.input.shape import ShapeRect\n# late imports\nWindow = None\nKeyboard = None\n\n\nclass HIDMotionEvent(MotionEvent):\n\n    def depack(self, args):\n        self.is_touch = True\n        self.sx = args['x']\n        self.sy = args['y']\n        self.profile = ['pos']\n        if 'size_w' in args and 'size_h' in args:\n            self.shape = ShapeRect()\n            self.shape.width = args['size_w']\n            self.shape.height = args['size_h']\n            self.profile.append('shape')\n        if 'pressure' in args:\n            self.pressure = args['pressure']\n            self.profile.append('pressure')\n        super(HIDMotionEvent, self).depack(args)\n\n    def __str__(self):\n        return '<HIDMotionEvent id=%d pos=(%f, %f) device=%s>' \\\n            % (self.id, self.sx, self.sy, self.device)\n\nif 'KIVY_DOC' in os.environ:\n    # documentation hack\n    HIDInputMotionEventProvider = None\n\nelse:\n    import threading\n    import collections\n    import struct\n    import fcntl\n    from kivy.input.provider import MotionEventProvider\n    from kivy.input.factory import MotionEventFactory\n    from kivy.logger import Logger\n\n    #\n    # This part is taken from linux-source-2.6.32/include/linux/input.h\n    #\n\n    # Event types\n    EV_SYN = 0x00\n    EV_KEY = 0x01\n    EV_REL = 0x02\n    EV_ABS = 0x03\n    EV_MSC = 0x04\n    EV_SW = 0x05\n    EV_LED = 0x11\n    EV_SND = 0x12\n    EV_REP = 0x14\n    EV_FF = 0x15\n    EV_PWR = 0x16\n    EV_FF_STATUS = 0x17\n    EV_MAX = 0x1f\n    EV_CNT = (EV_MAX + 1)\n\n    KEY_MAX = 0x2ff\n\n    # Synchronization events\n    SYN_REPORT = 0\n    SYN_CONFIG = 1\n    SYN_MT_REPORT = 2\n\n    # Misc events\n    MSC_SERIAL = 0x00\n    MSC_PULSELED = 0x01\n    MSC_GESTURE = 0x02\n    MSC_RAW = 0x03\n    MSC_SCAN = 0x04\n    MSC_MAX = 0x07\n    MSC_CNT = (MSC_MAX + 1)\n\n    ABS_X = 0x00\n    ABS_Y = 0x01\n    ABS_PRESSURE = 0x18\n    ABS_MT_TOUCH_MAJOR = 0x30  # Major axis of touching ellipse\n    ABS_MT_TOUCH_MINOR = 0x31  # Minor axis (omit if circular)\n    ABS_MT_WIDTH_MAJOR = 0x32  # Major axis of approaching ellipse\n    ABS_MT_WIDTH_MINOR = 0x33  # Minor axis (omit if circular)\n    ABS_MT_ORIENTATION = 0x34  # Ellipse orientation\n    ABS_MT_POSITION_X = 0x35   # Center X ellipse position\n    ABS_MT_POSITION_Y = 0x36   # Center Y ellipse position\n    ABS_MT_TOOL_TYPE = 0x37    # Type of touching device\n    ABS_MT_BLOB_ID = 0x38      # Group a set of packets as a blob\n    ABS_MT_TRACKING_ID = 0x39  # Unique ID of initiated contact\n    ABS_MT_PRESSURE = 0x3a     # Pressure on contact area\n\n    # some ioctl base (with 0 value)\n    EVIOCGNAME = 2147501318\n    EVIOCGBIT = 2147501344\n    EVIOCGABS = 2149074240\n\n    keyboard_keys = {\n        0x29: ('`', '~'),\n        0x02: ('1', '!'),\n        0x03: ('2', '@'),\n        0x04: ('3', '#'),\n        0x05: ('4', '$'),\n        0x06: ('5', '%'),\n        0x07: ('6', '^'),\n        0x08: ('7', '&'),\n        0x09: ('8', '*'),\n        0x0a: ('9', '('),\n        0x0b: ('0', ')'),\n        0x0c: ('-', '_'),\n        0x0d: ('=', '+'),\n        0x0e: ('backspace', ),\n        0x0f: ('tab', ),\n        0x10: ('q', 'Q'),\n        0x11: ('w', 'W'),\n        0x12: ('e', 'E'),\n        0x13: ('r', 'R'),\n        0x14: ('t', 'T'),\n        0x15: ('y', 'Y'),\n        0x16: ('u', 'U'),\n        0x17: ('i', 'I'),\n        0x18: ('o', 'O'),\n        0x19: ('p', 'P'),\n        0x1a: ('[', '{'),\n        0x1b: (']', '}'),\n        0x2b: ('\\\\', '|'),\n        0x3a: ('capslock', ),\n        0x1e: ('a', 'A'),\n        0x1f: ('s', 'S'),\n        0x20: ('d', 'D'),\n        0x21: ('f', 'F'),\n        0x22: ('g', 'G'),\n        0x23: ('h', 'H'),\n        0x24: ('j', 'J'),\n        0x25: ('k', 'K'),\n        0x26: ('l', 'L'),\n        0x27: (';', ':'),\n        0x28: (\"'\", '\"'),\n        0xff: ('non-US-1', ),\n        0x1c: ('enter', ),\n        0x2a: ('shift', ),\n        0x2c: ('z', 'Z'),\n        0x2d: ('x', 'X'),\n        0x2e: ('c', 'C'),\n        0x2f: ('v', 'V'),\n        0x30: ('b', 'B'),\n        0x31: ('n', 'N'),\n        0x32: ('m', 'M'),\n        0x33: (',', '<'),\n        0x34: ('.', '>'),\n        0x35: ('/', '?'),\n        0x36: ('shift', ),\n        0x56: ('pipe', ),\n        0x1d: ('ctrl', ),\n        0x7D: ('super', ),\n        0x38: ('alt', ),\n        0x39: ('spacebar', ),\n        0x64: ('alt-gr', ),\n        0x7e: ('super', ),\n        0x7f: ('compose', ),\n        0x61: ('ctrl', ),\n        0x45: ('numlock', ),\n        0x47: ('numpad7', 'home'),\n        0x4b: ('numpad4', 'left'),\n        0x4f: ('numpad1', 'end'),\n        0x48: ('numpad8', 'up'),\n        0x4c: ('numpad5', ),\n        0x50: ('numpad2', 'down'),\n        0x52: ('numpad0', 'insert'),\n        0x37: ('numpadmul', ),\n        0x62: ('numpaddivide', ),\n        0x49: ('numpad9', 'pageup'),\n        0x4d: ('numpad6', 'right'),\n        0x51: ('numpad3', 'pagedown'),\n        0x53: ('numpaddecimal', 'delete'),\n        0x4a: ('numpadsubstract', ),\n        0x4e: ('numpadadd', ),\n        0x60: ('numpadenter', ),\n        0x01: ('escape', ),\n        0x3b: ('f1', ),\n        0x3c: ('f2', ),\n        0x3d: ('f3', ),\n        0x3e: ('f4', ),\n        0x3f: ('f5', ),\n        0x40: ('f6', ),\n        0x41: ('f7', ),\n        0x42: ('f8', ),\n        0x43: ('f9', ),\n        0x44: ('f10', ),\n        0x57: ('f11', ),\n        0x58: ('f12', ),\n        0x54: ('Alt+SysRq', ),\n        0x46: ('Screenlock', ),\n        0x67: ('up', ),\n        0x6c: ('down', ),\n        0x69: ('left', ),\n        0x6a: ('right', ),\n        0x6e: ('insert', ),\n        0x6f: ('delete', ),\n        0x66: ('home', ),\n        0x6b: ('end', ),\n        0x68: ('pageup', ),\n        0x6d: ('pagedown', ),\n        0x63: ('print', ),\n        0x77: ('pause', ),\n\n\n        # TODO combinations\n        # e0-37    PrtScr\n        # e0-46    Ctrl+Break\n        # e0-5b    LWin (USB: LGUI)\n        # e0-5c    RWin (USB: RGUI)\n        # e0-5d    Menu\n        # e0-5f    Sleep\n        # e0-5e    Power\n        # e0-63    Wake\n        # e0-38    RAlt\n        # e0-1d    RCtrl\n        # e0-52    Insert\n        # e0-53    Delete\n        # e0-47    Home\n        # e0-4f    End\n        # e0-49    PgUp\n        # e0-51    PgDn\n        # e0-4b    Left\n        # e0-48    Up\n        # e0-50    Down\n        # e0-4d    Right\n        # e0-35    KP-/\n        # e0-1c    KP-Enter\n        # e1-1d-45 77      Pause\n    }\n\n    keys_str = {\n        'spacebar': ' ',\n        'tab': '\t',\n        'shift': '',\n        'alt': '',\n        'ctrl': '',\n        'escape': '',\n        'numpad1': '1',\n        'numpad2': '2',\n        'numpad3': '3',\n        'numpad4': '4',\n        'numpad5': '5',\n        'numpad6': '6',\n        'numpad7': '7',\n        'numpad8': '8',\n        'numpad9': '9',\n        'numpad0': '0',\n        'numpadmul': '*',\n        'numpaddivide': '/',\n        'numpadadd': '+',\n        'numpadsubstract': '-',\n    }\n\n    # sizeof(struct input_event)\n    struct_input_event_sz = struct.calcsize('LLHHi')\n    struct_input_absinfo_sz = struct.calcsize('iiiiii')\n    sz_l = struct.calcsize('Q')\n\n    class HIDInputMotionEventProvider(MotionEventProvider):\n\n        options = ('min_position_x', 'max_position_x',\n                   'min_position_y', 'max_position_y',\n                   'min_pressure', 'max_pressure',\n                   'invert_x', 'invert_y', 'rotation')\n\n        def __init__(self, device, args):\n            super(HIDInputMotionEventProvider, self).__init__(device, args)\n            global Window, Keyboard\n\n            if Window is None:\n                from kivy.core.window import Window\n            if Keyboard is None:\n                from kivy.core.window import Keyboard\n\n            self.input_fn = None\n            self.default_ranges = dict()\n\n            # split arguments\n            args = args.split(',')\n            if not args:\n                Logger.error('HIDInput: Filename missing in configuration')\n                Logger.error('HIDInput: Use /dev/input/event0 for example')\n                return None\n\n            # read filename\n            self.input_fn = args[0]\n            Logger.info('HIDInput: Read event from <%s>' % self.input_fn)\n\n            # read parameters\n            for arg in args[1:]:\n                if arg == '':\n                    continue\n                arg = arg.split('=')\n\n                # ensure it's a key = value\n                if len(arg) != 2:\n                    Logger.error('HIDInput: invalid parameter '\n                                 '%s, not in key=value format.' % arg)\n                    continue\n\n                # ensure the key exist\n                key, value = arg\n                if key not in HIDInputMotionEventProvider.options:\n                    Logger.error('HIDInput: unknown %s option' % key)\n                    continue\n\n                # ensure the value\n                try:\n                    self.default_ranges[key] = int(value)\n                except ValueError:\n                    err = 'HIDInput: invalid value \"%s\" for \"%s\"' % (\n                        key, value)\n                    Logger.error(err)\n                    continue\n\n                # all good!\n                Logger.info('HIDInput: Set custom %s to %d' % (\n                    key, int(value)))\n\n            if 'rotation' not in self.default_ranges:\n                self.default_ranges['rotation'] = 0\n            elif self.default_ranges['rotation'] not in (0, 90, 180, 270):\n                Logger.error('HIDInput: invalid rotation value ({})'.format(\n                    self.default_ranges['rotation']))\n                self.default_ranges['rotation'] = 0\n\n        def start(self):\n            if self.input_fn is None:\n                return\n            self.uid = 0\n            self.queue = collections.deque()\n            self.thread = threading.Thread(\n                target=self._thread_run,\n                kwargs=dict(\n                    queue=self.queue,\n                    input_fn=self.input_fn,\n                    device=self.device,\n                    default_ranges=self.default_ranges))\n            self.thread.daemon = True\n            self.thread.start()\n\n        def _thread_run(self, **kwargs):\n            input_fn = kwargs.get('input_fn')\n            queue = kwargs.get('queue')\n            device = kwargs.get('device')\n            drs = kwargs.get('default_ranges').get\n            touches = {}\n            touches_sent = []\n            point = {}\n            l_points = []\n\n            # prepare some vars to get limit of some component\n            range_min_position_x = 0\n            range_max_position_x = 2048\n            range_min_position_y = 0\n            range_max_position_y = 2048\n            range_min_pressure = 0\n            range_max_pressure = 255\n            range_min_abs_x = 0\n            range_max_abs_x = 255\n            range_min_abs_y = 0\n            range_max_abs_y = 255\n            range_min_abs_pressure = 0\n            range_max_abs_pressure = 255\n            invert_x = int(bool(drs('invert_x', 0)))\n            invert_y = int(bool(drs('invert_y', 1)))\n            rotation = drs('rotation', 0)\n\n            def assign_coord(point, value, invert, coords):\n                cx, cy = coords\n                if invert:\n                    value = 1. - value\n                if rotation == 0:\n                    point[cx] = value\n                elif rotation == 90:\n                    point[cy] = value\n                elif rotation == 180:\n                    point[cx] = 1. - value\n                elif rotation == 270:\n                    point[cy] = 1. - value\n\n            def assign_rel_coord(point, value, invert, coords):\n                cx, cy = coords\n                if invert:\n                    value = -1 * value\n                if rotation == 0:\n                    point[cx] += value\n                elif rotation == 90:\n                    point[cy] += value\n                elif rotation == 180:\n                    point[cx] += -value\n                elif rotation == 270:\n                    point[cy] += -value\n\n            def process_as_multitouch(tv_sec, tv_usec, ev_type,\n                                      ev_code, ev_value):\n                # sync event\n                if ev_type == EV_SYN:\n                    if ev_code == SYN_MT_REPORT:\n                        if 'id' not in point:\n                            return\n                        l_points.append(point.copy())\n                    elif ev_code == SYN_REPORT:\n                        process(l_points)\n                        del l_points[:]\n\n                elif ev_type == EV_MSC and ev_code in (MSC_RAW, MSC_SCAN):\n                    pass\n\n                else:\n                    # compute multitouch track\n                    if ev_code == ABS_MT_TRACKING_ID:\n                        point.clear()\n                        point['id'] = ev_value\n                    elif ev_code == ABS_MT_POSITION_X:\n                        val = normalize(ev_value,\n                                        range_min_position_x,\n                                        range_max_position_x)\n                        assign_coord(point, val, invert_x, 'xy')\n                    elif ev_code == ABS_MT_POSITION_Y:\n                        val = 1. - normalize(ev_value,\n                                             range_min_position_y,\n                                             range_max_position_y)\n                        assign_coord(point, val, invert_y, 'yx')\n                    elif ev_code == ABS_MT_ORIENTATION:\n                        point['orientation'] = ev_value\n                    elif ev_code == ABS_MT_BLOB_ID:\n                        point['blobid'] = ev_value\n                    elif ev_code == ABS_MT_PRESSURE:\n                        point['pressure'] = normalize(ev_value,\n                                                      range_min_pressure,\n                                                      range_max_pressure)\n                    elif ev_code == ABS_MT_TOUCH_MAJOR:\n                        point['size_w'] = ev_value\n                    elif ev_code == ABS_MT_TOUCH_MINOR:\n                        point['size_h'] = ev_value\n\n            def process_as_mouse_or_keyboard(\n                tv_sec, tv_usec, ev_type, ev_code, ev_value):\n\n                if ev_type == EV_SYN:\n                    if ev_code == SYN_REPORT:\n                        process([point])\n                elif ev_type == EV_REL:\n                    if ev_code == 0:\n                        assign_rel_coord(point,\n                            min(1., max(-1., ev_value / 1000.)),\n                            invert_x, 'xy')\n                    elif ev_code == 1:\n                        assign_rel_coord(point,\n                            min(1., max(-1., ev_value / 1000.)),\n                            invert_y, 'yx')\n                elif ev_code == ABS_X:\n                    val = normalize(ev_value,\n                                    range_min_abs_x,\n                                    range_max_abs_x)\n                    assign_coord(point, val, invert_x, 'xy')\n                elif ev_code == ABS_Y:\n                    val = 1. - normalize(ev_value,\n                                         range_min_abs_y,\n                                         range_max_abs_y)\n                    assign_coord(point, val, invert_y, 'yx')\n                elif ev_code == ABS_PRESSURE:\n                    point['pressure'] = normalize(ev_value,\n                                                  range_min_abs_pressure,\n                                                  range_max_abs_pressure)\n                elif ev_type == EV_KEY:\n                    buttons = {\n                        272: 'left',\n                        273: 'right',\n                        274: 'middle',\n                        275: 'side',\n                        276: 'extra',\n                        277: 'forward',\n                        278: 'back',\n                        279: 'task',\n                        330: 'touch',\n                        320: 'pen'}\n\n                    if ev_code in buttons.keys():\n                        if ev_value:\n                            if 'button' not in point:\n                                point['button'] = buttons[ev_code]\n                                point['id'] += 1\n                                if '_avoid' in point:\n                                    del point['_avoid']\n                        elif 'button' in point:\n                            if point['button'] == buttons[ev_code]:\n                                del point['button']\n                                point['id'] += 1\n                                point['_avoid'] = True\n                    else:\n                        if ev_value == 1:\n                            l = keyboard_keys[ev_code][-1\n                                if 'shift' in Window._modifiers else 0]\n                            if l == 'shift' or l == 'alt':\n                                Window._modifiers.append(l)\n                            Window.dispatch(\n                                'on_key_down',\n                                Keyboard.keycodes[l.lower()],\n                                ev_code, keys_str.get(l, l),\n                                Window._modifiers)\n                        if ev_value == 0:\n                            l = keyboard_keys[ev_code][-1\n                                if 'shift' in Window._modifiers else 0]\n                            Window.dispatch(\n                                'on_key_up',\n                                Keyboard.keycodes[l.lower()],\n                                ev_code,\n                                keys_str.get(l, l),\n                                Window._modifiers)\n                            if l == 'shift':\n                                Window._modifiers.remove('shift')\n                        # if ev_value == 2:\n                        #     Window.dispatch('on_key_down', ev_code)\n\n            def process(points):\n                if not is_multitouch:\n                    Window.mouse_pos = (\n                        points[0]['x'] * Window.width,\n                        points[0]['y'] * Window.height)\n\n                actives = [args['id']\n                           for args in points\n                           if 'id' in args and not '_avoid' in args]\n                for args in points:\n                    tid = args['id']\n                    try:\n                        touch = touches[tid]\n                        if touch.sx == args['x'] and touch.sy == args['y']:\n                            continue\n                        touch.move(args)\n                        if tid not in touches_sent:\n                            queue.append(('begin', touch))\n                            touches_sent.append(tid)\n                        queue.append(('update', touch))\n                    except KeyError:\n                        if '_avoid' not in args:\n                            touch = HIDMotionEvent(device, tid, args)\n                            touches[touch.id] = touch\n                            if tid not in touches_sent:\n                                queue.append(('begin', touch))\n                                touches_sent.append(tid)\n\n                for tid in list(touches.keys())[:]:\n                    if tid not in actives:\n                        touch = touches[tid]\n                        if tid in touches_sent:\n                            touch.update_time_end()\n                            queue.append(('end', touch))\n                            touches_sent.remove(tid)\n                        del touches[tid]\n\n            def normalize(value, vmin, vmax):\n                return (value - vmin) / float(vmax - vmin)\n\n            # open the input\n            fd = open(input_fn, 'rb')\n\n            # get the controler name (EVIOCGNAME)\n            device_name = str(fcntl.ioctl(fd, EVIOCGNAME + (256 << 16),\n                                      \" \" * 256)).split('\\x00')[0]\n            Logger.info('HIDMotionEvent: using <%s>' % device_name)\n\n            # get abs infos\n            bit = fcntl.ioctl(fd, EVIOCGBIT + (EV_MAX << 16), ' ' * sz_l)\n            bit, = struct.unpack('Q', bit)\n            is_multitouch = False\n            for x in range(EV_MAX):\n                # preserve this, we may want other things than EV_ABS\n                if x != EV_ABS:\n                    continue\n                # EV_ABS available for this device ?\n                if (bit & (1 << x)) == 0:\n                    continue\n                # ask abs info keys to the devices\n                sbit = fcntl.ioctl(fd, EVIOCGBIT + x + (KEY_MAX << 16),\n                                   ' ' * sz_l)\n                sbit, = struct.unpack('Q', sbit)\n                for y in range(KEY_MAX):\n                    if (sbit & (1 << y)) == 0:\n                        continue\n                    absinfo = fcntl.ioctl(fd, EVIOCGABS + y +\n                                          (struct_input_absinfo_sz << 16),\n                                          ' ' * struct_input_absinfo_sz)\n                    abs_value, abs_min, abs_max, abs_fuzz, \\\n                        abs_flat, abs_res = struct.unpack('iiiiii', absinfo)\n                    if y == ABS_MT_POSITION_X:\n                        is_multitouch = True\n                        range_min_position_x = drs('min_position_x', abs_min)\n                        range_max_position_x = drs('max_position_x', abs_max)\n                        Logger.info('HIDMotionEvent: ' +\n                                    '<%s> range position X is %d - %d' % (\n                                        device_name, abs_min, abs_max))\n                    elif y == ABS_MT_POSITION_Y:\n                        is_multitouch = True\n                        range_min_position_y = drs('min_position_y', abs_min)\n                        range_max_position_y = drs('max_position_y', abs_max)\n                        Logger.info('HIDMotionEvent: ' +\n                                    '<%s> range position Y is %d - %d' % (\n                                        device_name, abs_min, abs_max))\n                    elif y == ABS_MT_PRESSURE:\n                        range_min_pressure = drs('min_pressure', abs_min)\n                        range_max_pressure = drs('max_pressure', abs_max)\n                        Logger.info('HIDMotionEvent: ' +\n                                    '<%s> range pressure is %d - %d' % (\n                                        device_name, abs_min, abs_max))\n                    elif y == ABS_X:\n                        range_min_abs_x = drs('min_abs_x', abs_min)\n                        range_max_abs_x = drs('max_abs_x', abs_max)\n                        Logger.info('HIDMotionEvent: ' +\n                                    '<%s> range ABS X position is %d - %d' % (\n                                        device_name, abs_min, abs_max))\n                    elif y == ABS_Y:\n                        range_min_abs_y = drs('min_abs_y', abs_min)\n                        range_max_abs_y = drs('max_abs_y', abs_max)\n                        Logger.info('HIDMotionEvent: ' +\n                                    '<%s> range ABS Y position is %d - %d' % (\n                                        device_name, abs_min, abs_max))\n                    elif y == ABS_PRESSURE:\n                        range_min_abs_pressure = drs(\n                            'min_abs_pressure', abs_min)\n                        range_max_abs_pressure = drs(\n                            'max_abs_pressure', abs_max)\n                        Logger.info('HIDMotionEvent: ' +\n                                    '<%s> range ABS pressure is %d - %d' % (\n                                        device_name, abs_min, abs_max))\n\n            # init the point\n            if not is_multitouch:\n                point = {'x': .5, 'y': .5, 'id': 0, '_avoid': True}\n\n            # read until the end\n            while fd:\n\n                data = fd.read(struct_input_event_sz)\n                if len(data) < struct_input_event_sz:\n                    break\n\n                # extract each event\n                for i in range(int(len(data) / struct_input_event_sz)):\n                    ev = data[i * struct_input_event_sz:]\n\n                    # extract timeval + event infos\n                    infos = struct.unpack('LLHHi', ev[:struct_input_event_sz])\n\n                    if is_multitouch:\n                        process_as_multitouch(*infos)\n                    else:\n                        process_as_mouse_or_keyboard(*infos)\n\n        def update(self, dispatch_fn):\n            # dispatch all event from threads\n            try:\n                while True:\n                    event_type, touch = self.queue.popleft()\n                    dispatch_fn(event_type, touch)\n            except:\n                pass\n\n    MotionEventFactory.register('hidinput', HIDInputMotionEventProvider)\n\n"
  },
  {
    "path": "tickeys/kivy/input/providers/leapfinger.py",
    "content": "'''\nLeap Motion - finger only\n=========================\n'''\n\n__all__ = ('LeapFingerEventProvider', 'LeapFingerEvent')\n\nimport os\nfrom collections import deque\nfrom kivy.logger import Logger\nfrom kivy.input.provider import MotionEventProvider\nfrom kivy.input.factory import MotionEventFactory\nfrom kivy.input.motionevent import MotionEvent\n\n_LEAP_QUEUE = deque()\n\nLeap = InteractionBox = None\n\n\ndef normalize(value, a, b):\n    return (value - a) / float(b - a)\n\n\nclass LeapFingerEvent(MotionEvent):\n\n    def depack(self, args):\n        super(LeapFingerEvent, self).depack(args)\n        if args[0] is None:\n            return\n        self.profile = ('pos', 'pos3d', )\n        x, y, z = args\n        self.sx = normalize(x, -150, 150)\n        self.sy = normalize(y, 40, 460)\n        self.sz = normalize(z, -350, 350)\n        self.z = z\n        self.is_touch = True\n\n\nclass LeapFingerEventProvider(MotionEventProvider):\n\n    __handlers__ = {}\n\n    def start(self):\n        # don't do the import at start, or teh error will be always displayed\n        # for user who don't have Leap\n        global Leap, InteractionBox\n        import Leap\n        from Leap import InteractionBox\n\n        class LeapMotionListener(Leap.Listener):\n\n            def on_init(self, controller):\n                Logger.info('leapmotion: Initialized')\n\n            def on_connect(self, controller):\n                Logger.info('leapmotion: Connected')\n\n            def on_disconnect(self, controller):\n                Logger.info('leapmotion: Disconnected')\n\n            def on_frame(self, controller):\n                frame = controller.frame()\n                _LEAP_QUEUE.append(frame)\n\n            def on_exit(self, controller):\n                pass\n\n        self.uid = 0\n        self.touches = {}\n        self.listener = LeapMotionListener()\n        self.controller = Leap.Controller(self.listener)\n\n    def update(self, dispatch_fn):\n        try:\n            while True:\n                frame = _LEAP_QUEUE.popleft()\n                events = self.process_frame(frame)\n                for ev in events:\n                    dispatch_fn(*ev)\n        except IndexError:\n            pass\n\n    def process_frame(self, frame):\n        events = []\n        touches = self.touches\n        available_uid = []\n        for hand in frame.hands:\n            for finger in hand.fingers:\n                #print hand.id(), finger.id(), finger.tip()\n                uid = '{0}:{1}'.format(hand.id, finger.id)\n                available_uid.append(uid)\n                position = finger.tip_position\n                args = (position.x, position.y, position.z)\n                if uid not in touches:\n                    touch = LeapFingerEvent(self.device, uid, args)\n                    events.append(('begin', touch))\n                    touches[uid] = touch\n                else:\n                    touch = touches[uid]\n                    touch.move(args)\n                    events.append(('update', touch))\n        for key in touches.keys()[:]:\n            if key not in available_uid:\n                events.append(('end', touches[key]))\n                del touches[key]\n        return events\n\n\n# registers\nMotionEventFactory.register('leapfinger', LeapFingerEventProvider)\n"
  },
  {
    "path": "tickeys/kivy/input/providers/linuxwacom.py",
    "content": "'''\nNative support of Wacom tablet from linuxwacom driver\n=====================================================\n\nTo configure LinuxWacom, add this to your configuration::\n\n    [input]\n    pen = linuxwacom,/dev/input/event2,mode=pen\n    finger = linuxwacom,/dev/input/event3,mode=touch\n\n.. note::\n    You must have read access to the input event.\n\nYou can use a custom range for the X, Y and pressure values.\nOn some drivers, the range reported is invalid.\nTo fix that, you can add these options to the argument line:\n\n* invert_x : 1 to invert X axis\n* invert_y : 1 to invert Y axis\n* min_position_x : X minimum\n* max_position_x : X maximum\n* min_position_y : Y minimum\n* max_position_y : Y maximum\n* min_pressure : pressure minimum\n* max_pressure : pressure maximum\n'''\n\n__all__ = ('LinuxWacomMotionEventProvider', 'LinuxWacomMotionEvent')\n\nimport os\nfrom kivy.input.motionevent import MotionEvent\nfrom kivy.input.shape import ShapeRect\n\n\nclass LinuxWacomMotionEvent(MotionEvent):\n\n    def depack(self, args):\n        self.is_touch = True\n        self.sx = args['x']\n        self.sy = args['y']\n        self.profile = ['pos']\n        if 'size_w' in args and 'size_h' in args:\n            self.shape = ShapeRect()\n            self.shape.width = args['size_w']\n            self.shape.height = args['size_h']\n            self.profile.append('shape')\n        if 'pressure' in args:\n            self.pressure = args['pressure']\n            self.profile.append('pressure')\n        super(LinuxWacomMotionEvent, self).depack(args)\n\n    def __str__(self):\n        return '<LinuxWacomMotionEvent id=%d pos=(%f, %f) device=%s>' \\\n            % (self.id, self.sx, self.sy, self.device)\n\nif 'KIVY_DOC' in os.environ:\n    # documentation hack\n    LinuxWacomMotionEventProvider = None\n\nelse:\n    import threading\n    import collections\n    import struct\n    import fcntl\n    from kivy.input.provider import MotionEventProvider\n    from kivy.input.factory import MotionEventFactory\n    from kivy.logger import Logger\n\n    #\n    # This part is taken from linux-source-2.6.32/include/linux/input.h\n    #\n\n    # Event types\n    EV_SYN = 0x00\n    EV_KEY = 0x01\n    EV_REL = 0x02\n    EV_ABS = 0x03\n    EV_MSC = 0x04\n    EV_SW = 0x05\n    EV_LED = 0x11\n    EV_SND = 0x12\n    EV_REP = 0x14\n    EV_FF = 0x15\n    EV_PWR = 0x16\n    EV_FF_STATUS = 0x17\n    EV_MAX = 0x1f\n    EV_CNT = (EV_MAX + 1)\n\n    KEY_MAX = 0x2ff\n\n    # Synchronization events\n    SYN_REPORT = 0\n    SYN_CONFIG = 1\n    SYN_MT_REPORT = 2\n\n    # Misc events\n    MSC_SERIAL = 0x00\n    MSC_PULSELED = 0x01\n    MSC_GESTURE = 0x02\n    MSC_RAW = 0x03\n    MSC_SCAN = 0x04\n    MSC_MAX = 0x07\n    MSC_CNT = (MSC_MAX + 1)\n\n    ABS_X = 0x00\n    ABS_Y = 0x01\n    ABS_PRESSURE = 0x18\n    ABS_MISC = 0x28  # if 0, it's touch up\n    ABS_MT_TOUCH_MAJOR = 0x30  # Major axis of touching ellipse\n    ABS_MT_TOUCH_MINOR = 0x31  # Minor axis (omit if circular)\n    ABS_MT_WIDTH_MAJOR = 0x32  # Major axis of approaching ellipse\n    ABS_MT_WIDTH_MINOR = 0x33  # Minor axis (omit if circular)\n    ABS_MT_ORIENTATION = 0x34  # Ellipse orientation\n    ABS_MT_POSITION_X = 0x35   # Center X ellipse position\n    ABS_MT_POSITION_Y = 0x36   # Center Y ellipse position\n    ABS_MT_TOOL_TYPE = 0x37    # Type of touching device\n    ABS_MT_BLOB_ID = 0x38      # Group a set of packets as a blob\n    ABS_MT_TRACKING_ID = 0x39  # Unique ID of initiated contact\n    ABS_MT_PRESSURE = 0x3a     # Pressure on contact area\n\n    # some ioctl base (with 0 value)\n    EVIOCGNAME = 2147501318\n    EVIOCGBIT = 2147501344\n    EVIOCGABS = 2149074240\n\n    # sizeof(struct input_event)\n    struct_input_event_sz = struct.calcsize('LLHHi')\n    struct_input_absinfo_sz = struct.calcsize('iiiiii')\n    sz_l = struct.calcsize('Q')\n\n    class LinuxWacomMotionEventProvider(MotionEventProvider):\n\n        options = ('min_position_x', 'max_position_x',\n                   'min_position_y', 'max_position_y',\n                   'min_pressure', 'max_pressure',\n                   'invert_x', 'invert_y')\n\n        def __init__(self, device, args):\n            super(LinuxWacomMotionEventProvider, self).__init__(device, args)\n            self.input_fn = None\n            self.default_ranges = dict()\n            self.mode = 'touch'\n\n            # split arguments\n            args = args.split(',')\n            if not args:\n                Logger.error('LinuxWacom: No filename given in config')\n                Logger.error('LinuxWacom: Use /dev/input/event0 for example')\n                return None\n\n            # read filename\n            self.input_fn = args[0]\n            Logger.info('LinuxWacom: Read event from <%s>' % self.input_fn)\n\n            # read parameters\n            for arg in args[1:]:\n                if arg == '':\n                    continue\n                arg = arg.split('=')\n\n                # ensure it's a key = value\n                if len(arg) != 2:\n                    err = 'LinuxWacom: Bad parameter' \\\n                        '%s: Not in key=value format.' % arg\n                    Logger.error(err)\n                    continue\n\n                # ensure the key exist\n                key, value = arg\n                if key == 'mode':\n                    self.mode = value\n                    continue\n\n                if key not in LinuxWacomMotionEventProvider.options:\n                    Logger.error('LinuxWacom: unknown %s option' % key)\n                    continue\n\n                # ensure the value\n                try:\n                    self.default_ranges[key] = int(value)\n                except ValueError:\n                    err = 'LinuxWacom: value %s invalid for %s' % (key, value)\n                    Logger.error(err)\n                    continue\n\n                # all good!\n                msg = 'LinuxWacom: Set custom %s to %d' % (key, int(value))\n                Logger.info(msg)\n            Logger.info('LinuxWacom: mode is <%s>' % self.mode)\n\n        def start(self):\n            if self.input_fn is None:\n                return\n            self.uid = 0\n            self.queue = collections.deque()\n            self.thread = threading.Thread(\n                target=self._thread_run,\n                kwargs=dict(\n                    queue=self.queue,\n                    input_fn=self.input_fn,\n                    device=self.device,\n                    default_ranges=self.default_ranges))\n            self.thread.daemon = True\n            self.thread.start()\n\n        def _thread_run(self, **kwargs):\n            input_fn = kwargs.get('input_fn')\n            queue = kwargs.get('queue')\n            device = kwargs.get('device')\n            drs = kwargs.get('default_ranges').get\n            touches = {}\n            touches_sent = []\n            l_points = {}\n\n            # prepare some vars to get limit of some component\n            range_min_position_x = 0\n            range_max_position_x = 2048\n            range_min_position_y = 0\n            range_max_position_y = 2048\n            range_min_pressure = 0\n            range_max_pressure = 255\n            invert_x = int(bool(drs('invert_x', 0)))\n            invert_y = int(bool(drs('invert_y', 0)))\n            reset_touch = False\n\n            def process(points):\n                actives = list(points.keys())\n                for args in points.values():\n                    tid = args['id']\n                    try:\n                        touch = touches[tid]\n                    except KeyError:\n                        touch = LinuxWacomMotionEvent(device, tid, args)\n                        touches[touch.id] = touch\n                    if touch.sx == args['x'] \\\n                            and touch.sy == args['y'] \\\n                            and tid in touches_sent:\n                        continue\n                    touch.move(args)\n                    if tid not in touches_sent:\n                        queue.append(('begin', touch))\n                        touches_sent.append(tid)\n                    queue.append(('update', touch))\n\n                for tid in list(touches.keys())[:]:\n                    if tid not in actives:\n                        touch = touches[tid]\n                        if tid in touches_sent:\n                            touch.update_time_end()\n                            queue.append(('end', touch))\n                            touches_sent.remove(tid)\n                        del touches[tid]\n\n            def normalize(value, vmin, vmax):\n                return (value - vmin) / float(vmax - vmin)\n\n            # open the input\n            try:\n                fd = open(input_fn, 'rb')\n            except IOError:\n                Logger.exception('Unable to open %s' % input_fn)\n                return\n\n            # get the controler name (EVIOCGNAME)\n            device_name = fcntl.ioctl(fd, EVIOCGNAME + (256 << 16),\n                                      \" \" * 256).split('\\x00')[0]\n            Logger.info('LinuxWacom: using <%s>' % device_name)\n\n            # get abs infos\n            bit = fcntl.ioctl(fd, EVIOCGBIT + (EV_MAX << 16), ' ' * sz_l)\n            bit, = struct.unpack('Q', bit)\n            for x in range(EV_MAX):\n                # preserve this, we may want other things than EV_ABS\n                if x != EV_ABS:\n                    continue\n                # EV_ABS available for this device ?\n                if (bit & (1 << x)) == 0:\n                    continue\n                # ask abs info keys to the devices\n                sbit = fcntl.ioctl(fd, EVIOCGBIT + x + (KEY_MAX << 16),\n                                   ' ' * sz_l)\n                sbit, = struct.unpack('Q', sbit)\n                for y in range(KEY_MAX):\n                    if (sbit & (1 << y)) == 0:\n                        continue\n                    absinfo = fcntl.ioctl(fd, EVIOCGABS + y +\n                                          (struct_input_absinfo_sz << 16),\n                                          ' ' * struct_input_absinfo_sz)\n                    abs_value, abs_min, abs_max, abs_fuzz, \\\n                        abs_flat, abs_res = struct.unpack('iiiiii', absinfo)\n                    if y == ABS_X:\n                        range_min_position_x = drs('min_position_x', abs_min)\n                        range_max_position_x = drs('max_position_x', abs_max)\n                        Logger.info('LinuxWacom: ' +\n                                    '<%s> range position X is %d - %d' % (\n                                        device_name, abs_min, abs_max))\n                    elif y == ABS_Y:\n                        range_min_position_y = drs('min_position_y', abs_min)\n                        range_max_position_y = drs('max_position_y', abs_max)\n                        Logger.info('LinuxWacom: ' +\n                                    '<%s> range position Y is %d - %d' % (\n                                        device_name, abs_min, abs_max))\n                    elif y == ABS_PRESSURE:\n                        range_min_pressure = drs('min_pressure', abs_min)\n                        range_max_pressure = drs('max_pressure', abs_max)\n                        Logger.info('LinuxWacom: ' +\n                                    '<%s> range pressure is %d - %d' % (\n                                        device_name, abs_min, abs_max))\n\n            # read until the end\n            changed = False\n            touch_id = 0\n            touch_x = 0\n            touch_y = 0\n            touch_pressure = 0\n            while fd:\n\n                data = fd.read(struct_input_event_sz)\n                if len(data) < struct_input_event_sz:\n                    break\n\n                # extract each event\n                for i in range(len(data) / struct_input_event_sz):\n                    ev = data[i * struct_input_event_sz:]\n\n                    # extract timeval + event infos\n                    tv_sec, tv_usec, ev_type, ev_code, ev_value = \\\n                        struct.unpack('LLHHi', ev[:struct_input_event_sz])\n\n                    if ev_type == EV_SYN and ev_code == SYN_REPORT:\n                        if touch_id in l_points:\n                            p = l_points[touch_id]\n                        else:\n                            p = dict()\n                            l_points[touch_id] = p\n                        p['id'] = touch_id\n                        if reset_touch is False:\n                            p['x'] = touch_x\n                            p['y'] = touch_y\n                            p['pressure'] = touch_pressure\n                        if self.mode == 'pen' \\\n                                and touch_pressure == 0 \\\n                                and not reset_touch:\n                            del l_points[touch_id]\n                        if changed:\n                            if not 'x' in p:\n                                reset_touch = False\n                                continue\n                            process(l_points)\n                            changed = False\n                        if reset_touch:\n                            l_points.clear()\n                            reset_touch = False\n                            process(l_points)\n                    elif ev_type == EV_MSC and ev_code == MSC_SERIAL:\n                        touch_id = ev_value\n                    elif ev_type == EV_ABS and ev_code == ABS_X:\n                        val = normalize(ev_value,\n                                        range_min_position_x,\n                                        range_max_position_x)\n                        if invert_x:\n                            val = 1. - val\n                        touch_x = val\n                        changed = True\n                    elif ev_type == EV_ABS and ev_code == ABS_Y:\n                        val = 1. - normalize(ev_value,\n                                             range_min_position_y,\n                                             range_max_position_y)\n                        if invert_y:\n                            val = 1. - val\n                        touch_y = val\n                        changed = True\n                    elif ev_type == EV_ABS and ev_code == ABS_PRESSURE:\n                        touch_pressure = normalize(ev_value,\n                                                   range_min_pressure,\n                                                   range_max_pressure)\n                        changed = True\n                    elif ev_type == EV_ABS and ev_code == ABS_MISC:\n                        if ev_value == 0:\n                            reset_touch = True\n\n        def update(self, dispatch_fn):\n            # dispatch all event from threads\n            try:\n                while True:\n                    event_type, touch = self.queue.popleft()\n                    dispatch_fn(event_type, touch)\n            except:\n                pass\n\n    MotionEventFactory.register('linuxwacom', LinuxWacomMotionEventProvider)\n"
  },
  {
    "path": "tickeys/kivy/input/providers/mactouch.py",
    "content": "'''\nNative support of MultitouchSupport framework for MacBook (MaxOSX platform)\n===========================================================================\n'''\n\n__all__ = ('MacMotionEventProvider', )\n\nimport ctypes\nimport threading\nimport collections\nimport os\nfrom kivy.input.provider import MotionEventProvider\nfrom kivy.input.factory import MotionEventFactory\nfrom kivy.input.motionevent import MotionEvent\nfrom kivy.input.shape import ShapeRect\n\nif 'KIVY_DOC' not in os.environ:\n    CFArrayRef = ctypes.c_void_p\n    CFMutableArrayRef = ctypes.c_void_p\n    CFIndex = ctypes.c_long\n\n    dll = '/System/Library/PrivateFrameworks/' + \\\n        'MultitouchSupport.framework/MultitouchSupport'\n    MultitouchSupport = ctypes.CDLL(dll)\n\n    CFArrayGetCount = MultitouchSupport.CFArrayGetCount\n    CFArrayGetCount.argtypes = [CFArrayRef]\n    CFArrayGetCount.restype = CFIndex\n\n    CFArrayGetValueAtIndex = MultitouchSupport.CFArrayGetValueAtIndex\n    CFArrayGetValueAtIndex.argtypes = [CFArrayRef, CFIndex]\n    CFArrayGetValueAtIndex.restype = ctypes.c_void_p\n\n    MTDeviceCreateList = MultitouchSupport.MTDeviceCreateList\n    MTDeviceCreateList.argtypes = []\n    MTDeviceCreateList.restype = CFMutableArrayRef\n\n    class MTPoint(ctypes.Structure):\n        _fields_ = [('x', ctypes.c_float),\n                    ('y', ctypes.c_float)]\n\n    class MTVector(ctypes.Structure):\n        _fields_ = [('position', MTPoint),\n                    ('velocity', MTPoint)]\n\n    class MTData(ctypes.Structure):\n        _fields_ = [\n            ('frame', ctypes.c_int),\n            ('timestamp', ctypes.c_double),\n            ('identifier', ctypes.c_int),\n            # Current state (of unknown meaning).\n            ('state', ctypes.c_int),\n            ('unknown1', ctypes.c_int),\n            ('unknown2', ctypes.c_int),\n            # Normalized position and vector of the touch (0 to 1)\n            ('normalized', MTVector),\n            # The area of the touch.\n            ('size', ctypes.c_float),\n            ('unknown3', ctypes.c_int),\n            # The following three define the ellipsoid of a finger.\n            ('angle', ctypes.c_float),\n            ('major_axis', ctypes.c_float),\n            ('minor_axis', ctypes.c_float),\n            ('unknown4', MTVector),\n            ('unknown5_1', ctypes.c_int),\n            ('unknown5_2', ctypes.c_int),\n            ('unknown6', ctypes.c_float), ]\n\n    MTDataRef = ctypes.POINTER(MTData)\n\n    MTContactCallbackFunction = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int,\n                                                 MTDataRef, ctypes.c_int,\n                                                 ctypes.c_double, ctypes.c_int)\n\n    MTDeviceRef = ctypes.c_void_p\n\n    MTRegisterContactFrameCallback = \\\n        MultitouchSupport.MTRegisterContactFrameCallback\n    MTRegisterContactFrameCallback.argtypes = \\\n        [MTDeviceRef, MTContactCallbackFunction]\n    MTRegisterContactFrameCallback.restype = None\n\n    MTDeviceStart = MultitouchSupport.MTDeviceStart\n    MTDeviceStart.argtypes = [MTDeviceRef, ctypes.c_int]\n    MTDeviceStart.restype = None\n\nelse:\n    MTContactCallbackFunction = lambda x: None\n\n\nclass MacMotionEvent(MotionEvent):\n    '''MotionEvent representing a contact point on the touchpad. Supports pos\n    and shape profiles.\n    '''\n\n    def depack(self, args):\n        self.is_touch = True\n        self.shape = ShapeRect()\n        self.sx, self.sy = args[0], args[1]\n        self.shape.width = args[2]\n        self.shape.height = args[2]\n        self.profile = ('pos', 'shape')\n        super(MacMotionEvent, self).depack(args)\n\n    def __str__(self):\n        return '<MacMotionEvent id=%d pos=(%f, %f) device=%s>' \\\n            % (self.id, self.sx, self.sy, self.device)\n\n_instance = None\n\n\nclass MacMotionEventProvider(MotionEventProvider):\n\n    def __init__(self, *largs, **kwargs):\n        global _instance\n        if _instance is not None:\n            raise Exception('Only one MacMotionEvent provider is allowed.')\n        _instance = self\n        super(MacMotionEventProvider, self).__init__(*largs, **kwargs)\n\n    def start(self):\n        # global uid\n        self.uid = 0\n        # touches will be per devices\n        self.touches = {}\n        # lock needed to access on uid\n        self.lock = threading.Lock()\n        # event queue to dispatch in main thread\n        self.queue = collections.deque()\n\n        # ok, listing devices, and attach !\n        devices = MultitouchSupport.MTDeviceCreateList()\n        num_devices = CFArrayGetCount(devices)\n        for i in range(num_devices):\n            device = CFArrayGetValueAtIndex(devices, i)\n            # create touch dict for this device\n            data_id = str(device)\n            self.touches[data_id] = {}\n            # start !\n            MTRegisterContactFrameCallback(device, self._mts_callback)\n            MTDeviceStart(device, 0)\n\n    def update(self, dispatch_fn):\n        # dispatch all event from threads\n        try:\n            while True:\n                event_type, touch = self.queue.popleft()\n                dispatch_fn(event_type, touch)\n        except:\n            pass\n\n    def stop(self):\n        # i don't known how to stop it...\n        pass\n\n    @MTContactCallbackFunction\n    def _mts_callback(device, data_ptr, n_fingers, timestamp, frame):\n        global _instance\n        devid = str(device)\n\n        # XXX create live touch, we get one case that\n        # the device announced by macosx don't match the device\n        # in _mts_callback....\n        if not devid in _instance.touches:\n            _instance.touches[devid] = {}\n\n        touches = _instance.touches[devid]\n        actives = []\n\n        for i in range(n_fingers):\n            # get pointer on data\n            data = data_ptr[i]\n\n            # add this touch as an active touch\n            actives.append(data.identifier)\n\n            # extract identifier\n            data_id = data.identifier\n\n            # prepare argument position\n            norm_pos = data.normalized.position\n            args = (norm_pos.x, norm_pos.y, data.size)\n\n            if not data_id in touches:\n                # increment uid\n                _instance.lock.acquire()\n                _instance.uid += 1\n                # create a touch\n                touch = MacMotionEvent(_instance.device, _instance.uid, args)\n                _instance.lock.release()\n                # create event\n                _instance.queue.append(('begin', touch))\n                # store touch\n                touches[data_id] = touch\n            else:\n                touch = touches[data_id]\n                # check if he really moved\n                if data.normalized.position.x == touch.sx and \\\n                   data.normalized.position.y == touch.sy:\n                    continue\n                touch.move(args)\n                _instance.queue.append(('update', touch))\n\n        # delete old touchs\n        for tid in list(touches.keys())[:]:\n            if tid not in actives:\n                touch = touches[tid]\n                touch.update_time_end()\n                _instance.queue.append(('end', touch))\n                del touches[tid]\n\n        return 0\n\nMotionEventFactory.register('mactouch', MacMotionEventProvider)\n"
  },
  {
    "path": "tickeys/kivy/input/providers/mouse.py",
    "content": "'''\nMouse provider implementation\n=============================\n\nOn linux systems, the mouse provider can be annoying when used with another\nmultitouch provider (hidinput or mtdev). The Mouse can conflict with them: a\nsingle touch can generate one event from the mouse provider and another\nfrom the multitouch provider.\n\nTo avoid this behavior, you can activate the \"disable_on_activity\" token in\nthe mouse configuration. Then, if there are any touches activated by another\nprovider, the mouse event will be discarded. Add this to your configuration::\n\n    [input]\n    mouse = mouse,disable_on_activity\n\nUsing multitouch interaction with the mouse\n-------------------------------------------\n\n.. versionadded:: 1.3.0\n\nBy default, the middle and right mouse buttons, as well as a combination of\nctrl + left mouse button are used for multitouch emulation.\nIf you want to use them for other purposes, you can disable this behavior by\nactivating the \"disable_multitouch\" token::\n\n   [input]\n   mouse = mouse,disable_multitouch\n\n.. versionchanged:: 1.9.0\n\nYou can now selectively control whether a click initiated as described above\nwill emulate multi-touch. If the touch has been initiated in the above manner\n(e.g. right mouse button), multitouch_sim will be added to touch's profile,\nand property `multitouch_sim` to the touch. By default `multitouch_sim` is\nTrue and multitouch will be emulated for that touch. However, if\n`multitouch_on_demand` is added to the config::\n\n   [input]\n   mouse = mouse,multitouch_on_demand\n\nthen `multitouch_sim` defaults to `False`. In that case, if before mouse\nrelease (e.g. in on_touch_down/move) `multitouch_sim`\nis set to True, the touch will simulate multi-touch. For example::\n\n    if 'multitouch_sim' in touch.profile:\n        touch.multitouch_sim = True\n\nFollowing is a list of the supported profiles for :class:`MouseMotionEvent`.\n\n=================== ==========================================================\nProfile name        Description\n------------------- ----------------------------------------------------------\nbutton              Mouse button (left, right, middle, scrollup, scrolldown)\n                    Use property `button`\npos                 2D position. Use properties `x`, `y` or `pos``\nmultitouch_sim      If multitouch is simulated. Use property `multitouch_sim`.\n                    See documatation above.\n=================== ==========================================================\n\n'''\n\n__all__ = ('MouseMotionEventProvider', )\n\nfrom kivy.base import EventLoop\nfrom collections import deque\nfrom kivy.logger import Logger\nfrom kivy.input.provider import MotionEventProvider\nfrom kivy.input.factory import MotionEventFactory\nfrom kivy.input.motionevent import MotionEvent\n\n# late binding\nColor = Ellipse = None\n\n\nclass MouseMotionEvent(MotionEvent):\n\n    def depack(self, args):\n        profile = self.profile\n        # don't overwrite previous profile\n        if not profile:\n            profile.extend(('pos', 'button'))\n        self.is_touch = True\n        self.sx, self.sy = args[:2]\n        if len(args) >= 3:\n            self.button = args[2]\n        if len(args) == 4:\n            self.multitouch_sim = args[3]\n            profile.append('multitouch_sim')\n        super(MouseMotionEvent, self).depack(args)\n\n    #\n    # Create automatically touch on the surface.\n    #\n    def update_graphics(self, win, create=False):\n        global Color, Ellipse\n        de = self.ud.get('_drawelement', None)\n        if de is None and create:\n            if Color is None:\n                from kivy.graphics import Color, Ellipse\n            with win.canvas.after:\n                de = (\n                    Color(.8, .2, .2, .7),\n                    Ellipse(size=(20, 20), segments=15))\n            self.ud._drawelement = de\n        if de is not None:\n            self.push()\n            self.scale_for_screen(\n                win.system_size[0],\n                win.system_size[1],\n                rotation=win.rotation)\n            de[1].pos = self.x - 10, self.y - 10\n            self.pop()\n\n    def clear_graphics(self, win):\n        de = self.ud.pop('_drawelement', None)\n        if de is not None:\n            win.canvas.after.remove(de[0])\n            win.canvas.after.remove(de[1])\n\n\nclass MouseMotionEventProvider(MotionEventProvider):\n    __handlers__ = {}\n\n    def __init__(self, device, args):\n        super(MouseMotionEventProvider, self).__init__(device, args)\n        self.waiting_event = deque()\n        self.touches = {}\n        self.counter = 0\n        self.current_drag = None\n        self.alt_touch = None\n        self.disable_on_activity = False\n        self.disable_multitouch = False\n        self.multitouch_on_demenad = False\n\n        # split arguments\n        args = args.split(',')\n        for arg in args:\n            arg = arg.strip()\n            if arg == '':\n                continue\n            elif arg == 'disable_on_activity':\n                self.disable_on_activity = True\n            elif arg == 'disable_multitouch':\n                self.disable_multitouch = True\n            elif arg == 'multitouch_on_demand':\n                self.multitouch_on_demenad = True\n            else:\n                Logger.error('Mouse: unknown parameter <%s>' % arg)\n\n    def start(self):\n        '''Start the mouse provider'''\n        if not EventLoop.window:\n            return\n        EventLoop.window.bind(\n            on_mouse_move=self.on_mouse_motion,\n            on_mouse_down=self.on_mouse_press,\n            on_mouse_up=self.on_mouse_release)\n\n    def stop(self):\n        '''Stop the mouse provider'''\n        if not EventLoop.window:\n            return\n        EventLoop.window.unbind(\n            on_mouse_move=self.on_mouse_motion,\n            on_mouse_down=self.on_mouse_press,\n            on_mouse_up=self.on_mouse_release)\n\n    def test_activity(self):\n        if not self.disable_on_activity:\n            return False\n        # trying to get if we currently have other touch than us\n        # discard touches generated from kinetic\n        touches = EventLoop.touches\n        for touch in touches:\n            # discard all kinetic touch\n            if touch.__class__.__name__ == 'KineticMotionEvent':\n                continue\n            # not our instance, stop mouse\n            if touch.__class__ != MouseMotionEvent:\n                return True\n        return False\n\n    def find_touch(self, x, y):\n        factor = 10. / EventLoop.window.system_size[0]\n        for t in self.touches.values():\n            if abs(x - t.sx) < factor and abs(y - t.sy) < factor:\n                return t\n        return False\n\n    def create_touch(self, rx, ry, is_double_tap, do_graphics, button):\n        self.counter += 1\n        id = 'mouse' + str(self.counter)\n        args = [rx, ry, button]\n        if do_graphics:\n            args += [not self.multitouch_on_demenad]\n        self.current_drag = cur = MouseMotionEvent(self.device, id=id,\n                                                   args=args)\n        cur.is_double_tap = is_double_tap\n        self.touches[id] = cur\n        if do_graphics:\n            cur.update_graphics(EventLoop.window, True)\n        self.waiting_event.append(('begin', cur))\n        return cur\n\n    def remove_touch(self, cur):\n        if cur.id not in self.touches:\n            return\n        del self.touches[cur.id]\n        cur.update_time_end()\n        self.waiting_event.append(('end', cur))\n        cur.clear_graphics(EventLoop.window)\n\n    def on_mouse_motion(self, win, x, y, modifiers):\n        width, height = EventLoop.window.system_size\n        rx = x / float(width)\n        ry = 1. - y / float(height)\n        if self.current_drag:\n            cur = self.current_drag\n            cur.move([rx, ry])\n            cur.update_graphics(win)\n            self.waiting_event.append(('update', cur))\n        elif self.alt_touch is not None and 'alt' not in modifiers:\n            # alt just released ?\n            is_double_tap = 'shift' in modifiers\n            cur = self.create_touch(rx, ry, is_double_tap, True)\n        return True\n\n    def on_mouse_press(self, win, x, y, button, modifiers):\n        if self.test_activity():\n            return\n        width, height = EventLoop.window.system_size\n        rx = x / float(width)\n        ry = 1. - y / float(height)\n        new_me = self.find_touch(rx, ry)\n        if new_me:\n            self.current_drag = new_me\n        else:\n            is_double_tap = 'shift' in modifiers\n            do_graphics = (not self.disable_multitouch) and (\n                button != 'left' or 'ctrl' in modifiers)\n            cur = self.create_touch(rx, ry, is_double_tap, do_graphics, button)\n            if 'alt' in modifiers:\n                self.alt_touch = cur\n                self.current_drag = None\n        return True\n\n    def on_mouse_release(self, win, x, y, button, modifiers):\n        # special case, if button is all, then remove all the current mouses.\n        if button == 'all':\n            for cur in list(self.touches.values())[:]:\n                self.remove_touch(cur)\n            self.current_drag = None\n\n        cur = self.current_drag\n        if (cur and (self.disable_multitouch or 'multitouch_sim' not in\n                     cur.profile or not cur.multitouch_sim)) or\\\n            (button in ('left', 'scrollup', 'scrolldown', 'scrollleft',\n                        'scrollright') and cur and not ('ctrl' in modifiers)):\n            self.remove_touch(cur)\n            self.current_drag = None\n        if self.alt_touch:\n            self.remove_touch(self.alt_touch)\n            self.alt_touch = None\n        return True\n\n    def update(self, dispatch_fn):\n        '''Update the mouse provider (pop event from the queue)'''\n        try:\n            while True:\n                event = self.waiting_event.popleft()\n                dispatch_fn(*event)\n        except IndexError:\n            pass\n\n# registers\nMotionEventFactory.register('mouse', MouseMotionEventProvider)\n"
  },
  {
    "path": "tickeys/kivy/input/providers/mtdev.py",
    "content": "'''\nNative support for Multitouch devices on Linux, using libmtdev.\n===============================================================\n\nThe Mtdev project is a part of the Ubuntu Maverick multitouch architecture.\nYou can read more on http://wiki.ubuntu.com/Multitouch\n\nTo configure MTDev, it's preferable to use probesysfs providers.\nCheck :py:class:`~kivy.input.providers.probesysfs` for more information.\n\nOtherwise, add this to your configuration::\n\n    [input]\n    # devicename = hidinput,/dev/input/eventXX\n    acert230h = mtdev,/dev/input/event2\n\n.. note::\n    You must have read access to the input event.\n\nYou can use a custom range for the X, Y and pressure values.\nOn some drivers, the range reported is invalid.\nTo fix that, you can add these options to the argument line:\n\n* invert_x : 1 to invert X axis\n* invert_y : 1 to invert Y axis\n* min_position_x : X minimum\n* max_position_x : X maximum\n* min_position_y : Y minimum\n* max_position_y : Y maximum\n* min_pressure : pressure minimum\n* max_pressure : pressure maximum\n* min_touch_major : width shape minimum\n* max_touch_major : width shape maximum\n* min_touch_minor : width shape minimum\n* max_touch_minor : height shape maximum\n'''\n\n__all__ = ('MTDMotionEventProvider', 'MTDMotionEvent')\n\nimport os\nfrom kivy.input.motionevent import MotionEvent\nfrom kivy.input.shape import ShapeRect\n\n\nclass MTDMotionEvent(MotionEvent):\n\n    def depack(self, args):\n        self.is_touch = True\n        self.sx = args['x']\n        self.sy = args['y']\n        self.profile = ['pos']\n        if 'size_w' in args and 'size_h' in args:\n            self.shape = ShapeRect()\n            self.shape.width = args['size_w']\n            self.shape.height = args['size_h']\n            self.profile.append('shape')\n        if 'pressure' in args:\n            self.pressure = args['pressure']\n            self.profile.append('pressure')\n        super(MTDMotionEvent, self).depack(args)\n\n    def __str__(self):\n        i, sx, sy, d = (self.id, self.sx, self.sy, self.device)\n        return '<MTDMotionEvent id=%d pos=(%f, %f) device=%s>' % (i, sx, sy, d)\n\nif 'KIVY_DOC' in os.environ:\n\n    # documentation hack\n    MTDMotionEventProvider = None\n\nelse:\n    import threading\n    import collections\n    from kivy.lib.mtdev import Device, \\\n        MTDEV_TYPE_EV_ABS, MTDEV_CODE_SLOT, MTDEV_CODE_POSITION_X, \\\n        MTDEV_CODE_POSITION_Y, MTDEV_CODE_PRESSURE, \\\n        MTDEV_CODE_TOUCH_MAJOR, MTDEV_CODE_TOUCH_MINOR, \\\n        MTDEV_CODE_TRACKING_ID, MTDEV_ABS_POSITION_X, \\\n        MTDEV_ABS_POSITION_Y, MTDEV_ABS_TOUCH_MINOR, \\\n        MTDEV_ABS_TOUCH_MAJOR\n    from kivy.input.provider import MotionEventProvider\n    from kivy.input.factory import MotionEventFactory\n    from kivy.logger import Logger\n\n    class MTDMotionEventProvider(MotionEventProvider):\n\n        options = ('min_position_x', 'max_position_x',\n                   'min_position_y', 'max_position_y',\n                   'min_pressure', 'max_pressure',\n                   'min_touch_major', 'max_touch_major',\n                   'min_touch_minor', 'min_touch_major',\n                   'invert_x', 'invert_y')\n\n        def __init__(self, device, args):\n            super(MTDMotionEventProvider, self).__init__(device, args)\n            self._device = None\n            self.input_fn = None\n            self.default_ranges = dict()\n\n            # split arguments\n            args = args.split(',')\n            if not args:\n                Logger.error('MTD: No filename pass to MTD configuration')\n                Logger.error('MTD: Use /dev/input/event0 for example')\n                return None\n\n            # read filename\n            self.input_fn = args[0]\n            Logger.info('MTD: Read event from <%s>' % self.input_fn)\n\n            # read parameters\n            for arg in args[1:]:\n                if arg == '':\n                    continue\n                arg = arg.split('=')\n\n                # ensure it's a key = value\n                if len(arg) != 2:\n                    err = 'MTD: Bad parameter %s: Not in key=value format' %\\\n                        arg\n                    Logger.error()\n                    continue\n\n                # ensure the key exist\n                key, value = arg\n                if key not in MTDMotionEventProvider.options:\n                    Logger.error('MTD: unknown %s option' % key)\n                    continue\n\n                # ensure the value\n                try:\n                    self.default_ranges[key] = int(value)\n                except ValueError:\n                    err = 'MTD: invalid value %s for option %s' % (key, value)\n                    Logger.error(err)\n                    continue\n\n                # all good!\n                Logger.info('MTD: Set custom %s to %d' % (key, int(value)))\n\n        def start(self):\n            if self.input_fn is None:\n                return\n            self.uid = 0\n            self.queue = collections.deque()\n            self.thread = threading.Thread(\n                target=self._thread_run,\n                kwargs=dict(\n                    queue=self.queue,\n                    input_fn=self.input_fn,\n                    device=self.device,\n                    default_ranges=self.default_ranges))\n            self.thread.daemon = True\n            self.thread.start()\n\n        def _thread_run(self, **kwargs):\n            input_fn = kwargs.get('input_fn')\n            queue = kwargs.get('queue')\n            device = kwargs.get('device')\n            drs = kwargs.get('default_ranges').get\n            touches = {}\n            touches_sent = []\n            point = {}\n            l_points = {}\n\n            def process(points):\n                for args in points:\n                    # this can happen if we have a touch going on already at the\n                    # start of the app\n                    if 'id' not in args:\n                        continue\n                    tid = args['id']\n                    try:\n                        touch = touches[tid]\n                    except KeyError:\n                        touch = MTDMotionEvent(device, tid, args)\n                        touches[touch.id] = touch\n                    touch.move(args)\n                    action = 'update'\n                    if tid not in touches_sent:\n                        action = 'begin'\n                        touches_sent.append(tid)\n                    if 'delete' in args:\n                        action = 'end'\n                        del args['delete']\n                        del touches[touch.id]\n                        touches_sent.remove(tid)\n                        touch.update_time_end()\n                    queue.append((action, touch))\n\n            def normalize(value, vmin, vmax):\n                return (value - vmin) / float(vmax - vmin)\n\n            # open mtdev device\n            _fn = input_fn\n            _slot = 0\n            _device = Device(_fn)\n            _changes = set()\n\n            # prepare some vars to get limit of some component\n            ab = _device.get_abs(MTDEV_ABS_POSITION_X)\n            range_min_position_x = drs('min_position_x', ab.minimum)\n            range_max_position_x = drs('max_position_x', ab.maximum)\n            Logger.info('MTD: <%s> range position X is %d - %d' %\n                        (_fn, range_min_position_x, range_max_position_x))\n\n            ab = _device.get_abs(MTDEV_ABS_POSITION_Y)\n            range_min_position_y = drs('min_position_y', ab.minimum)\n            range_max_position_y = drs('max_position_y', ab.maximum)\n            Logger.info('MTD: <%s> range position Y is %d - %d' %\n                        (_fn, range_min_position_y, range_max_position_y))\n\n            ab = _device.get_abs(MTDEV_ABS_TOUCH_MAJOR)\n            range_min_major = drs('min_touch_major', ab.minimum)\n            range_max_major = drs('max_touch_major', ab.maximum)\n            Logger.info('MTD: <%s> range touch major is %d - %d' %\n                        (_fn, range_min_major, range_max_major))\n\n            ab = _device.get_abs(MTDEV_ABS_TOUCH_MINOR)\n            range_min_minor = drs('min_touch_minor', ab.minimum)\n            range_max_minor = drs('max_touch_minor', ab.maximum)\n            Logger.info('MTD: <%s> range touch minor is %d - %d' %\n                        (_fn, range_min_minor, range_max_minor))\n\n            range_min_pressure = drs('min_pressure', 0)\n            range_max_pressure = drs('max_pressure', 255)\n            Logger.info('MTD: <%s> range pressure is %d - %d' %\n                        (_fn, range_min_pressure, range_max_pressure))\n\n            invert_x = int(bool(drs('invert_x', 0)))\n            invert_y = int(bool(drs('invert_y', 0)))\n            Logger.info('MTD: <%s> axes invertion: X is %d, Y is %d' %\n                        (_fn, invert_x, invert_y))\n\n            while _device:\n                # idle as much as we can.\n                while _device.idle(1000):\n                    continue\n\n                # got data, read all without redoing idle\n                while True:\n                    data = _device.get()\n                    if data is None:\n                        break\n\n                    # set the working slot\n                    if data.type == MTDEV_TYPE_EV_ABS and \\\n                       data.code == MTDEV_CODE_SLOT:\n                        _slot = data.value\n                        continue\n\n                    # fill the slot\n                    if not _slot in l_points:\n                        l_points[_slot] = dict()\n                    point = l_points[_slot]\n                    ev_value = data.value\n                    ev_code = data.code\n                    if ev_code == MTDEV_CODE_POSITION_X:\n                        val = normalize(ev_value,\n                                        range_min_position_x,\n                                        range_max_position_x)\n                        if invert_x:\n                            val = 1. - val\n                        point['x'] = val\n                    elif ev_code == MTDEV_CODE_POSITION_Y:\n                        val = 1. - normalize(ev_value,\n                                             range_min_position_y,\n                                             range_max_position_y)\n                        if invert_y:\n                            val = 1. - val\n                        point['y'] = val\n                    elif ev_code == MTDEV_CODE_PRESSURE:\n                        point['pressure'] = normalize(ev_value,\n                                                      range_min_pressure,\n                                                      range_max_pressure)\n                    elif ev_code == MTDEV_CODE_TOUCH_MAJOR:\n                        point['size_w'] = normalize(ev_value,\n                                                    range_min_major,\n                                                    range_max_major)\n                    elif ev_code == MTDEV_CODE_TOUCH_MINOR:\n                        point['size_h'] = normalize(ev_value,\n                                                    range_min_minor,\n                                                    range_max_minor)\n                    elif ev_code == MTDEV_CODE_TRACKING_ID:\n                        if ev_value == -1:\n                            point['delete'] = True\n                            # force process of changes here, as the slot can be\n                            # reused.\n                            _changes.add(_slot)\n                            process([l_points[x] for x in _changes])\n                            _changes.clear()\n                            continue\n                        else:\n                            point['id'] = ev_value\n                    else:\n                        # unrecognized command, ignore.\n                        continue\n                    _changes.add(_slot)\n\n                # push all changes\n                if _changes:\n                    process([l_points[x] for x in _changes])\n                    _changes.clear()\n\n        def update(self, dispatch_fn):\n            # dispatch all event from threads\n            try:\n                while True:\n                    event_type, touch = self.queue.popleft()\n                    dispatch_fn(event_type, touch)\n            except:\n                pass\n\n    MotionEventFactory.register('mtdev', MTDMotionEventProvider)\n"
  },
  {
    "path": "tickeys/kivy/input/providers/probesysfs.py",
    "content": "'''\nAuto Create Input Provider Config Entry for Available MT Hardware (linux only).\n===============================================================================\n\nThanks to Marc Tardif for the probing code, taken from scan-for-mt-device.\n\nThe device discovery is done by this provider. However, the reading of\ninput can be performed by other providers like: hidinput, mtdev and\nlinuxwacom. mtdev is used prior to other providers. For more\ninformation about mtdev, check :py:class:`~kivy.input.providers.mtdev`.\n\nHere is an example of auto creation::\n\n    [input]\n    # using mtdev\n    device_%(name)s = probesysfs,provider=mtdev\n    # using hidinput\n    device_%(name)s = probesysfs,provider=hidinput\n    # using mtdev with a match on name\n    device_%(name)s = probesysfs,provider=mtdev,match=acer\n\n    # using hidinput with custom parameters to hidinput (all on one line)\n    %(name)s = probesysfs,\n        provider=hidinput,param=min_pressure=1,param=max_pressure=99\n\n    # you can also match your wacom touchscreen\n    touch = probesysfs,match=E3 Finger,provider=linuxwacom,\n        select_all=1,param=mode=touch\n    # and your wacom pen\n    pen = probesysfs,match=E3 Pen,provider=linuxwacom,\n        select_all=1,param=mode=pen\n\nBy default, ProbeSysfs module will enumerate hardware from the /sys/class/input\ndevice, and configure hardware with ABS_MT_POSITION_X capability. But for\nexample, the wacom screen doesn't support this capability. You can prevent this\nbehavior by putting select_all=1 in your config line.\n'''\n\n__all__ = ('ProbeSysfsHardwareProbe', )\n\nimport os\nfrom os.path import sep\n\nif 'KIVY_DOC' in os.environ:\n\n    ProbeSysfsHardwareProbe = None\n\nelse:\n    from re import match, IGNORECASE\n    from glob import glob\n    from subprocess import Popen, PIPE\n    from kivy.logger import Logger\n    from kivy.input.provider import MotionEventProvider\n    from kivy.input.factory import MotionEventFactory\n    from kivy.config import _is_rpi\n\n    # See linux/input.h\n    ABS_MT_POSITION_X = 0x35\n\n    _cache_input = None\n\n    class Input(object):\n\n        def __init__(self, path):\n            self.path = path\n\n        @property\n        def device(self):\n            base = os.path.basename(self.path)\n            return os.path.join(\"/dev\", \"input\", base)\n\n        @property\n        def name(self):\n            path = os.path.join(self.path, \"device\", \"name\")\n            return read_line(path)\n\n        def get_capabilities(self):\n            path = os.path.join(self.path, \"device\", \"capabilities\", \"abs\")\n            line = read_line(path)\n            capabilities = []\n            long_bit = getconf(\"LONG_BIT\")\n            for i, word in enumerate(line.split(\" \")):\n                word = int(word, 16)\n                subcapabilities = [bool(word & 1 << i)\n                                   for i in range(long_bit)]\n                capabilities[:0] = subcapabilities\n\n            return capabilities\n\n        def has_capability(self, capability):\n            capabilities = self.get_capabilities()\n            return len(capabilities) > capability and capabilities[capability]\n\n    def getconf(var):\n        output = Popen([\"getconf\", var], stdout=PIPE).communicate()[0]\n        return int(output)\n\n    def get_inputs(path):\n        global _cache_input\n        if _cache_input is None:\n            event_glob = os.path.join(path, \"event*\")\n            _cache_input = [Input(x) for x in glob(event_glob)]\n        return _cache_input\n\n    def read_line(path):\n        f = open(path)\n        try:\n            return f.readline().strip()\n        finally:\n            f.close()\n\n    class ProbeSysfsHardwareProbe(MotionEventProvider):\n\n        def __new__(self, device, args):\n            # hack to not return an instance of this provider.\n            # :)\n            instance = super(ProbeSysfsHardwareProbe, self).__new__(self)\n            instance.__init__(device, args)\n\n        def __init__(self, device, args):\n            super(ProbeSysfsHardwareProbe, self).__init__(device, args)\n            self.provider = 'mtdev'\n            self.match = None\n            self.input_path = '/sys/class/input'\n            self.select_all = True if _is_rpi else False\n            self.use_regex = False\n            self.args = []\n\n            args = args.split(',')\n            for arg in args:\n                if arg == '':\n                    continue\n                arg = arg.split('=', 1)\n                # ensure it's a key = value\n                if len(arg) != 2:\n                    Logger.error('ProbeSysfs: invalid parameters %s, not'\n                                 ' key=value format' % arg)\n                    continue\n\n                key, value = arg\n                if key == 'match':\n                    self.match = value\n                elif key == 'provider':\n                    self.provider = value\n                elif key == 'use_regex':\n                    self.use_regex = bool(value)\n                elif key == 'select_all':\n                    self.select_all = bool(value)\n                elif key == 'param':\n                    self.args.append(value)\n                else:\n                    Logger.error('ProbeSysfs: unknown %s option' % key)\n                    continue\n\n            self.probe()\n\n        def probe(self):\n            inputs = get_inputs(self.input_path)\n            Logger.debug('ProbeSysfs: using probsysfs!')\n            if not self.select_all:\n                inputs = [x for x in inputs if\n                          x.has_capability(ABS_MT_POSITION_X)]\n            for device in inputs:\n                Logger.debug('ProbeSysfs: found device: %s at %s' % (\n                    device.name, device.device))\n\n                # must ignore ?\n                if self.match:\n                    if self.use_regex:\n                        if not match(self.match, device.name, IGNORECASE):\n                            Logger.debug('ProbeSysfs: device not match the'\n                                         ' rule in config, ignoring.')\n                            continue\n                    else:\n                        if self.match not in device.name:\n                            continue\n\n                Logger.info('ProbeSysfs: device match: %s' % device.device)\n\n                d = device.device\n                devicename = self.device % dict(name=d.split(sep)[-1])\n\n                provider = MotionEventFactory.get(self.provider)\n                if provider is None:\n                    Logger.info('ProbeSysfs: unable to found provider %s' %\n                                self.provider)\n                    Logger.info('ProbeSysfs: fallback on hidinput')\n                    provider = MotionEventFactory.get('hidinput')\n                if provider is None:\n                    Logger.critical('ProbeSysfs: no input provider found'\n                                    ' to handle this device !')\n                    continue\n\n                instance = provider(devicename, '%s,%s' % (\n                    device.device, ','.join(self.args)))\n                if instance:\n                    from kivy.base import EventLoop\n                    EventLoop.add_input_provider(instance)\n\n    MotionEventFactory.register('probesysfs', ProbeSysfsHardwareProbe)\n"
  },
  {
    "path": "tickeys/kivy/input/providers/tuio.py",
    "content": "'''\nTUIO Input Provider\n===================\n\nTUIO is the de facto standard network protocol for the transmission of\ntouch and fiducial information between a server and a client. To learn\nmore about TUIO (which is itself based on the OSC protocol), please\nrefer to http://tuio.org -- The specification should be of special\ninterest.\n\nConfigure a TUIO provider in the config.ini\n-------------------------------------------\n\nThe TUIO provider can be configured in the configuration file in the\n``[input]`` section::\n\n    [input]\n    # name = tuio,<ip>:<port>\n    multitouchtable = tuio,192.168.0.1:3333\n\nConfigure a TUIO provider in the App\n------------------------------------\n\nYou must add the provider before your application is run, like this::\n\n    from kivy.app import App\n    from kivy.config import Config\n\n    class TestApp(App):\n        def build(self):\n            Config.set('input', 'multitouchscreen1', 'tuio,0.0.0.0:3333')\n            # You can also add a second TUIO listener\n            # Config.set('input', 'source2', 'tuio,0.0.0.0:3334')\n            # Then do the usual things\n            # ...\n            return\n'''\n\n__all__ = ('TuioMotionEventProvider', 'Tuio2dCurMotionEvent',\n           'Tuio2dObjMotionEvent')\n\nfrom kivy.lib import osc\nfrom collections import deque\nfrom kivy.input.provider import MotionEventProvider\nfrom kivy.input.factory import MotionEventFactory\nfrom kivy.input.motionevent import MotionEvent\nfrom kivy.input.shape import ShapeRect\nfrom kivy.logger import Logger\n\n\nclass TuioMotionEventProvider(MotionEventProvider):\n    '''The TUIO provider listens to a socket and handles some of the incoming\n    OSC messages:\n\n        * /tuio/2Dcur\n        * /tuio/2Dobj\n\n    You can easily extend the provider to handle new TUIO paths like so::\n\n        # Create a class to handle the new TUIO type/path\n        # Replace NEWPATH with the pathname you want to handle\n        class TuioNEWPATHMotionEvent(MotionEvent):\n            def __init__(self, id, args):\n                super(TuioNEWPATHMotionEvent, self).__init__(id, args)\n\n            def depack(self, args):\n                # In this method, implement 'unpacking' for the received\n                # arguments. you basically translate from TUIO args to Kivy\n                # MotionEvent variables. If all you receive are x and y\n                # values, you can do it like this:\n                if len(args) == 2:\n                    self.sx, self.sy = args\n                    self.profile = ('pos', )\n                self.sy = 1 - self.sy\n                super(TuioNEWPATHMotionEvent, self).depack(args)\n\n        # Register it with the TUIO MotionEvent provider.\n        # You obviously need to replace the PATH placeholders appropriately.\n        TuioMotionEventProvider.register('/tuio/PATH', TuioNEWPATHMotionEvent)\n\n    .. note::\n\n        The class name is of no technical importance. Your class will be\n        associated with the path that you pass to the ``register()``\n        function. To keep things simple, you should name your class after the\n        path that it handles, though.\n    '''\n\n    __handlers__ = {}\n\n    def __init__(self, device, args):\n        super(TuioMotionEventProvider, self).__init__(device, args)\n        args = args.split(',')\n        if len(args) <= 0:\n            Logger.error('Tuio: Invalid configuration for TUIO provider')\n            Logger.error('Tuio: Format must be ip:port (eg. 127.0.0.1:3333)')\n            err = 'Tuio: Current configuration is <%s>' % (str(','.join(args)))\n            Logger.error(err)\n            return None\n        ipport = args[0].split(':')\n        if len(ipport) != 2:\n            Logger.error('Tuio: Invalid configuration for TUIO provider')\n            Logger.error('Tuio: Format must be ip:port (eg. 127.0.0.1:3333)')\n            err = 'Tuio: Current configuration is <%s>' % (str(','.join(args)))\n            Logger.error(err)\n            return None\n        self.ip, self.port = args[0].split(':')\n        self.port = int(self.port)\n        self.handlers = {}\n        self.oscid = None\n        self.tuio_event_q = deque()\n        self.touches = {}\n\n    @staticmethod\n    def register(oscpath, classname):\n        '''Register a new path to handle in TUIO provider'''\n        TuioMotionEventProvider.__handlers__[oscpath] = classname\n\n    @staticmethod\n    def unregister(oscpath, classname):\n        '''Unregister a path to stop handling it in the TUIO provider'''\n        if oscpath in TuioMotionEventProvider.__handlers__:\n            del TuioMotionEventProvider.__handlers__[oscpath]\n\n    @staticmethod\n    def create(oscpath, **kwargs):\n        '''Create a touch event from a TUIO path'''\n        if oscpath not in TuioMotionEventProvider.__handlers__:\n            raise Exception('Unknown %s touch path' % oscpath)\n        return TuioMotionEventProvider.__handlers__[oscpath](**kwargs)\n\n    def start(self):\n        '''Start the TUIO provider'''\n        self.oscid = osc.listen(self.ip, self.port)\n        for oscpath in TuioMotionEventProvider.__handlers__:\n            self.touches[oscpath] = {}\n            osc.bind(self.oscid, self._osc_tuio_cb, oscpath)\n\n    def stop(self):\n        '''Stop the TUIO provider'''\n        osc.dontListen(self.oscid)\n\n    def update(self, dispatch_fn):\n        '''Update the TUIO provider (pop events from the queue)'''\n\n        # deque osc queue\n        osc.readQueue(self.oscid)\n\n        # read the Queue with event\n        while True:\n            try:\n                value = self.tuio_event_q.pop()\n            except IndexError:\n                # queue is empty, we're done for now\n                return\n            self._update(dispatch_fn, value)\n\n    def _osc_tuio_cb(self, *incoming):\n        message = incoming[0]\n        oscpath, types, args = message[0], message[1], message[2:]\n        self.tuio_event_q.appendleft([oscpath, args, types])\n\n    def _update(self, dispatch_fn, value):\n        oscpath, args, types = value\n        command = args[0]\n\n        # verify commands\n        if command not in ['alive', 'set']:\n            return\n\n        # move or create a new touch\n        if command == 'set':\n            id = args[1]\n            if id not in self.touches[oscpath]:\n                # new touch\n                touch = TuioMotionEventProvider.__handlers__[oscpath](\n                    self.device, id, args[2:])\n                self.touches[oscpath][id] = touch\n                dispatch_fn('begin', touch)\n            else:\n                # update a current touch\n                touch = self.touches[oscpath][id]\n                touch.move(args[2:])\n                dispatch_fn('update', touch)\n\n        # alive event, check for deleted touch\n        if command == 'alive':\n            alives = args[1:]\n            to_delete = []\n            for id in self.touches[oscpath]:\n                if not id in alives:\n                    # touch up\n                    touch = self.touches[oscpath][id]\n                    if not touch in to_delete:\n                        to_delete.append(touch)\n\n            for touch in to_delete:\n                dispatch_fn('end', touch)\n                del self.touches[oscpath][touch.id]\n\n\nclass TuioMotionEvent(MotionEvent):\n    '''Abstraction for TUIO touches/fiducials.\n\n    Depending on the tracking software you use (e.g. Movid, CCV, etc.) and its\n    TUIO implementation, the TuioMotionEvent object can support multiple\n    profiles such as:\n\n        * Fiducial ID: profile name 'markerid', attribute ``.fid``\n        * Position: profile name 'pos', attributes ``.x``, ``.y``\n        * Angle: profile name 'angle', attribute ``.a``\n        * Velocity vector: profile name 'mov', attributes ``.X``, ``.Y``\n        * Rotation velocity: profile name 'rot', attribute ``.A``\n        * Motion acceleration: profile name 'motacc', attribute ``.m``\n        * Rotation acceleration: profile name 'rotacc', attribute ``.r``\n    '''\n    __attrs__ = ('a', 'b', 'c', 'X', 'Y', 'Z', 'A', 'B', 'C', 'm', 'r')\n\n    def __init__(self, device, id, args):\n        super(TuioMotionEvent, self).__init__(device, id, args)\n        # Default argument for TUIO touches\n        self.a = 0.0\n        self.b = 0.0\n        self.c = 0.0\n        self.X = 0.0\n        self.Y = 0.0\n        self.Z = 0.0\n        self.A = 0.0\n        self.B = 0.0\n        self.C = 0.0\n        self.m = 0.0\n        self.r = 0.0\n\n    angle = property(lambda self: self.a)\n    mot_accel = property(lambda self: self.m)\n    rot_accel = property(lambda self: self.r)\n    xmot = property(lambda self: self.X)\n    ymot = property(lambda self: self.Y)\n    zmot = property(lambda self: self.Z)\n\n\nclass Tuio2dCurMotionEvent(TuioMotionEvent):\n    '''A 2dCur TUIO touch.'''\n\n    def __init__(self, device, id, args):\n        super(Tuio2dCurMotionEvent, self).__init__(device, id, args)\n\n    def depack(self, args):\n        self.is_touch = True\n        if len(args) < 5:\n            self.sx, self.sy = list(map(float, args[0:2]))\n            self.profile = ('pos', )\n        elif len(args) == 5:\n            self.sx, self.sy, self.X, self.Y, self.m = list(map(float,\n                                                                args[0:5]))\n            self.Y = -self.Y\n            self.profile = ('pos', 'mov', 'motacc')\n        else:\n            self.sx, self.sy, self.X, self.Y = list(map(float, args[0:4]))\n            self.m, width, height = list(map(float, args[4:7]))\n            self.Y = -self.Y\n            self.profile = ('pos', 'mov', 'motacc', 'shape')\n            if self.shape is None:\n                self.shape = ShapeRect()\n            self.shape.width = width\n            self.shape.height = height\n        self.sy = 1 - self.sy\n        super(Tuio2dCurMotionEvent, self).depack(args)\n\n\nclass Tuio2dObjMotionEvent(TuioMotionEvent):\n    '''A 2dObj TUIO object.\n    '''\n\n    def __init__(self, device, id, args):\n        super(Tuio2dObjMotionEvent, self).__init__(device, id, args)\n\n    def depack(self, args):\n        self.is_touch = True\n        if len(args) < 5:\n            self.sx, self.sy = args[0:2]\n            self.profile = ('pos', )\n        elif len(args) == 9:\n            self.fid, self.sx, self.sy, self.a, self.X, self.Y = args[:6]\n            self.A, self.m, self.r = args[6:9]\n            self.Y = -self.Y\n            self.profile = ('markerid', 'pos', 'angle', 'mov', 'rot',\n                            'motacc', 'rotacc')\n        else:\n            self.fid, self.sx, self.sy, self.a, self.X, self.Y = args[:6]\n            self.A, self.m, self.r, width, height = args[6:11]\n            self.Y = -self.Y\n            self.profile = ('markerid', 'pos', 'angle', 'mov', 'rot', 'rotacc',\n                            'acc', 'shape')\n            if self.shape is None:\n                self.shape = ShapeRect()\n                self.shape.width = width\n                self.shape.height = height\n        self.sy = 1 - self.sy\n        super(Tuio2dObjMotionEvent, self).depack(args)\n\n\nclass Tuio2dBlbMotionEvent(TuioMotionEvent):\n    '''A 2dBlb TUIO object.\n    # FIXME 3d shape are not supported\n    /tuio/2Dobj set s i x y a       X Y A m r\n    /tuio/2Dblb set s   x y a w h f X Y A m r\n    '''\n\n    def __init__(self, device, id, args):\n        super(Tuio2dBlbMotionEvent, self).__init__(device, id, args)\n\n    def depack(self, args):\n        self.is_touch = True\n        self.sx, self.sy, self.a, self.X, self.Y, sw, sh, sd, \\\n            self.A, self.m, self.r = args\n        self.Y = -self.Y\n        self.profile = ('pos', 'angle', 'mov', 'rot', 'rotacc',\n                        'acc', 'shape')\n        if self.shape is None:\n            self.shape = ShapeRect()\n            self.shape.width = sw\n            self.shape.height = sh\n        self.sy = 1 - self.sy\n        super(Tuio2dBlbMotionEvent, self).depack(args)\n\n\n# registers\nTuioMotionEventProvider.register('/tuio/2Dcur', Tuio2dCurMotionEvent)\nTuioMotionEventProvider.register('/tuio/2Dobj', Tuio2dObjMotionEvent)\nTuioMotionEventProvider.register('/tuio/2Dblb', Tuio2dBlbMotionEvent)\nMotionEventFactory.register('tuio', TuioMotionEventProvider)\n"
  },
  {
    "path": "tickeys/kivy/input/providers/wm_common.py",
    "content": "'''\nCommon definitions for a Windows provider\n=========================================\n\nThis file provides common definitions for constants used by WM_Touch / WM_Pen.\n'''\n\nWM_MOUSEFIRST = 512\nWM_MOUSEMOVE = 512\nWM_LBUTTONDOWN = 513\nWM_LBUTTONUP = 514\nWM_LBUTTONDBLCLK = 515\nWM_RBUTTONDOWN = 516\nWM_RBUTTONUP = 517\nWM_RBUTTONDBLCLK = 518\nWM_MBUTTONDOWN = 519\nWM_MBUTTONUP = 520\nWM_MBUTTONDBLCLK = 521\nWM_MOUSEWHEEL = 522\nWM_MOUSELAST = 522\n\nWM_TOUCH = 576\nTOUCHEVENTF_MOVE = 1\nTOUCHEVENTF_DOWN = 2\nTOUCHEVENTF_UP = 4\n\nPEN_OR_TOUCH_SIGNATURE = 0xFF515700\nPEN_OR_TOUCH_MASK = 0xFFFFFF00\nPEN_EVENT_TOUCH_MASK = 0x80\n\nSM_CYCAPTION = 4\n\nWM_TABLET_QUERYSYSTEMGESTURE = 0x000002CC\nTABLET_DISABLE_PRESSANDHOLD = 0x00000001\nTABLET_DISABLE_PENTAPFEEDBACK = 0x00000008\nTABLET_DISABLE_PENBARRELFEEDBACK = 0x00000010\nTABLET_DISABLE_TOUCHUIFORCEON = 0x00000100\nTABLET_DISABLE_TOUCHUIFORCEOFF = 0x00000200\nTABLET_DISABLE_TOUCHSWITCH = 0x00008000\nTABLET_DISABLE_FLICKS = 0x00010000\nTABLET_ENABLE_FLICKSONCONTEXT = 0x00020000\nTABLET_ENABLE_FLICKLEARNINGMODE = 0x00040000\nTABLET_DISABLE_SMOOTHSCROLLING = 0x00080000\nTABLET_DISABLE_FLICKFALLBACKKEYS = 0x00100000\nGWL_WNDPROC = -4\n\n\nQUERYSYSTEMGESTURE_WNDPROC = (\n    TABLET_DISABLE_PRESSANDHOLD |\n    TABLET_DISABLE_PENTAPFEEDBACK |\n    TABLET_DISABLE_PENBARRELFEEDBACK |\n    TABLET_DISABLE_SMOOTHSCROLLING |\n    TABLET_DISABLE_FLICKFALLBACKKEYS |\n    TABLET_DISABLE_TOUCHSWITCH |\n    TABLET_DISABLE_FLICKS)\n"
  },
  {
    "path": "tickeys/kivy/input/providers/wm_pen.py",
    "content": "'''\nSupport for WM_PEN messages (Windows platform)\n==============================================\n'''\n\n__all__ = ('WM_PenProvider', 'WM_Pen')\n\nimport os\nfrom kivy.input.providers.wm_common import (\n    PEN_OR_TOUCH_SIGNATURE, PEN_OR_TOUCH_MASK, GWL_WNDPROC,\n    WM_MOUSEMOVE, WM_LBUTTONUP, WM_LBUTTONDOWN,\n    WM_TABLET_QUERYSYSTEMGESTURE, QUERYSYSTEMGESTURE_WNDPROC,\n    PEN_EVENT_TOUCH_MASK)\nfrom kivy.input.motionevent import MotionEvent\n\n\nclass WM_Pen(MotionEvent):\n    '''MotionEvent representing the WM_Pen event. Supports the pos profile.'''\n\n    def depack(self, args):\n        self.is_touch = True\n        self.sx, self.sy = args[0], args[1]\n        super(WM_Pen, self).depack(args)\n\n    def __str__(self):\n        i, u, s, d = (self.id, self.uid, str(self.spos), self.device)\n        return '<WMPen id:%d uid:%d pos:%s device:%s>' % (i, u, s, d)\nif 'KIVY_DOC' in os.environ:\n    # documentation hack\n    WM_PenProvider = None\n\nelse:\n    from collections import deque\n    from ctypes.wintypes import (ULONG, UINT, WPARAM, LPARAM,\n                                 HANDLE, BOOL)\n    from ctypes import (Structure, windll, byref, c_int16,\n                        c_int, WINFUNCTYPE, POINTER)\n    from kivy.input.provider import MotionEventProvider\n    from kivy.input.factory import MotionEventFactory\n\n    LRESULT = LPARAM\n    WNDPROC = WINFUNCTYPE(LRESULT, HANDLE, UINT, WPARAM, LPARAM)\n\n    class RECT(Structure):\n        _fields_ = [\n            ('left', ULONG),\n            ('top', ULONG),\n            ('right', ULONG),\n            ('bottom', ULONG)]\n\n        x = property(lambda self: self.left)\n        y = property(lambda self: self.top)\n        w = property(lambda self: self.right - self.left)\n        h = property(lambda self: self.bottom - self.top)\n    win_rect = RECT()\n\n    try:\n        windll.user32.SetWindowLongPtrW.restype = WNDPROC\n        windll.user32.SetWindowLongPtrW.argtypes = [HANDLE, c_int, WNDPROC]\n        SetWindowLong_wrapper = windll.user32.SetWindowLongPtrW\n    except AttributeError:\n        windll.user32.SetWindowLongW.restype = WNDPROC\n        windll.user32.SetWindowLongW.argtypes = [HANDLE, c_int, WNDPROC]\n        SetWindowLong_wrapper = windll.user32.SetWindowLongW\n\n    windll.user32.GetMessageExtraInfo.restype = LPARAM\n    windll.user32.GetMessageExtraInfo.argtypes = []\n    windll.user32.GetClientRect.restype = BOOL\n    windll.user32.GetClientRect.argtypes = [HANDLE, POINTER(RECT)]\n    windll.user32.CallWindowProcW.restype = LRESULT\n    windll.user32.CallWindowProcW.argtypes = [WNDPROC, HANDLE, UINT, WPARAM,\n                                              LPARAM]\n    windll.user32.GetActiveWindow.restype = HANDLE\n    windll.user32.GetActiveWindow.argtypes = []\n\n    class WM_PenProvider(MotionEventProvider):\n\n        def _is_pen_message(self, msg):\n            info = windll.user32.GetMessageExtraInfo()\n            # It's a touch or a pen\n            if (info & PEN_OR_TOUCH_MASK) == PEN_OR_TOUCH_SIGNATURE:\n                if not info & PEN_EVENT_TOUCH_MASK:\n                    return True\n\n        def _pen_handler(self, msg, wParam, lParam):\n            if msg not in (WM_LBUTTONDOWN, WM_MOUSEMOVE, WM_LBUTTONUP):\n                return\n\n            windll.user32.GetClientRect(self.hwnd, byref(win_rect))\n            x = c_int16(lParam & 0xffff).value / float(win_rect.w)\n            y = c_int16(lParam >> 16).value / float(win_rect.h)\n            y = abs(1.0 - y)\n\n            if msg == WM_LBUTTONDOWN:\n                self.pen_events.appendleft(('begin', x, y))\n                self.pen_status = True\n\n            if msg == WM_MOUSEMOVE and self.pen_status:\n                self.pen_events.appendleft(('update', x, y))\n\n            if msg == WM_LBUTTONUP:\n                self.pen_events.appendleft(('end', x, y))\n                self.pen_status = False\n\n        def _pen_wndProc(self, hwnd, msg, wParam, lParam):\n            if msg == WM_TABLET_QUERYSYSTEMGESTURE:\n                return QUERYSYSTEMGESTURE_WNDPROC\n            if self._is_pen_message(msg):\n                self._pen_handler(msg, wParam, lParam)\n                return 1\n            else:\n                return windll.user32.CallWindowProcW(self.old_windProc,\n                                                     hwnd, msg, wParam, lParam)\n\n        def start(self):\n            self.uid = 0\n            self.pen = None\n            self.pen_status = None\n            self.pen_events = deque()\n\n            self.hwnd = windll.user32.GetActiveWindow()\n\n            # inject our own wndProc to handle messages\n            # before window manager does\n            self.new_windProc = WNDPROC(self._pen_wndProc)\n            self.old_windProc = SetWindowLong_wrapper(\n                self.hwnd, GWL_WNDPROC, self.new_windProc)\n\n        def update(self, dispatch_fn):\n            while True:\n\n                try:\n                    etype, x, y = self.pen_events.pop()\n                except:\n                    break\n\n                if etype == 'begin':\n                    self.uid += 1\n                    self.pen = WM_Pen(self.device, self.uid, [x, y])\n                elif etype == 'update':\n                    self.pen.move([x, y])\n                elif etype == 'end':\n                    self.pen.update_time_end()\n\n                dispatch_fn(etype, self.pen)\n\n        def stop(self):\n            self.pen = None\n            SetWindowLong_wrapper(self.hwnd, GWL_WNDPROC, self.old_windProc)\n\n    MotionEventFactory.register('wm_pen', WM_PenProvider)\n"
  },
  {
    "path": "tickeys/kivy/input/providers/wm_touch.py",
    "content": "'''\nSupport for WM_TOUCH messages (Windows platform)\n================================================\n'''\n\n__all__ = ('WM_MotionEventProvider', 'WM_MotionEvent')\n\nimport os\nfrom kivy.input.providers.wm_common import (\n    WM_TABLET_QUERYSYSTEMGESTURE,\n    GWL_WNDPROC, QUERYSYSTEMGESTURE_WNDPROC, WM_TOUCH, WM_MOUSEMOVE,\n    WM_MOUSELAST, PEN_OR_TOUCH_MASK, PEN_OR_TOUCH_SIGNATURE,\n    PEN_EVENT_TOUCH_MASK, TOUCHEVENTF_UP, TOUCHEVENTF_DOWN,\n    TOUCHEVENTF_MOVE, SM_CYCAPTION)\nfrom kivy.input.motionevent import MotionEvent\nfrom kivy.input.shape import ShapeRect\n\n\nclass WM_MotionEvent(MotionEvent):\n    '''MotionEvent representing the WM_MotionEvent event.\n       Supports pos, shape and size profiles.\n    '''\n    __attrs__ = ('size', )\n\n    def depack(self, args):\n        self.is_touch = True\n        self.shape = ShapeRect()\n        self.sx, self.sy = args[0], args[1]\n        self.shape.width = args[2][0]\n        self.shape.height = args[2][1]\n        self.size = self.shape.width * self.shape.height\n        self.profile = ('pos', 'shape', 'size')\n\n        super(WM_MotionEvent, self).depack(args)\n\n    def __str__(self):\n        args = (self.id, self.uid, str(self.spos), self.device)\n        return '<WMMotionEvent id:%d uid:%d pos:%s device:%s>' % args\n\nif 'KIVY_DOC' in os.environ:\n    # documentation hack\n    WM_MotionEventProvider = None\n\nelse:\n    from ctypes.wintypes import (ULONG, HANDLE, DWORD, LONG, UINT,\n                                 WPARAM, LPARAM, BOOL)\n    from ctypes import (windll, WINFUNCTYPE, POINTER,\n                        c_int, Structure, sizeof, byref)\n    from collections import deque\n    from kivy.input.provider import MotionEventProvider\n    from kivy.input.factory import MotionEventFactory\n\n    # check availability of RegisterTouchWindow\n    if not hasattr(windll.user32, 'RegisterTouchWindow'):\n        raise Exception('Unsupported Window version')\n\n    LRESULT = LPARAM\n    WNDPROC = WINFUNCTYPE(LRESULT, HANDLE, UINT, WPARAM, LPARAM)\n\n    class TOUCHINPUT(Structure):\n        _fields_ = [\n            ('x', LONG),\n            ('y', LONG),\n            ('pSource', HANDLE),\n            ('id', DWORD),\n            ('flags', DWORD),\n            ('mask', DWORD),\n            ('time', DWORD),\n            ('extraInfo', POINTER(ULONG)),\n            ('size_x', DWORD),\n            ('size_y', DWORD)]\n\n        def size(self):\n            return (self.size_x, self.size_y)\n\n        def screen_x(self):\n            return self.x / 100.0\n\n        def screen_y(self):\n            return self.y / 100.0\n\n        def _event_type(self):\n            if self.flags & TOUCHEVENTF_MOVE:\n                return 'update'\n            if self.flags & TOUCHEVENTF_DOWN:\n                return 'begin'\n            if self.flags & TOUCHEVENTF_UP:\n                return 'end'\n        event_type = property(_event_type)\n\n    class RECT(Structure):\n        _fields_ = [\n            ('left', LONG),\n            ('top', LONG),\n            ('right', LONG),\n            ('bottom', LONG)]\n\n        x = property(lambda self: self.left)\n        y = property(lambda self: self.top)\n        w = property(lambda self: self.right - self.left)\n        h = property(lambda self: self.bottom - self.top)\n\n    try:\n        windll.user32.SetWindowLongPtrW.restype = WNDPROC\n        windll.user32.SetWindowLongPtrW.argtypes = [HANDLE, c_int, WNDPROC]\n        SetWindowLong_wrapper = windll.user32.SetWindowLongPtrW\n    except AttributeError:\n        windll.user32.SetWindowLongW.restype = WNDPROC\n        windll.user32.SetWindowLongW.argtypes = [HANDLE, c_int, WNDPROC]\n        SetWindowLong_wrapper = windll.user32.SetWindowLongW\n\n    windll.user32.GetMessageExtraInfo.restype = LPARAM\n    windll.user32.GetMessageExtraInfo.argtypes = []\n    windll.user32.GetClientRect.restype = BOOL\n    windll.user32.GetClientRect.argtypes = [HANDLE, POINTER(RECT)]\n    windll.user32.GetWindowRect.restype = BOOL\n    windll.user32.GetWindowRect.argtypes = [HANDLE, POINTER(RECT)]\n    windll.user32.CallWindowProcW.restype = LRESULT\n    windll.user32.CallWindowProcW.argtypes = [WNDPROC, HANDLE, UINT, WPARAM,\n                                              LPARAM]\n    windll.user32.GetActiveWindow.restype = HANDLE\n    windll.user32.GetActiveWindow.argtypes = []\n    windll.user32.RegisterTouchWindow.restype = BOOL\n    windll.user32.RegisterTouchWindow.argtypes = [HANDLE, ULONG]\n    windll.user32.UnregisterTouchWindow.restype = BOOL\n    windll.user32.UnregisterTouchWindow.argtypes = [HANDLE]\n    windll.user32.GetTouchInputInfo.restype = BOOL\n    windll.user32.GetTouchInputInfo.argtypes = [HANDLE, UINT,\n                                                POINTER(TOUCHINPUT), c_int]\n    windll.user32.GetSystemMetrics.restype = c_int\n    windll.user32.GetSystemMetrics.argtypes = [c_int]\n\n    class WM_MotionEventProvider(MotionEventProvider):\n\n        def start(self):\n            self.touch_events = deque()\n            self.touches = {}\n            self.uid = 0\n\n            # get window handle, and register to recive WM_TOUCH messages\n            self.hwnd = windll.user32.GetActiveWindow()\n            windll.user32.RegisterTouchWindow(self.hwnd, 1)\n\n            # inject our own wndProc to handle messages\n            # before window manager does\n            self.new_windProc = WNDPROC(self._touch_wndProc)\n            self.old_windProc = SetWindowLong_wrapper(\n                self.hwnd, GWL_WNDPROC, self.new_windProc)\n\n            self.caption_size = windll.user32.GetSystemMetrics(SM_CYCAPTION)\n\n        def update(self, dispatch_fn):\n            win_rect = RECT()\n            windll.user32.GetWindowRect(self.hwnd, byref(win_rect))\n            caption = self.caption_size\n\n            while True:\n                try:\n                    t = self.touch_events.pop()\n                except:\n                    break\n\n                # adjust x,y to window coordinates (0.0 to 1.0)\n                x = (t.screen_x() - win_rect.x) / float(win_rect.w)\n                y = 1.0 - (t.screen_y() - win_rect.y - caption\n                           ) / float(win_rect.h)\n\n                # actually dispatch input\n                if t.event_type == 'begin':\n                    self.uid += 1\n                    self.touches[t.id] = WM_MotionEvent(\n                        self.device, self.uid, [x, y, t.size()])\n                    dispatch_fn('begin', self.touches[t.id])\n\n                if t.event_type == 'update' and t.id in self.touches:\n                    self.touches[t.id].move([x, y, t.size()])\n                    dispatch_fn('update', self.touches[t.id])\n\n                if t.event_type == 'end' and t.id in self.touches:\n                    touch = self.touches[t.id]\n                    touch.move([x, y, t.size()])\n                    touch.update_time_end()\n                    dispatch_fn('end', touch)\n                    del self.touches[t.id]\n\n        def stop(self):\n            windll.user32.UnregisterTouchWindow(self.hwnd)\n            self.new_windProc = SetWindowLong_wrapper(\n                self.hwnd, GWL_WNDPROC, self.old_windProc)\n\n        # we inject this wndProc into our main window, to process\n        # WM_TOUCH and mouse messages before the window manager does\n        def _touch_wndProc(self, hwnd, msg, wParam, lParam):\n            done = False\n            if msg == WM_TABLET_QUERYSYSTEMGESTURE:\n                return QUERYSYSTEMGESTURE_WNDPROC\n\n            if msg == WM_TOUCH:\n                done = self._touch_handler(msg, wParam, lParam)\n\n            if msg >= WM_MOUSEMOVE and msg <= WM_MOUSELAST:\n                done = self._mouse_handler(msg, wParam, lParam)\n\n            if not done:\n                return windll.user32.CallWindowProcW(self.old_windProc,\n                                                     hwnd, msg, wParam,\n                                                     lParam)\n            return 1\n\n        # this on pushes WM_TOUCH messages onto our event stack\n        def _touch_handler(self, msg, wParam, lParam):\n            touches = (TOUCHINPUT * wParam)()\n            windll.user32.GetTouchInputInfo(HANDLE(lParam),\n                                            wParam,\n                                            touches,\n                                            sizeof(TOUCHINPUT))\n            for i in range(wParam):\n                self.touch_events.appendleft(touches[i])\n            return True\n\n        # filter fake mouse events, because touch and stylus\n        # also make mouse events\n        def _mouse_handler(self, msg, wparam, lParam):\n            info = windll.user32.GetMessageExtraInfo()\n            # its a touch or a pen\n            if (info & PEN_OR_TOUCH_MASK) == PEN_OR_TOUCH_SIGNATURE:\n                if info & PEN_EVENT_TOUCH_MASK:\n                    return True\n\n    MotionEventFactory.register('wm_touch', WM_MotionEventProvider)\n"
  },
  {
    "path": "tickeys/kivy/input/recorder.py",
    "content": "'''\nInput recorder\n==============\n\n.. versionadded:: 1.1.0\n\n.. warning::\n\n    This part of Kivy is still experimental and this API is subject to\n    change in a future version.\n\nThis is a class that can record and replay some input events. This can\nbe used for test cases, screen savers etc.\n\nOnce activated, the recorder will listen for any input event and save its\nproperties in a file with the delta time. Later, you can play the input\nfile: it will generate fake touch events with the saved properties and\ndispatch it to the event loop.\n\nBy default, only the position is saved ('pos' profile and 'sx', 'sy',\nattributes). Change it only if you understand how input handling works.\n\nRecording events\n----------------\n\nThe best way is to use the \"recorder\" module. Check the :doc:`api-kivy.modules`\ndocumentation to see how to activate a module.\n\nOnce activated, you can press F8 to start the recording. By default,\nevents will be written to `<currentpath>/recorder.kvi`. When you want to\nstop recording, press F8 again.\n\nYou can replay the file by pressing F7.\n\nCheck the :doc:`api-kivy.modules.recorder` module for more information.\n\nManual play\n-----------\n\nYou can manually open a recorder file, and play it by doing::\n\n    from kivy.input.recorder import Recorder\n\n    rec = Recorder(filename='myrecorder.kvi')\n    rec.play = True\n\nIf you want to loop over that file, you can do::\n\n\n    from kivy.input.recorder import Recorder\n\n    def recorder_loop(instance, value):\n        if value is False:\n            instance.play = True\n\n    rec = Recorder(filename='myrecorder.kvi')\n    rec.bind(play=recorder_loop)\n    rec.play = True\n\nRecording more attributes\n-------------------------\n\nYou can extend the attributes to save on one condition: attributes values must\nbe simple values, not instances of complex classes.\n\nLet's say you want to save the angle and pressure of the touch, if available::\n\n    from kivy.input.recorder import Recorder\n\n    rec = Recorder(filename='myrecorder.kvi',\n        record_attrs=['is_touch', 'sx', 'sy', 'angle', 'pressure'],\n        record_profile_mask=['pos', 'angle', 'pressure'])\n    rec.record = True\n\nOr with modules variables::\n\n    $ python main.py -m recorder,attrs=is_touch:sx:sy:angle:pressure,\\\n            profile_mask=pos:angle:pressure\n\nKnown limitations\n-----------------\n\n  - Unable to save attributes with instances of complex classes.\n  - Values that represent time will not be adjusted.\n  - Can replay only complete records. If a begin/update/end event is missing,\n    this could lead to ghost touches.\n  - Stopping the replay before the end can lead to ghost touches.\n\n'''\n\n__all__ = ('Recorder', )\n\nfrom os.path import exists\nfrom time import time\nfrom kivy.event import EventDispatcher\nfrom kivy.properties import ObjectProperty, BooleanProperty, StringProperty, \\\n    NumericProperty, ListProperty\nfrom kivy.input.motionevent import MotionEvent\nfrom kivy.base import EventLoop\nfrom kivy.logger import Logger\nfrom ast import literal_eval\nfrom functools import partial\n\n\nclass RecorderMotionEvent(MotionEvent):\n\n    def depack(self, args):\n        for key, value in list(args.items()):\n            setattr(self, key, value)\n        super(RecorderMotionEvent, self).depack(args)\n\n\nclass Recorder(EventDispatcher):\n    '''Recorder class. Please check module documentation for more information.\n    '''\n\n    window = ObjectProperty(None)\n    '''Window instance to attach the recorder. If None, it will use the\n    default instance.\n\n    :attr:`window` is a :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    counter = NumericProperty(0)\n    '''Number of events recorded in the last session.\n\n    :attr:`counter` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 0, read-only.\n    '''\n\n    play = BooleanProperty(False)\n    '''Boolean to start/stop the replay of the current file (if it exists).\n\n    :attr:`play` is a :class:`~kivy.properties.BooleanProperty` and defaults to\n    False.\n    '''\n\n    record = BooleanProperty(False)\n    '''Boolean to start/stop the recording of input events.\n\n    :attr:`record` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    filename = StringProperty('recorder.kvi')\n    '''Filename to save the output of the recorder.\n\n    :attr:`filename` is a :class:`~kivy.properties.StringProperty` and defaults\n    to 'recorder.kvi'.\n    '''\n\n    record_attrs = ListProperty(['is_touch', 'sx', 'sy'])\n    '''Attributes to record from the motion event.\n\n    :attr:`record_attrs` is a :class:`~kivy.properties.ListProperty` and\n    defaults to ['is_touch', 'sx', 'sy'].\n    '''\n\n    record_profile_mask = ListProperty(['pos'])\n    '''Profile to save in the fake motion event when replayed.\n\n    :attr:`record_profile_mask` is a :class:`~kivy.properties.ListProperty` and\n    defaults to ['pos'].\n    '''\n\n    # internals\n    record_fd = ObjectProperty(None)\n    record_time = NumericProperty(0.)\n\n    def __init__(self, **kwargs):\n        super(Recorder, self).__init__(**kwargs)\n        if self.window is None:\n            # manually set the current window\n            from kivy.core.window import Window\n            self.window = Window\n        self.window.bind(\n            on_motion=self.on_motion,\n            on_key_up=partial(self.on_keyboard, 'keyup'),\n            on_key_down=partial(self.on_keyboard, 'keydown'),\n            on_keyboard=partial(self.on_keyboard, 'keyboard'))\n\n    def on_motion(self, window, etype, motionevent):\n        if not self.record:\n            return\n\n        args = dict((arg, getattr(motionevent, arg))\n                    for arg in self.record_attrs if hasattr(motionevent, arg))\n\n        args['profile'] = [x for x in motionevent.profile if x in\n                           self.record_profile_mask]\n        self.record_fd.write('%r\\n' % (\n            (time() - self.record_time, etype, motionevent.uid, args), ))\n        self.counter += 1\n\n    def on_keyboard(self, etype, window, key, *args, **kwargs):\n        if not self.record:\n            return\n        self.record_fd.write('%r\\n' % (\n            (time() - self.record_time, etype, 0, {\n                'key': key,\n                'scancode': kwargs.get('scancode'),\n                'codepoint': kwargs.get('codepoint', kwargs.get('unicode')),\n                'modifier': kwargs.get('modifier'),\n                'is_touch': False}), ))\n        self.counter += 1\n\n    def release(self):\n        self.window.unbind(\n            on_motion=self.on_motion,\n            on_key_up=self.on_keyboard,\n            on_key_down=self.on_keyboard)\n\n    def on_record(self, instance, value):\n        if value:\n            # generate a record filename\n            self.counter = 0\n            self.record_time = time()\n            self.record_fd = open(self.filename, 'w')\n            self.record_fd.write('#RECORDER1.0\\n')\n            Logger.info('Recorder: Recording inputs to %r' % self.filename)\n        else:\n            self.record_fd.close()\n            Logger.info('Recorder: Recorded %d events in %r' % (self.counter,\n                                                                self.filename))\n\n    # needed for acting as an input provider\n    def stop(self):\n        pass\n\n    def start(self):\n        pass\n\n    def on_play(self, instance, value):\n        if not value:\n            Logger.info('Recorder: Stop playing %r' % self.filename)\n            EventLoop.remove_input_provider(self)\n            return\n        if not exists(self.filename):\n            Logger.error('Recorder: Unable to found %r file, play aborted.' % (\n                self.filename))\n            return\n\n        with open(self.filename, 'r') as fd:\n            data = fd.read().splitlines()\n\n        if len(data) < 2:\n            Logger.error('Recorder: Unable to play %r, file truncated.' % (\n                self.filename))\n            return\n\n        if data[0] != '#RECORDER1.0':\n            Logger.error('Recorder: Unable to play %r, invalid header.' % (\n                self.filename))\n            return\n\n        # decompile data\n        self.play_data = [literal_eval(x) for x in data[1:]]\n        self.play_time = time()\n        self.play_me = {}\n        Logger.info('Recorder: Start playing %d events from %r' %\n                    (len(self.play_data), self.filename))\n        EventLoop.add_input_provider(self)\n\n    def update(self, dispatch_fn):\n        if not self.play_data:\n            Logger.info('Recorder: Playing finished.')\n            self.play = False\n\n        dt = time() - self.play_time\n        while self.play_data:\n            event = self.play_data[0]\n            assert(len(event) == 4)\n            if event[0] > dt:\n                return\n\n            me = None\n            etype, uid, args = event[1:]\n            if etype == 'begin':\n                me = RecorderMotionEvent('recorder', uid, args)\n                self.play_me[uid] = me\n            elif etype == 'update':\n                me = self.play_me[uid]\n                me.depack(args)\n            elif etype == 'end':\n                me = self.play_me.pop(uid)\n                me.depack(args)\n            elif etype == 'keydown':\n                self.window.dispatch(\n                    'on_key_down',\n                    args['key'],\n                    args['scancode'],\n                    args['codepoint'],\n                    args['modifier'])\n            elif etype == 'keyup':\n                self.window.dispatch(\n                    'on_key_up',\n                    args['key'],\n                    args['scancode'],\n                    args['codepoint'],\n                    args['modifier'])\n            elif etype == 'keyboard':\n                self.window.dispatch(\n                    'on_keyboard',\n                    args['key'],\n                    args['scancode'],\n                    args['codepoint'],\n                    args['modifier'])\n\n            if me:\n                dispatch_fn(etype, me)\n\n            self.play_data.pop(0)\n\n\ndef start(win, ctx):\n    ctx.recorder = Recorder(window=win)\n\n\ndef stop(win, ctx):\n    if hasattr(ctx, 'recorder'):\n        ctx.recorder.release()\n"
  },
  {
    "path": "tickeys/kivy/input/shape.py",
    "content": "'''\nMotion Event Shape\n==================\n\nRepresent the shape of the :class:`~kivy.input.motionevent.MotionEvent`\n'''\n\n__all__ = ('Shape', 'ShapeRect')\n\n\nclass Shape(object):\n    '''Abstract class for all implementations of a shape'''\n    pass\n\n\nclass ShapeRect(Shape):\n    '''Class for the representation of a rectangle.'''\n    __slots__ = ('width', 'height')\n\n    def __init__(self):\n        super(ShapeRect, self).__init__()\n\n        #: Width fo the rect\n        self.width = 0\n\n        #: Height of the rect\n        self.height = 0\n"
  },
  {
    "path": "tickeys/kivy/interactive.py",
    "content": "'''\nInteractive launcher\n====================\n\n.. versionadded:: 1.3.0\n\nThe :class:`InteractiveLauncher` provides a user-friendly python shell\ninterface to an :class:`App` so that it can be prototyped and debugged\ninteractively.\n\n.. note::\n\n    The Kivy API intends for some functions to only be run once or before the\n    main EventLoop has started. Methods that can normally be called during the\n    course of an application will work as intended, but specifically overriding\n    methods such as :meth:`on_touch` dynamically leads to trouble.\n\nCreating an InteractiveLauncher\n-------------------------------\n\nTake your existing subclass of :class:`App` (this can be production code) and\npass an instance to the :class:`InteractiveLauncher` constructor.::\n\n    from kivy.interactive import InteractiveLauncher\n    from kivy.app import App\n    from kivy.uix.button import Button\n\n    class MyApp(App):\n        def build(self):\n            return Button(test='Hello Shell')\n\n    launcher = InteractiveLauncher(MyApp())\n    launcher.run()\n\nAfter pressing *enter*, the script will return. This allows the interpreter to\ncontinue running. Inspection or modification of the :class:`App` can be done\nsafely through the InteractiveLauncher instance or the provided\n:class:`SafeMembrane` class instances.\n\n.. note::\n\n    If you want to test this example, start Python without any file to have\n    already an interpreter, and copy/paste all the lines. You'll still have the\n    interpreter at the end + the kivy application running.\n\nInteractive Development\n-----------------------\n\nIPython provides a fast way to learn the Kivy API. The :class:`App` instance\nand all of it's attributes, including methods and the entire widget tree,\ncan be quickly listed by using the '.' operator and pressing 'tab'. Try this\ncode in an Ipython shell.::\n\n    from kivy.interactive import InteractiveLauncher\n    from kivy.app import App\n    from kivy.uix.widget import Widget\n    from kivy.graphics import Color, Ellipse\n\n    class MyPaintWidget(Widget):\n        def on_touch_down(self, touch):\n            with self.canvas:\n                Color(1, 1, 0)\n                d = 30.\n                Ellipse(pos=(touch.x - d/2, touch.y - d/2), size=(d, d))\n\n\n    class TestApp(App):\n        def build(self):\n            return Widget()\n\n\n    i = InteractiveLauncher(TestApp())\n    i.run()\n    i.       # press 'tab' to list attributes of the app\n    i.root.  # press 'tab' to list attributes of the root widget\n\n    # App is boring. Attach a new widget!\n    i.root.add_widget(MyPaintWidget())\n\n    i.safeIn()\n    # The application is now blocked.\n    # Click on the screen several times.\n    i.safeOut()\n    # The clicks will show up now\n\n    # Erase artwork and start over\n    i.root.canvas.clear()\n\n.. note::\n\n    All of the proxies used in the module store their referent in the\n    :attr:`_ref` attribute, which can be accessed directly if needed, such as\n    for getting doc strings. :func:`help` and :func:`type` will access the\n    proxy, not its referent.\n\nDirectly Pausing the Application\n--------------------------------\n\nBoth the :class:`InteractiveLauncher` and :class:`SafeMembrane` hold internal\nreferences to the :class:`EventLoop`'s 'safe' and 'confirmed'\n:class:`threading.Event` objects. You can use their safing methods to control\nthe application manually.\n\n:meth:`SafeMembrane.safeIn` will cause the application to pause and\n:meth:`SafeMembrane.safeOut` will allow a paused application\nto continue running. This is potentially useful for scripting actions into\nfunctions that need the screen to update etc.\n\n.. note::\n\n    The pausing is implemented via the\n    :class:`Clocks' <kivy.clock.Clock>`\n    :meth:`~kivy.clock.ClockBase.schedule_once` method\n    and occurs before the start of each frame.\n\nAdding Attributes Dynamically\n-----------------------------\n\n.. note::\n\n    This module uses threading and object proxies to encapsulate the running\n    :class:`App`. Deadlocks and memory corruption can occur if making direct\n    references inside the thread without going through the provided proxy(s).\n\nThe :class:`InteractiveLauncher` can have attributes added to it exactly like a\nnormal object and if these were created from outside the membrane, they will\nnot be threadsafe because the external references to them in the python\ninterpreter do not go through InteractiveLauncher's membrane behavior,\ninherited from :class:`SafeMembrane`.\n\nTo threadsafe these external references, simply assign them to\n:class:`SafeMembrane` instances of themselves like so::\n\n    from kivy.interactive import SafeMembrane\n\n    interactiveLauncher.attribute = myNewObject\n    # myNewObject is unsafe\n    myNewObject = SafeMembrane(myNewObject)\n    # myNewObject is now safe. Call at will.\n    myNewObject.method()\n\nTODO\n====\n\nUnit tests, examples, and a better explanation of which methods are safe in a\nrunning application would be nice. All three would be excellent.\n\nCould be re-written with a context-manager style i.e.::\n\n    with safe:\n        foo()\n\nAny use cases besides compacting code?\n\n'''\n\n__all__ = ('SafeMembrane', 'InteractiveLauncher')\n\nfrom kivy.app import App\nfrom kivy.base import EventLoop\nfrom kivy.clock import Clock\nfrom threading import Thread, Event\n\n\ndef safeWait(dt):\n    EventLoop.confirmed.set()\n    EventLoop.safe.wait()\n    EventLoop.confirmed.clear()\n\n\ndef unwrap(ob):\n    while type(ob) == SafeMembrane:\n        ob = ob._ref\n    return ob\n\n\nclass SafeMembrane(object):\n    '''\n    This help is for a proxy object. Did you want help on the proxy's referent\n    instead? Try using help(<instance>._ref)\n\n    The SafeMembrane is a threadsafe proxy that also returns attributes as new\n    thread-safe objects\n    and makes thread-safe method calls, preventing thread-unsafe objects\n    from leaking into the user's environment.\n    '''\n\n    __slots__ = ('_ref', 'safe', 'confirmed')\n\n    def __init__(self, ob, *args, **kwargs):\n        self.confirmed = EventLoop.confirmed\n        self.safe = EventLoop.safe\n        self._ref = ob\n\n    def safeIn(self):\n        \"\"\"Provides a thread-safe entry point for interactive launching.\"\"\"\n        self.safe.clear()\n        Clock.schedule_once(safeWait, -1)\n        self.confirmed.wait()\n\n    def safeOut(self):\n        \"\"\"Provides a thread-safe exit point for interactive launching.\"\"\"\n        self.safe.set()\n\n    def isMethod(self, fn):\n        return type(fn) is type(self.isMethod)\n\n    # Everything from this point on is just a series of thread-safing proxy\n    # methods that make calls against _ref and threadsafe whenever data will be\n    # written to or if a method will be called. SafeMembrane instances should\n    # be unwrapped whenever passing them into the thread\n    #use type() to determine if an object is a SafeMembrane while debugging\n    def __repr__(self):\n        return self._ref.__repr__()\n\n    def __call__(self, *args, **kw):\n        self.safeIn()\n        args = list(map(unwrap, args))\n        for k in list(kw.keys()):\n            kw[k] = unwrap(kw[k])\n        r = self._ref(*args, **kw)\n        self.safeOut()\n        if r is not None:\n            return SafeMembrane(r)\n\n    def __getattribute__(self, attr, oga=object.__getattribute__):\n        if attr.startswith('__') or attr == '_ref':\n            subject = oga(self, '_ref')\n            if attr == '_ref':\n                return subject\n            return getattr(subject, attr)\n        return oga(self, attr)\n\n    def __getattr__(self, attr, oga=object.__getattribute__):\n        r = getattr(oga(self, '_ref'), attr)\n        return SafeMembrane(r)\n\n    def __setattr__(self, attr, val, osa=object.__setattr__):\n        if (attr == '_ref'\n                or hasattr(type(self), attr) and not attr.startswith('__')):\n            osa(self, attr, val)\n        else:\n            self.safeIn()\n            val = unwrap(val)\n            setattr(self._ref, attr, val)\n            self.safeOut()\n\n    def __delattr__(self, attr, oda=object.__delattr__):\n        self.safeIn()\n        delattr(self._ref, attr)\n        self.safeOut()\n\n    def __bool__(self):\n        return bool(self._ref)\n\n    def __getitem__(self, arg):\n        return SafeMembrane(self._ref[arg])\n\n    def __setitem__(self, arg, val):\n        self.safeIn()\n        val = unwrap(val)\n        self._ref[arg] = val\n        self.safeOut()\n\n    def __delitem__(self, arg):\n        self.safeIn()\n        del self._ref[arg]\n        self.safeOut()\n\n    def __getslice__(self, i, j):\n        return SafeMembrane(self._ref[i:j])\n\n    def __setslice__(self, i, j, val):\n        self.safeIn()\n        val = unwrap(val)\n        self._ref[i:j] = val\n        self.safeOut()\n\n    def __delslice__(self, i, j):\n        self.safeIn()\n        del self._ref[i:j]\n        self.safeOut()\n\n    def __enter__(self, *args, **kwargs):\n        self.safeIn()\n        self._ref.__enter__(*args, **kwargs)\n\n    def __exit__(self, *args, **kwargs):\n        self._ref.__exit__(*args, **kwargs)\n        self.safeOut()\n\n\nclass InteractiveLauncher(SafeMembrane):\n    '''\n    Proxy to an application instance that launches it in a thread and\n    then returns and acts as a proxy to the application in the thread.\n    '''\n\n    __slots__ = ('_ref', 'safe', 'confirmed', 'thread', 'app')\n\n    def __init__(self, app=None, *args, **kwargs):\n        if app is None:\n            app = App()\n        EventLoop.safe = Event()\n        self.safe = EventLoop.safe\n        self.safe.set()\n        EventLoop.confirmed = Event()\n        self.confirmed = EventLoop.confirmed\n        self.app = app\n\n        def startApp(app=app, *args, **kwargs):\n            app.run(*args, **kwargs)\n\n        self.thread = Thread(target=startApp, *args, **kwargs)\n\n    def run(self):\n        self.thread.start()\n        #Proxy behavior starts after this is set. Before this point, attaching\n        #widgets etc can only be done through the Launcher's app attribute\n        self._ref = self.app\n\n    def stop(self):\n        EventLoop.quit = True\n        self.thread.join()\n\n    #Act like the app instance even before _ref is set\n    def __repr__(self):\n        return self.app.__repr__()\n"
  },
  {
    "path": "tickeys/kivy/lang.py",
    "content": "'''Kivy Language\n=============\n\nThe Kivy language is a language dedicated to describing user interface and\ninteractions. You could compare this language to Qt's QML\n(http://qt.nokia.com), but we included new concepts such as rule definitions\n(which are somewhat akin to what you may know from CSS), templating and so on.\n\n.. versionchanged:: 1.7.0\n\n    The Builder doesn't execute canvas expressions in realtime anymore. It will\n    pack all the expressions that need to be executed first and execute them\n    after dispatching input, just before drawing the frame. If you want to\n    force the execution of canvas drawing, just call\n    :meth:`Builder.sync <BuilderBase.sync>`.\n\n    An experimental profiling tool for the kv lang is also included. You can\n    activate it by setting the environment variable `KIVY_PROFILE_LANG=1`.\n    It will then generate an html file named `builder_stats.html`.\n\nOverview\n--------\n\nThe language consists of several constructs that you can use:\n\n    Rules\n        A rule is similar to a CSS rule. A rule applies to specific widgets (or\n        classes thereof) in your widget tree and modifies them in a\n        certain way.\n        You can use rules to specify interactive behaviour or use them to add\n        graphical representations of the widgets they apply to.\n        You can target a specific class of widgets (similar to the CSS\n        concept of a *class*) by using the ``cls`` attribute (e.g.\n        ``cls=MyTestWidget``).\n\n    A Root Widget\n        You can use the language to create your entire user interface.\n        A kv file must contain only one root widget at most.\n\n    Dynamic Classes\n        *(introduced in version 1.7.0)*\n        Dynamic classes let you create new widgets and rules on-the-fly,\n        without any Python declaration.\n\n    Templates (deprecated)\n        *(introduced in version 1.0.5, deprecated from version 1.7.0)*\n        Templates were used to populate parts of an application, such as\n        styling the content of a list (e.g. icon on the left, text on the\n        right). They are now deprecated by dynamic classes.\n\n\nSyntax of a kv File\n-------------------\n\n.. highlight:: kv\n\nA Kivy language file must have ``.kv`` as filename extension.\n\nThe content of the file should always start with the Kivy header, where\n`version` must be replaced with the Kivy language version you're using.\nFor now, use 1.0::\n\n    #:kivy `1.0`\n\n    # content here\n\nThe `content` can contain rule definitions, a root widget, dynamic class\ndefinitions and templates::\n\n    # Syntax of a rule definition. Note that several Rules can share the same\n    # definition (as in CSS). Note the braces: they are part of the definition.\n    <Rule1,Rule2>:\n        # .. definitions ..\n\n    <Rule3>:\n        # .. definitions ..\n\n    # Syntax for creating a root widget\n    RootClassName:\n        # .. definitions ..\n\n    # Syntax for creating a dynamic class\n    <NewWidget@BaseClass>:\n        # .. definitions ..\n\n    # Syntax for create a template\n    [TemplateName@BaseClass1,BaseClass2]:\n        # .. definitions ..\n\nRegardless of whether it's a rule, root widget, dynamic class or\ntemplate you're defining, the definition should look like this::\n\n    # With the braces it's a rule. Without them, it's a root widget.\n    <ClassName>:\n        prop1: value1\n        prop2: value2\n\n        canvas:\n            CanvasInstruction1:\n                canvasprop1: value1\n            CanvasInstruction2:\n                canvasprop2: value2\n\n        AnotherClass:\n            prop3: value1\n\nHere `prop1` and `prop2` are the properties of `ClassName` and `prop3` is the\nproperty of `AnotherClass`. If the widget doesn't have a property with\nthe given name, an :class:`~kivy.properties.ObjectProperty` will be\nautomatically created and added to the widget.\n\n`AnotherClass` will be created and added as a child of the `ClassName`\ninstance.\n\n- The indentation is important and must be consistent. The spacing must be a\n  multiple of the number of spaces used on the first indented line. Spaces\n  are encouraged: mixing tabs and spaces is not recommended.\n- The value of a property must be given on a single line (for now at least).\n- The `canvas` property is special: you can put graphics instructions in it\n  to create a graphical representation of the current class.\n\n\nHere is a simple example of a kv file that contains a root widget::\n\n    #:kivy 1.0\n\n    Button:\n        text: 'Hello world'\n\n\n.. versionchanged:: 1.7.0\n\n    The indentation is not limited to 4 spaces anymore. The spacing must be a\n    multiple of the number of spaces used on the first indented line.\n\nBoth the :meth:`~BuilderBase.load_file` and the\n:meth:`~BuilderBase.load_string` methods\nreturn the root widget defined in your kv file/string. They will also add any\nclass and template definitions to the :class:`~kivy.factory.Factory` for later\nusage.\n\nValue Expressions, on_property Expressions, ids and Reserved Keywords\n---------------------------------------------------------------------\n\nWhen you specify a property's value, the value is evaluated as a Python\nexpression. This expression can be static or dynamic, which means that\nthe value can use the values of other properties using reserved keywords.\n\n    self\n        The keyword self references the \"current widget instance\"::\n\n            Button:\n                text: 'My state is %s' % self.state\n\n    root\n        This keyword is available only in rule definitions and represents the\n        root widget of the rule (the first instance of the rule)::\n\n            <MyWidget>:\n                custom: 'Hello world'\n                Button:\n                    text: root.custom\n\n    app\n        This keyword always refers to your app instance. It's equivalent\n        to a call to :meth:`kivy.app.App.get_running_app` in Python.::\n\n            Label:\n                text: app.name\n\n    args\n        This keyword is available in on_<action> callbacks. It refers to the\n        arguments passed to the callback.::\n\n            TextInput:\n                on_focus: self.insert_text(\"Focus\" if args[1] else \"No focus\")\n\nids\n~~~\n\nClass definitions may contain ids which can be used as a keywords:::\n\n    <MyWidget>:\n        Button:\n            id: btn1\n        Button:\n            text: 'The state of the other button is %s' % btn1.state\n\nPlease note that the `id` will not be available in the widget instance:\nit is used exclusively for external references. `id` is a weakref to the\nwidget, and not the widget itself. The widget itself can be accessed\nwith `id.__self__` (`btn1.__self__` in this case).\n\nWhen the kv file is processed, weakrefs to all the widgets tagged with ids are\nadded to the root widgets `ids` dictionary. In other words, following on from\nthe example above, the buttons state could also be accessed as follows:\n\n.. code-block:: python\n\n    widget = MyWidget()\n    state = widget.ids[\"btn1\"].state\n\n    # Or, as an alternative syntax,\n    state = widget.ids.btn1.state\n\nNote that the outermost widget applies the kv rules to all its inner widgets\nbefore any other rules are applied. This means if an inner widget contains ids,\nthese ids may not be available during the inner widget's `__init__` function.\n\nValid expressons\n~~~~~~~~~~~~~~~~\n\nThere are two places that accept python statments in a kv file:\nafter a property, which assigns to the property the result of the expression\n(such as the text of a button as shown above) and after a on_property, which\nexecutes the statement when the property is updated (such as on_state).\n\nIn the former case, the\n`expression <http://docs.python.org/2/reference/expressions.html>`_ can only\nspan a single line, cannot be extended to multiple lines using newline\nescaping, and must return a value. An example of a valid expression is\n``text: self.state and ('up' if self.state == 'normal' else 'down')``.\n\nIn the latter case, multiple single line statements are valid including\nmulti-line statements that escape their newline, as long as they don't\nadd an indentation level.\n\nExamples of valid statements are:\n\n.. code-block:: python\n\n    on_press: if self.state == 'normal': print('normal')\n    on_state:\n        if self.state == 'normal': print('normal')\n        else: print('down')\n        if self.state == 'normal': \\\\\n        print('multiline normal')\n        for i in range(10): print(i)\n        print([1,2,3,4,\n        5,6,7])\n\nAn example of a invalid statement:\n\n.. code-block:: python\n\n    on_state:\n        if self.state == 'normal':\n            print('normal')\n\nRelation Between Values and Properties\n--------------------------------------\n\nWhen you use the Kivy language, you might notice that we do some work\nbehind the scenes to automatically make things work properly. You should\nknow that :doc:`api-kivy.properties` implement the\n`Observer Design Pattern <http://en.wikipedia.org/wiki/Observer_pattern>`_.\nThat means that you can bind your own function to be\ncalled when the value of a property changes (i.e. you passively\n`observe` the property for potential changes).\n\nThe Kivy language detects properties in your `value` expression and will create\ncreate callbacks to automatically update the property via your expression when\nchanges occur.\n\nHere's a simple example that demonstrates this behaviour::\n\n    Button:\n        text: str(self.state)\n\nIn this example, the parser detects that `self.state` is a dynamic value (a\nproperty). The :attr:`~kivy.uix.button.Button.state` property of the button\ncan change at any moment (when the user touches it).\nWe now want this button to display its own state as text, even as the state\nchanges. To do this, we use the state property of the Button and use it in the\nvalue expression for the button's `text` property, which controls what text is\ndisplayed on the button (We also convert the state to a string representation).\nNow, whenever the button state changes, the text property will be updated\nautomatically.\n\nRemember: The value is a python expression! That means that you can do\nsomething more interesting like::\n\n    Button:\n        text: 'Plop world' if self.state == 'normal' else 'Release me!'\n\nThe Button text changes with the state of the button. By default, the button\ntext will be 'Plop world', but when the button is being pressed, the text will\nchange to 'Release me!'.\n\nMore precisely, the kivy language parser detects all substrings of the form\n`X.a.b` where `X` is `self` or `root` or `app` or a known id, and `a` and `b`\nare properties: it then adds the appropriate dependencies to cause the\nthe constraint to be reevaluated whenever something changes. For example,\nthis works exactly as expected::\n\n    <IndexedExample>:\n        beta: self.a.b[self.c.d]\n\nHowever, due to limitations in the parser which hopefully may be lifted in the\nfuture, the following doesn't work::\n\n    <BadExample>:\n        beta: self.a.b[self.c.d].e.f\n\nindeed the `.e.f` part is not recognized because it doesn't follow the expected\npattern, and so, does not result in an appropriate dependency being setup.\nInstead, an intermediate property should be introduced to allow the following\nconstraint::\n\n    <GoodExample>:\n        alpha: self.a.b[self.c.d]\n        beta: self.alpha.e.f\n\n\nGraphical Instructions\n----------------------\n\nThe graphical instructions are a special part of the Kivy language. They are\nhandled by the 'canvas' property definition::\n\n    Widget:\n        canvas:\n            Color:\n                rgb: (1, 1, 1)\n            Rectangle:\n                size: self.size\n                pos: self.pos\n\nAll the classes added inside the canvas property must be derived from the\n:class:`~kivy.graphics.Instruction` class. You cannot put any Widget class\ninside the canvas property (as that would not make sense because a\nwidget is not a graphics instruction).\n\nIf you want to do theming, you'll have the same question as in CSS: which rules\nhave been executed first? In our case, the rules are executed\nin processing order (i.e. top-down).\n\nIf you want to change how Buttons are rendered, you can create your own kv file\nand add something like this::\n\n    <Button>:\n        canvas:\n            Color:\n                rgb: (1, 0, 0)\n            Rectangle:\n                pos: self.pos\n                size: self.size\n            Rectangle:\n                pos: self.pos\n                size: self.texture_size\n                texture: self.texture\n\nThis will result in buttons having a red background with the label in the\nbottom left, in addition to all the preceding rules.\nYou can clear all the previous instructions by using the `Clear` command::\n\n    <Button>:\n        canvas:\n            Clear\n            Color:\n                rgb: (1, 0, 0)\n            Rectangle:\n                pos: self.pos\n                size: self.size\n            Rectangle:\n                pos: self.pos\n                size: self.texture_size\n                texture: self.texture\n\nThen, only your rules that follow the `Clear` command will be taken into\nconsideration.\n\n.. _dynamic_classes:\n\nDynamic classes\n---------------\n\nDynamic classes allow you to create new widgets on-the-fly, without any python\ndeclaration in the first place. The syntax of the dynamic classes is similar to\nthe Rules, but you need to specify the base classes you want to\nsubclass.\n\nThe syntax looks like:\n\n.. code-block:: kv\n\n    # Simple inheritance\n    <NewWidget@Button>:\n        # kv code here ...\n\n    # Multiple inheritance\n    <NewWidget@ButtonBehavior+Label>:\n        # kv code here ...\n\nThe `@` character is used to seperate your class name from the classes you want\nto subclass. The Python equivalent would have been:\n\n.. code-block:: python\n\n    # Simple inheritance\n    class NewWidget(Button):\n        pass\n\n    # Multiple inheritance\n    class NewWidget(ButtonBehavior, Label):\n        pass\n\nAny new properties, usually added in python code, should be declared\nfirst. If the property doesn't exist in the dynamic class, it will be\nautomatically created as an :class:`~kivy.properties.ObjectProperty`\n(pre 1.8.0) or as an appropriate typed property (from version\n1.8.0).\n\n.. versionchanged:: 1.8.0\n\n    If the property value is an expression that can be evaluated right away (no\n    external binding), then the value will be used as default value of the\n    property, and the type of the value will be used for the specialization of\n    the Property class. In other terms: if you declare `hello: \"world\"`, a new\n    :class:`~kivy.properties.StringProperty` will be instantiated, with the\n    default value `\"world\"`. Lists, tuples, dictionaries and strings are\n    supported.\n\nLet's illustrate the usage of these dynamic classes with an\nimplementation of a basic Image button. We could derive our classes from\nthe Button and just add a property for the image filename:\n\n.. code-block:: kv\n\n    <ImageButton@Button>:\n        source: None\n\n        Image:\n            source: root.source\n            pos: root.pos\n            size: root.size\n\n    # let's use the new classes in another rule:\n    <MainUI>:\n        BoxLayout:\n            ImageButton:\n                source: 'hello.png'\n                on_press: root.do_something()\n            ImageButton:\n                source: 'world.png'\n                on_press: root.do_something_else()\n\nIn Python, you can create an instance of the dynamic class as follows:\n\n.. code-block:: python\n\n    from kivy.factory import Factory\n    button_inst = Factory.ImageButton()\n\n.. note::\n\n    Using dynamic classes, a child class can be declared before it's parent.\n    This however, leads to the unintuitive situation where the parent\n    properties/methods override those of the child. Be careful if you choose\n    to do this.\n\n.. _template_usage:\n\nTemplates\n---------\n\n.. versionchanged:: 1.7.0\n\n    Template usage is now deprecated. Please use Dynamic classes instead.\n\nSyntax of templates\n~~~~~~~~~~~~~~~~~~~\n\nUsing a template in Kivy requires 2 things :\n\n    #. a context to pass for the context (will be ctx inside template).\n    #. a kv definition of the template.\n\nSyntax of a template:\n\n.. code-block:: kv\n\n    # With only one base class\n    [ClassName@BaseClass]:\n        # .. definitions ..\n\n    # With more than one base class\n    [ClassName@BaseClass1,BaseClass2]:\n        # .. definitions ..\n\nFor example, for a list, you'll need to create a entry with a image on\nthe left, and a label on the right. You can create a template for making\nthat definition easier to use.\nSo, we'll create a template that uses 2 entries in the context: an image\nfilename and a title:\n\n.. code-block:: kv\n\n    [IconItem@BoxLayout]:\n        Image:\n            source: ctx.image\n        Label:\n            text: ctx.title\n\nThen in Python, you can instantiate the template using:\n\n.. code-block:: python\n\n    from kivy.lang import Builder\n\n    # create a template with hello world + an image\n    # the context values should be passed as kwargs to the Builder.template\n    # function\n    icon1 = Builder.template('IconItem', title='Hello world',\n        image='myimage.png')\n\n    # create a second template with other information\n    ctx = {'title': 'Another hello world',\n           'image': 'myimage2.png'}\n    icon2 = Builder.template('IconItem', **ctx)\n    # and use icon1 and icon2 as other widget.\n\n\nTemplate example\n~~~~~~~~~~~~~~~~\n\nMost of time, when you are creating a screen in the kv lang, you use a lot of\nredefinitions. In our example, we'll create a Toolbar, based on a\nBoxLayout, and put in a few :class:`~kivy.uix.image.Image` widgets that\nwill react to the *on_touch_down* event.:\n\n.. code-block:: kv\n\n    <MyToolbar>:\n        BoxLayout:\n            Image:\n                source: 'data/text.png'\n                size: self.texture_size\n                size_hint: None, None\n                on_touch_down: self.collide_point(*args[1].pos) and\\\n root.create_text()\n\n            Image:\n                source: 'data/image.png'\n                size: self.texture_size\n                size_hint: None, None\n                on_touch_down: self.collide_point(*args[1].pos) and\\\n root.create_image()\n\n            Image:\n                source: 'data/video.png'\n                size: self.texture_size\n                size_hint: None, None\n                on_touch_down: self.collide_point(*args[1].pos) and\\\n root.create_video()\n\nWe can see that the size and size_hint attribute are exactly the same.\nMore than that, the callback in on_touch_down and the image are changing.\nTheses can be the variable part of the template that we can put into a context.\nLet's try to create a template for the Image:\n\n.. code-block:: kv\n\n    [ToolbarButton@Image]:\n\n        # This is the same as before\n        size: self.texture_size\n        size_hint: None, None\n\n        # Now, we are using the ctx for the variable part of the template\n        source: 'data/%s.png' % ctx.image\n        on_touch_down: self.collide_point(*args[1].pos) and ctx.callback()\n\nThe template can be used directly in the MyToolbar rule:\n\n.. code-block:: kv\n\n    <MyToolbar>:\n        BoxLayout:\n            ToolbarButton:\n                image: 'text'\n                callback: root.create_text\n            ToolbarButton:\n                image: 'image'\n                callback: root.create_image\n            ToolbarButton:\n                image: 'video'\n                callback: root.create_video\n\nThat's all :)\n\n\nTemplate limitations\n~~~~~~~~~~~~~~~~~~~~\n\nWhen you are creating a context:\n\n    #. you cannot use references other than \"root\":\n\n        .. code-block:: kv\n\n            <MyRule>:\n                Widget:\n                    id: mywidget\n                    value: 'bleh'\n                Template:\n                    ctxkey: mywidget.value # << fail, this references the id\n                    # mywidget\n\n    #. not all of the dynamic parts will be understood:\n\n        .. code-block:: kv\n\n            <MyRule>:\n                Template:\n                    ctxkey: 'value 1' if root.prop1 else 'value2' # << even if\n                    # root.prop1 is a property, if it changes value, ctxkey\n                    # will not be updated\n\nRedefining a widget's style\n---------------------------\n\nSometimes we would like to inherit from a widget in order to use its Python\nproperties without also using its .kv defined style. For example, we would\nlike to inherit from a Label, but we would also like to define our own\ncanvas instructions instead of automatically using the canvas instructions\ninherited from the Label. We can achieve this by prepending a dash (-) before\nthe class name in the .kv style definition.\n\nIn myapp.py:\n\n.. code-block:: python\n\n    class MyWidget(Label):\n        pass\n\nand in my.kv:\n\n.. code-block:: kv\n\n    <-MyWidget>:\n        canvas:\n            Color:\n                rgb: 1, 1, 1\n            Rectangle:\n                size: (32, 32)\n\nMyWidget will now have a Color and Rectangle instruction in its canvas\nwithout any of the instructions inherited from the Label.\n\nLang Directives\n---------------\n\nYou can use directives to add declarative commands, such as imports or constant\ndefinitions, to the lang files. Directives are added as comments in the\nfollowing format:\n\n.. code-block:: kv\n\n    #:<directivename> <options>\n\nimport <package>\n~~~~~~~~~~~~~~~~\n\n.. versionadded:: 1.0.5\n\nSyntax:\n\n.. code-block:: kv\n\n    #:import <alias> <package>\n\nYou can import a package by writing:\n\n.. code-block:: kv\n\n    #:import os os\n\n    <Rule>:\n        Button:\n            text: os.getcwd()\n\nOr more complex:\n\n.. code-block:: kv\n\n    #:import ut kivy.utils\n\n    <Rule>:\n        canvas:\n            Color:\n                rgba: ut.get_random_color()\n\n.. versionadded:: 1.0.7\n\nYou can directly import classes from a module:\n\n.. code-block:: kv\n\n    #: import Animation kivy.animation.Animation\n    <Rule>:\n        on_prop: Animation(x=.5).start(self)\n\nset <key> <expr>\n~~~~~~~~~~~~~~~~\n\n.. versionadded:: 1.0.6\n\nSyntax:\n\n.. code-block:: kv\n\n    #:set <key> <expr>\n\nSet a key that will be available anywhere in the kv. For example:\n\n.. code-block:: kv\n\n    #:set my_color (.4, .3, .4)\n    #:set my_color_hl (.5, .4, .5)\n\n    <Rule>:\n        state: 'normal'\n        canvas:\n            Color:\n                rgb: my_color if self.state == 'normal' else my_color_hl\n\ninclude <file>\n~~~~~~~~~~~~~~~~\n\n.. versionadded:: 1.9.0\n\nSyntax:\n\n.. code-block:: kv\n\n    #:include [force] <file>\n\nIncludes an external kivy file. This allows you to split complex\nwidgets into their own files. If the include is forced, the file\nwill first be unloaded and then reloaded again. For example:\n\n.. code-block:: kv\n\n    # Test.kv\n    #:include mycomponent.kv\n    #:include force mybutton.kv\n\n    <Rule>:\n        state: 'normal'\n        MyButton:\n        MyComponent:\n\n\n.. code-block:: kv\n\n    # mycomponent.kv\n    #:include mybutton.kv\n\n    <MyComponent>:\n        MyButton:\n\n.. code-block:: kv\n\n    # mybutton.kv\n\n    <MyButton>:\n        canvas:\n            Color:\n                rgb: (1.0, 0.0, 0.0)\n            Rectangle:\n                pos: self.pos\n                size: (self.size[0]/4, self.size[1]/4)\n\n'''\nimport os\n\n__all__ = ('Observable', 'Builder', 'BuilderBase', 'BuilderException', 'Parser',\n           'ParserException')\n\nimport codecs\nimport re\nimport sys\nimport traceback\nimport types\nfrom re import sub, findall\nfrom os import environ\nfrom os.path import join\nfrom copy import copy\nfrom types import CodeType\nfrom functools import partial\nfrom collections import OrderedDict, defaultdict\n\nfrom kivy.factory import Factory\nfrom kivy.logger import Logger\nfrom kivy.utils import QueryDict\nfrom kivy.cache import Cache\nfrom kivy import kivy_data_dir, require\nfrom kivy.compat import PY2, iteritems, iterkeys\nfrom kivy.context import register_context\nfrom kivy.resources import resource_find\nimport kivy.metrics as Metrics\nfrom kivy._event import Observable, EventDispatcher\n\n\ntrace = Logger.trace\nglobal_idmap = {}\n\n# late import\nInstruction = None\n\n# register cache for creating new classtype (template)\nCache.register('kv.lang')\n\n# all previously included files\n__KV_INCLUDES__ = []\n\n# precompile regexp expression\nlang_str = re.compile('([\\'\"][^\\'\"]*[\\'\"])')\nlang_key = re.compile('([a-zA-Z_]+)')\nlang_keyvalue = re.compile('([a-zA-Z_][a-zA-Z0-9_.]*\\.[a-zA-Z0-9_.]+)')\nlang_tr = re.compile('(_\\()')\n\n# class types to check with isinstance\nif PY2:\n    _cls_type = (type, types.ClassType)\nelse:\n    _cls_type = (type, )\n\n# all the widget handlers, used to correctly unbind all the callbacks then the\n# widget is deleted\n_handlers = defaultdict(list)\n\n\nclass ProxyApp(object):\n    # proxy app object\n    # taken from http://code.activestate.com/recipes/496741-object-proxying/\n\n    __slots__ = ['_obj']\n\n    def __init__(self):\n        object.__init__(self)\n        object.__setattr__(self, '_obj', None)\n\n    def _ensure_app(self):\n        app = object.__getattribute__(self, '_obj')\n        if app is None:\n            from kivy.app import App\n            app = App.get_running_app()\n            object.__setattr__(self, '_obj', app)\n            # Clear cached application instance, when it stops\n            app.bind(on_stop=lambda instance:\n                     object.__setattr__(self, '_obj', None))\n        return app\n\n    def __getattribute__(self, name):\n        object.__getattribute__(self, '_ensure_app')()\n        return getattr(object.__getattribute__(self, '_obj'), name)\n\n    def __delattr__(self, name):\n        object.__getattribute__(self, '_ensure_app')()\n        delattr(object.__getattribute__(self, '_obj'), name)\n\n    def __setattr__(self, name, value):\n        object.__getattribute__(self, '_ensure_app')()\n        setattr(object.__getattribute__(self, '_obj'), name, value)\n\n    def __bool__(self):\n        object.__getattribute__(self, '_ensure_app')()\n        return bool(object.__getattribute__(self, '_obj'))\n\n    def __str__(self):\n        object.__getattribute__(self, '_ensure_app')()\n        return str(object.__getattribute__(self, '_obj'))\n\n    def __repr__(self):\n        object.__getattribute__(self, '_ensure_app')()\n        return repr(object.__getattribute__(self, '_obj'))\n\n\nglobal_idmap['app'] = ProxyApp()\nglobal_idmap['pt'] = Metrics.pt\nglobal_idmap['inch'] = Metrics.inch\nglobal_idmap['cm'] = Metrics.cm\nglobal_idmap['mm'] = Metrics.mm\nglobal_idmap['dp'] = Metrics.dp\nglobal_idmap['sp'] = Metrics.sp\n\n\n# delayed calls are canvas expression triggered during an loop. It is one\n# directional linked list of args to call call_fn with. Each element is a list\n# whos last element points to the next list of args to execute when\n# Builder.sync is called.\n_delayed_start = None\n\n\nclass ParserException(Exception):\n    '''Exception raised when something wrong happened in a kv file.\n    '''\n\n    def __init__(self, context, line, message, cause=None):\n        self.filename = context.filename or '<inline>'\n        self.line = line\n        sourcecode = context.sourcecode\n        sc_start = max(0, line - 2)\n        sc_stop = min(len(sourcecode), line + 3)\n        sc = ['...']\n        for x in range(sc_start, sc_stop):\n            if x == line:\n                sc += ['>> %4d:%s' % (line + 1, sourcecode[line][1])]\n            else:\n                sc += ['   %4d:%s' % (x + 1, sourcecode[x][1])]\n        sc += ['...']\n        sc = '\\n'.join(sc)\n\n        message = 'Parser: File \"%s\", line %d:\\n%s\\n%s' % (\n            self.filename, self.line + 1, sc, message)\n        if cause:\n            message += '\\n' + ''.join(traceback.format_tb(cause))\n\n        super(ParserException, self).__init__(message)\n\n\nclass BuilderException(ParserException):\n    '''Exception raised when the Builder failed to apply a rule on a widget.\n    '''\n    pass\n\n\nclass ParserRuleProperty(object):\n    '''Represent a property inside a rule.\n    '''\n\n    __slots__ = ('ctx', 'line', 'name', 'value', 'co_value',\n                 'watched_keys', 'mode', 'count')\n\n    def __init__(self, ctx, line, name, value):\n        super(ParserRuleProperty, self).__init__()\n        #: Associated parser\n        self.ctx = ctx\n        #: Line of the rule\n        self.line = line\n        #: Name of the property\n        self.name = name\n        #: Value of the property\n        self.value = value\n        #: Compiled value\n        self.co_value = None\n        #: Compilation mode\n        self.mode = None\n        #: Watched keys\n        self.watched_keys = None\n        #: Stats\n        self.count = 0\n\n    def precompile(self):\n        name = self.name\n        value = self.value\n\n        # first, remove all the string from the value\n        tmp = sub(lang_str, '', self.value)\n\n        # detecting how to handle the value according to the key name\n        mode = self.mode\n        if self.mode is None:\n            self.mode = mode = 'exec' if name[:3] == 'on_' else 'eval'\n        if mode == 'eval':\n            # if we don't detect any string/key in it, we can eval and give the\n            # result\n            if re.search(lang_key, tmp) is None:\n                self.co_value = eval(value)\n                return\n\n        # ok, we can compile.\n        value = '\\n' * self.line + value\n        self.co_value = compile(value, self.ctx.filename or '<string>', mode)\n\n        # for exec mode, we don't need to watch any keys.\n        if mode == 'exec':\n            return\n\n        # now, detect obj.prop\n        # first, remove all the string from the value\n        tmp = sub(lang_str, '', value)\n        idx = tmp.find('#')\n        if idx != -1:\n            tmp = tmp[:idx]\n        # detect key.value inside value, and split them\n        wk = list(set(findall(lang_keyvalue, tmp)))\n        if len(wk):\n            self.watched_keys = [x.split('.') for x in wk]\n        if findall(lang_tr, tmp):\n            if self.watched_keys:\n                self.watched_keys += [['_']]\n            else:\n                self.watched_keys = [['_']]\n\n    def __repr__(self):\n        return '<ParserRuleProperty name=%r filename=%s:%d ' \\\n               'value=%r watched_keys=%r>' % (\n                   self.name, self.ctx.filename, self.line + 1,\n                   self.value, self.watched_keys)\n\n\nclass ParserRule(object):\n    '''Represents a rule, in terms of the Kivy internal language.\n    '''\n\n    __slots__ = ('ctx', 'line', 'name', 'children', 'id', 'properties',\n                 'canvas_before', 'canvas_root', 'canvas_after',\n                 'handlers', 'level', 'cache_marked', 'avoid_previous_rules')\n\n    def __init__(self, ctx, line, name, level):\n        super(ParserRule, self).__init__()\n        #: Level of the rule in the kv\n        self.level = level\n        #: Associated parser\n        self.ctx = ctx\n        #: Line of the rule\n        self.line = line\n        #: Name of the rule\n        self.name = name\n        #: List of children to create\n        self.children = []\n        #: Id given to the rule\n        self.id = None\n        #: Properties associated to the rule\n        self.properties = OrderedDict()\n        #: Canvas normal\n        self.canvas_root = None\n        #: Canvas before\n        self.canvas_before = None\n        #: Canvas after\n        self.canvas_after = None\n        #: Handlers associated to the rule\n        self.handlers = []\n        #: Properties cache list: mark which class have already been checked\n        self.cache_marked = []\n        #: Indicate if any previous rules should be avoided.\n        self.avoid_previous_rules = False\n\n        if level == 0:\n            self._detect_selectors()\n        else:\n            self._forbid_selectors()\n\n    def precompile(self):\n        for x in self.properties.values():\n            x.precompile()\n        for x in self.handlers:\n            x.precompile()\n        for x in self.children:\n            x.precompile()\n        if self.canvas_before:\n            self.canvas_before.precompile()\n        if self.canvas_root:\n            self.canvas_root.precompile()\n        if self.canvas_after:\n            self.canvas_after.precompile()\n\n    def create_missing(self, widget):\n        # check first if the widget class already been processed by this rule\n        cls = widget.__class__\n        if cls in self.cache_marked:\n            return\n        self.cache_marked.append(cls)\n        for name in self.properties:\n            if hasattr(widget, name):\n                continue\n            value = self.properties[name].co_value\n            if type(value) is CodeType:\n                value = None\n            widget.create_property(name, value)\n\n    def _forbid_selectors(self):\n        c = self.name[0]\n        if c == '<' or c == '[':\n            raise ParserException(\n                self.ctx, self.line,\n                'Selectors rules are allowed only at the first level')\n\n    def _detect_selectors(self):\n        c = self.name[0]\n        if c == '<':\n            self._build_rule()\n        elif c == '[':\n            self._build_template()\n        else:\n            if self.ctx.root is not None:\n                raise ParserException(\n                    self.ctx, self.line,\n                    'Only one root object is allowed by .kv')\n            self.ctx.root = self\n\n    def _build_rule(self):\n        name = self.name\n        if __debug__:\n            trace('Builder: build rule for %s' % name)\n        if name[0] != '<' or name[-1] != '>':\n            raise ParserException(self.ctx, self.line,\n                                  'Invalid rule (must be inside <>)')\n\n        # if the very first name start with a -, avoid previous rules\n        name = name[1:-1]\n        if name[:1] == '-':\n            self.avoid_previous_rules = True\n            name = name[1:]\n\n        rules = name.split(',')\n        for rule in rules:\n            crule = None\n\n            if not len(rule):\n                raise ParserException(self.ctx, self.line,\n                                      'Empty rule detected')\n\n            if '@' in rule:\n                # new class creation ?\n                # ensure the name is correctly written\n                rule, baseclasses = rule.split('@', 1)\n                if not re.match(lang_key, rule):\n                    raise ParserException(self.ctx, self.line,\n                                          'Invalid dynamic class name')\n\n                # save the name in the dynamic classes dict.\n                self.ctx.dynamic_classes[rule] = baseclasses\n                crule = ParserSelectorName(rule)\n\n            else:\n                # classical selectors.\n\n                if rule[0] == '.':\n                    crule = ParserSelectorClass(rule[1:])\n                elif rule[0] == '#':\n                    crule = ParserSelectorId(rule[1:])\n                else:\n                    crule = ParserSelectorName(rule)\n\n            self.ctx.rules.append((crule, self))\n\n    def _build_template(self):\n        name = self.name\n        if __debug__:\n            trace('Builder: build template for %s' % name)\n        if name[0] != '[' or name[-1] != ']':\n            raise ParserException(self.ctx, self.line,\n                                  'Invalid template (must be inside [])')\n        item_content = name[1:-1]\n        if not '@' in item_content:\n            raise ParserException(self.ctx, self.line,\n                                  'Invalid template name (missing @)')\n        template_name, template_root_cls = item_content.split('@')\n        self.ctx.templates.append((template_name, template_root_cls, self))\n\n    def __repr__(self):\n        return '<ParserRule name=%r>' % (self.name, )\n\n\nclass Parser(object):\n    '''Create a Parser object to parse a Kivy language file or Kivy content.\n    '''\n\n    PROP_ALLOWED = ('canvas.before', 'canvas.after')\n    CLASS_RANGE = list(range(ord('A'), ord('Z') + 1))\n    PROP_RANGE = (\n        list(range(ord('A'), ord('Z') + 1)) +\n        list(range(ord('a'), ord('z') + 1)) +\n        list(range(ord('0'), ord('9') + 1)) + [ord('_')])\n\n    __slots__ = ('rules', 'templates', 'root', 'sourcecode',\n                 'directives', 'filename', 'dynamic_classes')\n\n    def __init__(self, **kwargs):\n        super(Parser, self).__init__()\n        self.rules = []\n        self.templates = []\n        self.root = None\n        self.sourcecode = []\n        self.directives = []\n        self.dynamic_classes = {}\n        self.filename = kwargs.get('filename', None)\n        content = kwargs.get('content', None)\n        if content is None:\n            raise ValueError('No content passed')\n        self.parse(content)\n\n    def execute_directives(self):\n        global __KV_INCLUDES__\n        for ln, cmd in self.directives:\n            cmd = cmd.strip()\n            if __debug__:\n                trace('Parser: got directive <%s>' % cmd)\n            if cmd[:5] == 'kivy ':\n                version = cmd[5:].strip()\n                if len(version.split('.')) == 2:\n                    version += '.0'\n                require(version)\n            elif cmd[:4] == 'set ':\n                try:\n                    name, value = cmd[4:].strip().split(' ', 1)\n                except:\n                    Logger.exception('')\n                    raise ParserException(self, ln, 'Invalid directive syntax')\n                try:\n                    value = eval(value)\n                except:\n                    Logger.exception('')\n                    raise ParserException(self, ln, 'Invalid value')\n                global_idmap[name] = value\n            elif cmd[:8] == 'include ':\n                ref = cmd[8:].strip()\n                force_load = False\n\n                if ref[:6] == 'force ':\n                    ref = ref[6:].strip()\n                    force_load = True\n\n                if ref[-3:] != '.kv':\n                    Logger.warn('WARNING: {0} does not have a valid Kivy'\n                                'Language extension (.kv)'.format(ref))\n                    break\n                if ref in __KV_INCLUDES__:\n                    if not os.path.isfile(ref):\n                        raise ParserException(self, ln,\n                            'Invalid or unknown file: {0}'.format(ref))\n                    if not force_load:\n                        Logger.warn('WARNING: {0} has already been included!'\n                                    .format(ref))\n                        break\n                    else:\n                        Logger.debug('Reloading {0} because include was forced.'\n                                    .format(ref))\n                        Builder.unload_file(ref)\n                        Builder.load_file(ref)\n                        continue\n                Logger.debug('Including file: {0}'.format(0))\n                __KV_INCLUDES__.append(ref)\n                Builder.load_file(ref)\n            elif cmd[:7] == 'import ':\n                package = cmd[7:].strip()\n                l = package.split(' ')\n                if len(l) != 2:\n                    raise ParserException(self, ln, 'Invalid import syntax')\n                alias, package = l\n                try:\n                    if package not in sys.modules:\n                        try:\n                            mod = __import__(package)\n                        except ImportError:\n                            mod = __import__('.'.join(package.split('.')[:-1]))\n                        # resolve the whole thing\n                        for part in package.split('.')[1:]:\n                            mod = getattr(mod, part)\n                    else:\n                        mod = sys.modules[package]\n                    global_idmap[alias] = mod\n                except ImportError:\n                    Logger.exception('')\n                    raise ParserException(self, ln,\n                                          'Unable to import package %r' %\n                                          package)\n            else:\n                raise ParserException(self, ln, 'Unknown directive')\n\n    def parse(self, content):\n        '''Parse the contents of a Parser file and return a list\n        of root objects.\n        '''\n        # Read and parse the lines of the file\n        lines = content.splitlines()\n        if not lines:\n            return\n        num_lines = len(lines)\n        lines = list(zip(list(range(num_lines)), lines))\n        self.sourcecode = lines[:]\n\n        if __debug__:\n            trace('Parser: parsing %d lines' % num_lines)\n\n        # Strip all comments\n        self.strip_comments(lines)\n\n        # Execute directives\n        self.execute_directives()\n\n        # Get object from the first level\n        objects, remaining_lines = self.parse_level(0, lines)\n\n        # Precompile rules tree\n        for rule in objects:\n            rule.precompile()\n\n        # After parsing, there should be no remaining lines\n        # or there's an error we did not catch earlier.\n        if remaining_lines:\n            ln, content = remaining_lines[0]\n            raise ParserException(self, ln, 'Invalid data (not parsed)')\n\n    def strip_comments(self, lines):\n        '''Remove all comments from all lines in-place.\n           Comments need to be on a single line and not at the end of a line.\n           i.e. a comment line's first non-whitespace character must be a #.\n        '''\n        # extract directives\n        for ln, line in lines[:]:\n            stripped = line.strip()\n            if stripped[:2] == '#:':\n                self.directives.append((ln, stripped[2:]))\n            if stripped[:1] == '#':\n                lines.remove((ln, line))\n            if not stripped:\n                lines.remove((ln, line))\n\n    def parse_level(self, level, lines, spaces=0):\n        '''Parse the current level (level * spaces) indentation.\n        '''\n        indent = spaces * level if spaces > 0 else 0\n        objects = []\n\n        current_object = None\n        current_property = None\n        current_propobject = None\n        i = 0\n        while i < len(lines):\n            line = lines[i]\n            ln, content = line\n\n            # Get the number of space\n            tmp = content.lstrip(' \\t')\n\n            # Replace any tab with 4 spaces\n            tmp = content[:len(content) - len(tmp)]\n            tmp = tmp.replace('\\t', '    ')\n\n            # first indent designates the indentation\n            if spaces == 0:\n                spaces = len(tmp)\n\n            count = len(tmp)\n\n            if spaces > 0 and count % spaces != 0:\n                raise ParserException(self, ln,\n                                      'Invalid indentation, '\n                                      'must be a multiple of '\n                                      '%s spaces' % spaces)\n            content = content.strip()\n            rlevel = count // spaces if spaces > 0 else 0\n\n            # Level finished\n            if count < indent:\n                return objects, lines[i - 1:]\n\n            # Current level, create an object\n            elif count == indent:\n                x = content.split(':', 1)\n                if not len(x[0]):\n                    raise ParserException(self, ln, 'Identifier missing')\n                if (len(x) == 2 and len(x[1]) and\n                    not x[1].lstrip().startswith('#')):\n                    raise ParserException(self, ln,\n                                          'Invalid data after declaration')\n                name = x[0]\n                # if it's not a root rule, then we got some restriction\n                # aka, a valid name, without point or everything else\n                if count != 0:\n                    if False in [ord(z) in Parser.PROP_RANGE for z in name]:\n                        raise ParserException(self, ln, 'Invalid class name')\n\n                current_object = ParserRule(self, ln, x[0], rlevel)\n                current_property = None\n                objects.append(current_object)\n\n            # Next level, is it a property or an object ?\n            elif count == indent + spaces:\n                x = content.split(':', 1)\n                if not len(x[0]):\n                    raise ParserException(self, ln, 'Identifier missing')\n\n                # It's a class, add to the current object as a children\n                current_property = None\n                name = x[0]\n                if ord(name[0]) in Parser.CLASS_RANGE or name[0] == '+':\n                    _objects, _lines = self.parse_level(\n                        level + 1, lines[i:], spaces)\n                    current_object.children = _objects\n                    lines = _lines\n                    i = 0\n\n                # It's a property\n                else:\n                    if name not in Parser.PROP_ALLOWED:\n                        if not all(ord(z) in Parser.PROP_RANGE for z in name):\n                            raise ParserException(self, ln,\n                                                  'Invalid property name')\n                    if len(x) == 1:\n                        raise ParserException(self, ln, 'Syntax error')\n                    value = x[1].strip()\n                    if name == 'id':\n                        if len(value) <= 0:\n                            raise ParserException(self, ln, 'Empty id')\n                        if value in ('self', 'root'):\n                            raise ParserException(\n                                self, ln,\n                                'Invalid id, cannot be \"self\" or \"root\"')\n                        current_object.id = value\n                    elif len(value):\n                        rule = ParserRuleProperty(self, ln, name, value)\n                        if name[:3] == 'on_':\n                            current_object.handlers.append(rule)\n                        else:\n                            current_object.properties[name] = rule\n                    else:\n                        current_property = name\n                        current_propobject = None\n\n            # Two more levels?\n            elif count == indent + 2 * spaces:\n                if current_property in (\n                        'canvas', 'canvas.after', 'canvas.before'):\n                    _objects, _lines = self.parse_level(\n                        level + 2, lines[i:], spaces)\n                    rl = ParserRule(self, ln, current_property, rlevel)\n                    rl.children = _objects\n                    if current_property == 'canvas':\n                        current_object.canvas_root = rl\n                    elif current_property == 'canvas.before':\n                        current_object.canvas_before = rl\n                    else:\n                        current_object.canvas_after = rl\n                    current_property = None\n                    lines = _lines\n                    i = 0\n                else:\n                    if current_propobject is None:\n                        current_propobject = ParserRuleProperty(\n                            self, ln, current_property, content)\n                        if current_property[:3] == 'on_':\n                            current_object.handlers.append(current_propobject)\n                        else:\n                            current_object.properties[current_property] = \\\n                                current_propobject\n                    else:\n                        current_propobject.value += '\\n' + content\n\n            # Too much indentation, invalid\n            else:\n                raise ParserException(self, ln,\n                                      'Invalid indentation (too many levels)')\n\n            # Check the next line\n            i += 1\n\n        return objects, []\n\n\ndef get_proxy(widget):\n    try:\n        return widget.proxy_ref\n    except AttributeError:\n        return widget\n\n\ndef custom_callback(__kvlang__, idmap, *largs, **kwargs):\n    idmap['args'] = largs\n    exec(__kvlang__.co_value, idmap)\n\n\ndef call_fn(args, instance, v):\n    element, key, value, rule, idmap = args\n    if __debug__:\n        trace('Builder: call_fn %s, key=%s, value=%r, %r' % (\n            element, key, value, rule.value))\n    rule.count += 1\n    e_value = eval(value, idmap)\n    if __debug__:\n        trace('Builder: call_fn => value=%r' % (e_value, ))\n    setattr(element, key, e_value)\n\n\ndef delayed_call_fn(args, instance, v):\n    # it's already on the list\n    if args[-1] is not None:\n        return\n\n    global _delayed_start\n    if _delayed_start is None:\n        _delayed_start = args\n        args[-1] = StopIteration\n    else:\n        args[-1] = _delayed_start\n        _delayed_start = args\n\n\ndef update_intermediates(base, keys, bound, s, fn, args, instance, value):\n    ''' Function that is called when an intermediate property is updated\n    and `rebind` of that property is True. In that case, we unbind\n    all bound funcs that were bound to attrs of the old value of the\n    property and rebind to the new value of the property.\n\n    For example, if the rule is `self.a.b.c.d`, then when b is changed, we\n    unbind from `b`, `c` and `d`, if they were bound before (they were not\n    None and `rebind` of the respective properties was True) and we rebind\n    to the new values of the attrs `b`, `c``, `d` that are not None and\n    `rebind` is True.\n\n    :Parameters:\n        `base`\n            A (proxied) ref to the base widget, `self` in the example\n            above.\n        `keys`\n            A list of the name off the attrs of `base` being watched. In\n            the example above it'd be `['a', 'b', 'c', 'd']`.\n        `bound`\n            A list 4-tuples, each tuple being (widget, attr, callback, uid)\n            representing callback functions bound to the attributed `attr`\n            of `widget`. `uid` is returned by `fast_bind` when binding.\n            The callback may be None, in which case the attr\n            was not bound, but is there to be able to walk the attr tree.\n            E.g. in the example above, if `b` was not an eventdispatcher,\n            `(_b_ref_, `c`, None)` would be added to the list so we can get\n            to `c` and `d`, which may be eventdispatchers and their attrs.\n        `s`\n            The index in `keys` of the of the attr that needs to be\n            updated. That is all the keys from `s` and further will be\n            rebound, since the `s` key was changed. In bound, the\n            corresponding index is `s - 1`. If `s` is None, we start from\n            1 (first attr).\n        `fn`\n            The function to be called args, `args` on bound callback.\n    '''\n    # first remove all the old bound functions from `s` and down.\n    for f, k, fun, uid in bound[s:]:\n        if fun is None:\n            continue\n        try:\n            f.unbind_uid(k, uid)\n        except ReferenceError:\n            pass\n    del bound[s:]\n\n    # find the first attr from which we need to start rebinding.\n    f = getattr(*bound[-1][:2])\n    if f is None:\n        fn(args, None, None)\n        return\n    s += 1\n    append = bound.append\n\n    # bind all attrs, except last to update_intermediates\n    for val in keys[s:-1]:\n        # if we need to dynamically rebind, bindm otherwise just\n        # add the attr to the list\n        if isinstance(f, (EventDispatcher, Observable)):\n            prop = f.property(val, True)\n            if prop is not None and getattr(prop, 'rebind', False):\n                # fast_bind should not dispatch, otherwise\n                # update_intermediates might be called in the middle\n                # here messing things up\n                uid = f.fast_bind(\n                    val, update_intermediates, base, keys, bound, s, fn, args)\n                append([f.proxy_ref, val, update_intermediates, uid])\n            else:\n                append([f.proxy_ref, val, None, None])\n        else:\n            append([getattr(f, 'proxy_ref', f), val, None, None])\n\n        f = getattr(f, val, None)\n        if f is None:\n            break\n        s += 1\n\n    # for the last attr we bind directly to the setting function,\n    # because that attr sets the value of the rule.\n    if isinstance(f, (EventDispatcher, Observable)):\n        uid = f.fast_bind(keys[-1], fn, args)\n        if uid:\n            append([f.proxy_ref, keys[-1], fn, uid])\n    # when we rebind we have to update the\n    # rule with the most recent value, otherwise, the value might be wrong\n    # and wouldn't be updated since we might not have tracked it before.\n    # This only happens for a callback when rebind was True for the prop.\n    fn(args, None, None)\n\n\ndef create_handler(iself, element, key, value, rule, idmap, delayed=False):\n    idmap = copy(idmap)\n    idmap.update(global_idmap)\n    idmap['self'] = iself.proxy_ref\n    handler_append = _handlers[iself.uid].append\n\n    # we need a hash for when delayed, so we don't execute duplicate canvas\n    # callbacks from the same handler during a sync op\n    if delayed:\n        fn = delayed_call_fn\n        args = [element, key, value, rule, idmap, None]  # see _delayed_start\n    else:\n        fn = call_fn\n        args = (element, key, value, rule, idmap)\n\n    # bind every key.value\n    if rule.watched_keys is not None:\n        for keys in rule.watched_keys:\n            base = idmap.get(keys[0])\n            if base is None:\n                continue\n            f = base = getattr(base, 'proxy_ref', base)\n            bound = []\n            was_bound = False\n            append = bound.append\n\n            # bind all attrs, except last to update_intermediates\n            k = 1\n            for val in keys[1:-1]:\n                # if we need to dynamically rebind, bindm otherwise\n                # just add the attr to the list\n                if isinstance(f, (EventDispatcher, Observable)):\n                    prop = f.property(val, True)\n                    if prop is not None and getattr(prop, 'rebind', False):\n                        # fast_bind should not dispatch, otherwise\n                        # update_intermediates might be called in the middle\n                        # here messing things up\n                        uid = f.fast_bind(\n                            val, update_intermediates, base, keys, bound, k,\n                            fn, args)\n                        append([f.proxy_ref, val, update_intermediates, uid])\n                        was_bound = True\n                    else:\n                        append([f.proxy_ref, val, None, None])\n                elif not isinstance(f, _cls_type):\n                    append([getattr(f, 'proxy_ref', f), val, None, None])\n                else:\n                    append([f, val, None, None])\n                f = getattr(f, val, None)\n                if f is None:\n                    break\n                k += 1\n\n            # for the last attr we bind directly to the setting\n            # function, because that attr sets the value of the rule.\n            if isinstance(f, (EventDispatcher, Observable)):\n                uid = f.fast_bind(keys[-1], fn, args)  # f is not None\n                if uid:\n                    append([f.proxy_ref, keys[-1], fn, uid])\n                    was_bound = True\n            if was_bound:\n                handler_append(bound)\n\n    try:\n        return eval(value, idmap)\n    except Exception as e:\n        tb = sys.exc_info()[2]\n        raise BuilderException(rule.ctx, rule.line,\n                               '{}: {}'.format(e.__class__.__name__, e),\n                               cause=tb)\n\n\nclass ParserSelector(object):\n\n    def __init__(self, key):\n        self.key = key.lower()\n\n    def match(self, widget):\n        raise NotImplemented()\n\n    def __repr__(self):\n        return '<%s key=%s>' % (self.__class__.__name__, self.key)\n\n\nclass ParserSelectorId(ParserSelector):\n\n    def match(self, widget):\n        if widget.id:\n            return widget.id.lower() == self.key\n\n\nclass ParserSelectorClass(ParserSelector):\n\n    def match(self, widget):\n        return self.key in widget.cls\n\n\nclass ParserSelectorName(ParserSelector):\n\n    parents = {}\n\n    def get_bases(self, cls):\n        for base in cls.__bases__:\n            if base.__name__ == 'object':\n                break\n            yield base\n            if base.__name__ == 'Widget':\n                break\n            for cbase in self.get_bases(base):\n                yield cbase\n\n    def match(self, widget):\n        parents = ParserSelectorName.parents\n        cls = widget.__class__\n        if not cls in parents:\n            classes = [x.__name__.lower() for x in\n                       [cls] + list(self.get_bases(cls))]\n            parents[cls] = classes\n        return self.key in parents[cls]\n\n\nclass BuilderBase(object):\n    '''The Builder is responsible for creating a :class:`Parser` for parsing a\n    kv file, merging the results into its internal rules, templates, etc.\n\n    By default, :class:`Builder` is a global Kivy instance used in widgets\n    that you can use to load other kv files in addition to the default ones.\n    '''\n\n    _match_cache = {}\n\n    def __init__(self):\n        super(BuilderBase, self).__init__()\n        self.files = []\n        self.dynamic_classes = {}\n        self.templates = {}\n        self.rules = []\n        self.rulectx = {}\n\n    def load_file(self, filename, **kwargs):\n        '''Insert a file into the language builder and return the root widget\n        (if defined) of the kv file.\n\n        :parameters:\n            `rulesonly`: bool, defaults to False\n                If True, the Builder will raise an exception if you have a root\n                widget inside the definition.\n        '''\n        filename = resource_find(filename) or filename\n        if __debug__:\n            trace('Builder: load file %s' % filename)\n        with open(filename, 'r') as fd:\n            kwargs['filename'] = filename\n            data = fd.read()\n\n            # remove bom ?\n            if PY2:\n                if data.startswith((codecs.BOM_UTF16_LE, codecs.BOM_UTF16_BE)):\n                    raise ValueError('Unsupported UTF16 for kv files.')\n                if data.startswith((codecs.BOM_UTF32_LE, codecs.BOM_UTF32_BE)):\n                    raise ValueError('Unsupported UTF32 for kv files.')\n                if data.startswith(codecs.BOM_UTF8):\n                    data = data[len(codecs.BOM_UTF8):]\n\n            return self.load_string(data, **kwargs)\n\n    def unload_file(self, filename):\n        '''Unload all rules associated with a previously imported file.\n\n        .. versionadded:: 1.0.8\n\n        .. warning::\n\n            This will not remove rules or templates already applied/used on\n            current widgets. It will only effect the next widgets creation or\n            template invocation.\n        '''\n        # remove rules and templates\n        self.rules = [x for x in self.rules if x[1].ctx.filename != filename]\n        self._clear_matchcache()\n        templates = {}\n        for x, y in self.templates.items():\n            if y[2] != filename:\n                templates[x] = y\n        self.templates = templates\n        if filename in self.files:\n            self.files.remove(filename)\n\n        # unregister all the dynamic classes\n        Factory.unregister_from_filename(filename)\n\n    def load_string(self, string, **kwargs):\n        '''Insert a string into the Language Builder and return the root widget\n        (if defined) of the kv string.\n\n        :Parameters:\n            `rulesonly`: bool, defaults to False\n                If True, the Builder will raise an exception if you have a root\n                widget inside the definition.\n        '''\n        kwargs.setdefault('rulesonly', False)\n        self._current_filename = fn = kwargs.get('filename', None)\n\n        # put a warning if a file is loaded multiple times\n        if fn in self.files:\n            Logger.warning(\n                'Lang: The file {} is loaded multiples times, '\n                'you might have unwanted behaviors.'.format(fn))\n\n        try:\n            # parse the string\n            parser = Parser(content=string, filename=fn)\n\n            # merge rules with our rules\n            self.rules.extend(parser.rules)\n            self._clear_matchcache()\n\n            # add the template found by the parser into ours\n            for name, cls, template in parser.templates:\n                self.templates[name] = (cls, template, fn)\n                Factory.register(name,\n                                 cls=partial(self.template, name),\n                                 is_template=True, warn=True)\n\n            # register all the dynamic classes\n            for name, baseclasses in iteritems(parser.dynamic_classes):\n                Factory.register(name, baseclasses=baseclasses, filename=fn,\n                                 warn=True)\n\n            # create root object is exist\n            if kwargs['rulesonly'] and parser.root:\n                filename = kwargs.get('rulesonly', '<string>')\n                raise Exception('The file <%s> contain also non-rules '\n                                'directives' % filename)\n\n            # save the loaded files only if there is a root without\n            # template/dynamic classes\n            if fn and (parser.templates or\n                       parser.dynamic_classes or parser.rules):\n                self.files.append(fn)\n\n            if parser.root:\n                widget = Factory.get(parser.root.name)()\n                self._apply_rule(widget, parser.root, parser.root)\n                return widget\n        finally:\n            self._current_filename = None\n\n    def template(self, *args, **ctx):\n        '''Create a specialized template using a specific context.\n        .. versionadded:: 1.0.5\n\n        With templates, you can construct custom widgets from a kv lang\n        definition by giving them a context. Check :ref:`Template usage\n        <template_usage>`.\n        '''\n        # Prevent naming clash with whatever the user might be putting into the\n        # ctx as key.\n        name = args[0]\n        if name not in self.templates:\n            raise Exception('Unknown <%s> template name' % name)\n        baseclasses, rule, fn = self.templates[name]\n        key = '%s|%s' % (name, baseclasses)\n        cls = Cache.get('kv.lang', key)\n        if cls is None:\n            rootwidgets = []\n            for basecls in baseclasses.split('+'):\n                rootwidgets.append(Factory.get(basecls))\n            cls = type(name, tuple(rootwidgets), {})\n            Cache.append('kv.lang', key, cls)\n        widget = cls()\n        # in previous versions, ``ctx`` is passed as is as ``template_ctx``\n        # preventing widgets in it from be collected by the GC. This was\n        # especially relevant to AccordionItem's title_template.\n        proxy_ctx = {k: get_proxy(v) for k, v in ctx.items()}\n        self._apply_rule(widget, rule, rule, template_ctx=proxy_ctx)\n        return widget\n\n    def apply(self, widget):\n        '''Search all the rules that match the widget and apply them.\n        '''\n        rules = self.match(widget)\n        if __debug__:\n            trace('Builder: Found %d rules for %s' % (len(rules), widget))\n        if not rules:\n            return\n        for rule in rules:\n            self._apply_rule(widget, rule, rule)\n\n    def _clear_matchcache(self):\n        BuilderBase._match_cache = {}\n\n    def _apply_rule(self, widget, rule, rootrule, template_ctx=None):\n        # widget: the current instantiated widget\n        # rule: the current rule\n        # rootrule: the current root rule (for children of a rule)\n\n        # will collect reference to all the id in children\n        assert(rule not in self.rulectx)\n        self.rulectx[rule] = rctx = {\n            'ids': {'root': widget.proxy_ref},\n            'set': [], 'hdl': []}\n\n        # extract the context of the rootrule (not rule!)\n        assert(rootrule in self.rulectx)\n        rctx = self.rulectx[rootrule]\n\n        # if a template context is passed, put it as \"ctx\"\n        if template_ctx is not None:\n            rctx['ids']['ctx'] = QueryDict(template_ctx)\n\n        # if we got an id, put it in the root rule for a later global usage\n        if rule.id:\n            # use only the first word as `id` discard the rest.\n            rule.id = rule.id.split('#', 1)[0].strip()\n            rctx['ids'][rule.id] = widget.proxy_ref\n            # set id name as a attribute for root widget so one can in python\n            # code simply access root_widget.id_name\n            _ids = dict(rctx['ids'])\n            _root = _ids.pop('root')\n            _new_ids = _root.ids\n            for _key in iterkeys(_ids):\n                if _ids[_key] == _root:\n                    # skip on self\n                    continue\n                _new_ids[_key] = _ids[_key]\n            _root.ids = _new_ids\n\n        # first, ensure that the widget have all the properties used in\n        # the rule if not, they will be created as ObjectProperty.\n        rule.create_missing(widget)\n\n        # build the widget canvas\n        if rule.canvas_before:\n            with widget.canvas.before:\n                self._build_canvas(widget.canvas.before, widget,\n                                   rule.canvas_before, rootrule)\n        if rule.canvas_root:\n            with widget.canvas:\n                self._build_canvas(widget.canvas, widget,\n                                   rule.canvas_root, rootrule)\n        if rule.canvas_after:\n            with widget.canvas.after:\n                self._build_canvas(widget.canvas.after, widget,\n                                   rule.canvas_after, rootrule)\n\n        # create children tree\n        Factory_get = Factory.get\n        Factory_is_template = Factory.is_template\n        for crule in rule.children:\n            cname = crule.name\n\n            if cname in ('canvas', 'canvas.before', 'canvas.after'):\n                raise ParserException(\n                    crule.ctx, crule.line,\n                    'Canvas instructions added in kv must '\n                    'be declared before child widgets.')\n\n            # depending if the child rule is a template or not, we are not\n            # having the same approach\n            cls = Factory_get(cname)\n\n            if Factory_is_template(cname):\n                # we got a template, so extract all the properties and\n                # handlers, and push them in a \"ctx\" dictionary.\n                ctx = {}\n                idmap = copy(global_idmap)\n                idmap.update({'root': rctx['ids']['root']})\n                if 'ctx' in rctx['ids']:\n                    idmap.update({'ctx': rctx['ids']['ctx']})\n                try:\n                    for prule in crule.properties.values():\n                        value = prule.co_value\n                        if type(value) is CodeType:\n                            value = eval(value, idmap)\n                        ctx[prule.name] = value\n                    for prule in crule.handlers:\n                        value = eval(prule.value, idmap)\n                        ctx[prule.name] = value\n                except Exception as e:\n                    tb = sys.exc_info()[2]\n                    raise BuilderException(\n                        prule.ctx, prule.line,\n                        '{}: {}'.format(e.__class__.__name__, e), cause=tb)\n\n                # create the template with an explicit ctx\n                child = cls(**ctx)\n                widget.add_widget(child)\n\n                # reference it on our root rule context\n                if crule.id:\n                    rctx['ids'][crule.id] = child\n\n            else:\n                # we got a \"normal\" rule, construct it manually\n                # we can't construct it without __no_builder=True, because the\n                # previous implementation was doing the add_widget() before\n                # apply(), and so, we could use \"self.parent\".\n                child = cls(__no_builder=True)\n                widget.add_widget(child)\n                self.apply(child)\n                self._apply_rule(child, crule, rootrule)\n\n        # append the properties and handlers to our final resolution task\n        if rule.properties:\n            rctx['set'].append((widget.proxy_ref,\n                                list(rule.properties.values())))\n        if rule.handlers:\n            rctx['hdl'].append((widget.proxy_ref, rule.handlers))\n\n        # if we are applying another rule that the root one, then it's done for\n        # us!\n        if rootrule is not rule:\n            del self.rulectx[rule]\n            return\n\n        # normally, we can apply a list of properties with a proper context\n        try:\n            rule = None\n            for widget_set, rules in reversed(rctx['set']):\n                for rule in rules:\n                    assert(isinstance(rule, ParserRuleProperty))\n                    key = rule.name\n                    value = rule.co_value\n                    if type(value) is CodeType:\n                        value = create_handler(widget_set, widget_set, key,\n                                               value, rule, rctx['ids'])\n                    setattr(widget_set, key, value)\n        except Exception as e:\n            if rule is not None:\n                tb = sys.exc_info()[2]\n                raise BuilderException(rule.ctx, rule.line,\n                                       '{}: {}'.format(e.__class__.__name__,\n                                                       e), cause=tb)\n            raise e\n\n        # build handlers\n        try:\n            crule = None\n            for widget_set, rules in rctx['hdl']:\n                for crule in rules:\n                    assert(isinstance(crule, ParserRuleProperty))\n                    assert(crule.name.startswith('on_'))\n                    key = crule.name\n                    if not widget_set.is_event_type(key):\n                        key = key[3:]\n                    idmap = copy(global_idmap)\n                    idmap.update(rctx['ids'])\n                    idmap['self'] = widget_set.proxy_ref\n                    if not widget_set.fast_bind(key, custom_callback, crule,\n                                                idmap):\n                        raise AttributeError(key)\n                    #hack for on_parent\n                    if crule.name == 'on_parent':\n                        Factory.Widget.parent.dispatch(widget_set.__self__)\n        except Exception as e:\n            if crule is not None:\n                tb = sys.exc_info()[2]\n                raise BuilderException(\n                    crule.ctx, crule.line,\n                    '{}: {}'.format(e.__class__.__name__, e), cause=tb)\n            raise e\n\n        # rule finished, forget it\n        del self.rulectx[rootrule]\n\n    def match(self, widget):\n        '''Return a list of :class:`ParserRule` objects matching the widget.\n        '''\n        cache = BuilderBase._match_cache\n        k = (widget.__class__, widget.id, tuple(widget.cls))\n        if k in cache:\n            return cache[k]\n        rules = []\n        for selector, rule in self.rules:\n            if selector.match(widget):\n                if rule.avoid_previous_rules:\n                    del rules[:]\n                rules.append(rule)\n        cache[k] = rules\n        return rules\n\n    def sync(self):\n        '''Execute all the waiting operations, such as the execution of all the\n        expressions related to the canvas.\n\n        .. versionadded:: 1.7.0\n        '''\n        global _delayed_start\n        next_args = _delayed_start\n        if next_args is None:\n            return\n\n        while next_args is not StopIteration:\n            # is this try/except still needed? yes, in case widget died in this\n            # frame after the call was scheduled\n            try:\n                call_fn(next_args[:-1], None, None)\n            except ReferenceError:\n                pass\n            args = next_args\n            next_args = args[-1]\n            args[-1] = None\n        _delayed_start = None\n\n    def unbind_widget(self, uid):\n        '''(internal) Unbind all the handlers created by the rules of the\n        widget. The :attr:`kivy.uix.widget.Widget.uid` is passed here\n        instead of the widget itself, because we are using it in the\n        widget destructor.\n\n        .. versionadded:: 1.7.2\n        '''\n        if uid not in _handlers:\n            return\n        for callbacks in _handlers[uid]:\n            for f, k, fn, bound_uid in callbacks:\n                if fn is None:  # it's not a kivy prop.\n                    continue\n                try:\n                    f.unbind_uid(k, bound_uid)\n                except ReferenceError:\n                    # proxy widget is already gone, that's cool :)\n                    pass\n        del _handlers[uid]\n\n    def _build_canvas(self, canvas, widget, rule, rootrule):\n        global Instruction\n        if Instruction is None:\n            Instruction = Factory.get('Instruction')\n        idmap = copy(self.rulectx[rootrule]['ids'])\n        for crule in rule.children:\n            name = crule.name\n            if name == 'Clear':\n                canvas.clear()\n                continue\n            instr = Factory.get(name)()\n            if not isinstance(instr, Instruction):\n                raise BuilderException(\n                    crule.ctx, crule.line,\n                    'You can add only graphics Instruction in canvas.')\n            try:\n                for prule in crule.properties.values():\n                    key = prule.name\n                    value = prule.co_value\n                    if type(value) is CodeType:\n                        value = create_handler(\n                            widget, instr.proxy_ref,\n                            key, value, prule, idmap, True)\n                    setattr(instr, key, value)\n            except Exception as e:\n                tb = sys.exc_info()[2]\n                raise BuilderException(\n                    prule.ctx, prule.line,\n                    '{}: {}'.format(e.__class__.__name__, e), cause=tb)\n\n#: Main instance of a :class:`BuilderBase`.\nBuilder = register_context('Builder', BuilderBase)\nBuilder.load_file(join(kivy_data_dir, 'style.kv'), rulesonly=True)\n\nif 'KIVY_PROFILE_LANG' in environ:\n    import atexit\n    import cgi\n\n    def match_rule(fn, index, rule):\n        if rule.ctx.filename != fn:\n            return\n        for prop, prp in iteritems(rule.properties):\n            if prp.line != index:\n                continue\n            yield prp\n        for child in rule.children:\n            for r in match_rule(fn, index, child):\n                yield r\n        if rule.canvas_root:\n            for r in match_rule(fn, index, rule.canvas_root):\n                yield r\n        if rule.canvas_before:\n            for r in match_rule(fn, index, rule.canvas_before):\n                yield r\n        if rule.canvas_after:\n            for r in match_rule(fn, index, rule.canvas_after):\n                yield r\n\n    def dump_builder_stats():\n        html = [\n            '<!doctype html>'\n            '<html><body>',\n            '<style type=\"text/css\">\\n',\n            'pre { margin: 0; }\\n',\n            '</style>']\n        files = set([x[1].ctx.filename for x in Builder.rules])\n        for fn in files:\n            lines = open(fn).readlines()\n            html += ['<h2>', fn, '</h2>', '<table>']\n            count = 0\n            for index, line in enumerate(lines):\n                line = line.rstrip()\n                line = cgi.escape(line)\n                matched_prp = []\n                for psn, rule in Builder.rules:\n                    matched_prp += list(match_rule(fn, index, rule))\n\n                count = sum(set([x.count for x in matched_prp]))\n\n                color = (255, 155, 155) if count else (255, 255, 255)\n                html += ['<tr style=\"background-color: rgb{}\">'.format(color),\n                         '<td>', str(index + 1), '</td>',\n                         '<td>', str(count), '</td>',\n                         '<td><pre>', line, '</pre></td>',\n                         '</tr>']\n            html += ['</table>']\n        html += ['</body></html>']\n        with open('builder_stats.html', 'w') as fd:\n            fd.write(''.join(html))\n\n        print('Profiling written at builder_stats.html')\n\n    atexit.register(dump_builder_stats)\n"
  },
  {
    "path": "tickeys/kivy/loader.py",
    "content": "'''\nAsynchronous data loader\n========================\n\nThis is the Asynchronous Loader. You can use it to load an image\nand use it, even if data are not yet available. You must specify a default\nloading image when using the loader::\n\n    from kivy.loader import Loader\n    image = Loader.image('mysprite.png')\n\nYou can also load an image from a url::\n\n    image = Loader.image('http://mysite.com/test.png')\n\nIf you want to change the default loading image, you can do::\n\n    Loader.loading_image = Image('another_loading.png')\n\nTweaking the asynchronous loader\n--------------------------------\n\n.. versionadded:: 1.6.0\n\nYou can tweak the loader to provide a better user experience or more\nperformance, depending of the images you are going to load. Take a look at the\nparameters:\n\n- :attr:`Loader.num_workers` - define the number of threads to start for\n  loading images.\n- :attr:`Loader.max_upload_per_frame` - define the maximum image uploads in\n  GPU to do per frame.\n\n'''\n\n__all__ = ('Loader', 'LoaderBase', 'ProxyImage')\n\nfrom kivy import kivy_data_dir\nfrom kivy.logger import Logger\nfrom kivy.clock import Clock\nfrom kivy.cache import Cache\nfrom kivy.core.image import ImageLoader, Image\nfrom kivy.compat import PY2, string_types\n\nfrom collections import deque\nfrom time import sleep\nfrom os.path import join\nfrom os import write, close, unlink, environ\nimport threading\nimport mimetypes\n\n# Register a cache for loader\nCache.register('kv.loader', limit=500, timeout=60)\n\n\nclass ProxyImage(Image):\n    '''Image returned by the Loader.image() function.\n\n    :Properties:\n        `loaded`: bool, defaults to False\n            This value may be True if the image is already cached.\n\n    :Events:\n        `on_load`\n            Fired when the image is loaded or changed.\n    '''\n\n    __events__ = ('on_load', )\n\n    def __init__(self, arg, **kwargs):\n        kwargs.setdefault('loaded', False)\n        super(ProxyImage, self).__init__(arg, **kwargs)\n        self.loaded = kwargs.get('loaded')\n\n    def on_load(self):\n        pass\n\n\nclass LoaderBase(object):\n    '''Common base for the Loader and specific implementations.\n    By default, the Loader will be the best available loader implementation.\n\n    The _update() function is called every 1 / 25.s or each frame if we have\n    less than 25 FPS.\n    '''\n\n    def __init__(self):\n        self._loading_image = None\n        self._error_image = None\n        self._num_workers = 2\n        self._max_upload_per_frame = 2\n        self._paused = False\n        self._resume_cond = threading.Condition()\n\n        self._q_load = deque()\n        self._q_done = deque()\n        self._client = []\n        self._running = False\n        self._start_wanted = False\n        self._trigger_update = Clock.create_trigger(self._update)\n\n    def __del__(self):\n        try:\n            Clock.unschedule(self._update)\n        except Exception:\n            pass\n\n    def _set_num_workers(self, num):\n        if num < 2:\n            raise Exception('Must have at least 2 workers')\n        self._num_workers = num\n\n    def _get_num_workers(self):\n        return self._num_workers\n\n    num_workers = property(_get_num_workers, _set_num_workers)\n    '''Number of workers to use while loading (used only if the loader\n    implementation supports it). This setting impacts the loader only on\n    initialization. Once the loader is started, the setting has no impact::\n\n        from kivy.loader import Loader\n        Loader.num_workers = 4\n\n    The default value is 2 for giving a smooth user experience. You could\n    increase the number of workers, then all the images will be loaded faster,\n    but the user will not been able to use the application while loading.\n    Prior to 1.6.0, the default number was 20, and loading many full-hd images\n    was completly blocking the application.\n\n    .. versionadded:: 1.6.0\n    '''\n\n    def _set_max_upload_per_frame(self, num):\n        if num is not None and num < 1:\n            raise Exception('Must have at least 1 image processing per image')\n        self._max_upload_per_frame = num\n\n    def _get_max_upload_per_frame(self):\n        return self._max_upload_per_frame\n\n    max_upload_per_frame = property(_get_max_upload_per_frame,\n                                    _set_max_upload_per_frame)\n    '''The number of images to upload per frame. By default, we'll\n    upload only 2 images to the GPU per frame. If you are uploading many\n    small images, you can easily increase this parameter to 10 or more.\n    If you are loading multiple full HD images, the upload time may have\n    consequences and block the application. If you want a\n    smooth experience, use the default.\n\n    As a matter of fact, a Full-HD RGB image will take ~6MB in memory,\n    so it may take time. If you have activated mipmap=True too, then the\n    GPU must calculate the mipmap of these big images too, in real time.\n    Then it may be best to reduce the :attr:`max_upload_per_frame` to 1\n    or 2. If you want to get rid of that (or reduce it a lot), take a\n    look at the DDS format.\n\n    .. versionadded:: 1.6.0\n    '''\n\n    def _get_loading_image(self):\n        if not self._loading_image:\n            loading_png_fn = join(kivy_data_dir, 'images', 'image-loading.gif')\n            self._loading_image = ImageLoader.load(filename=loading_png_fn)\n        return self._loading_image\n\n    def _set_loading_image(self, image):\n        if isinstance(image, string_types):\n            self._loading_image = ImageLoader.load(filename=image)\n        else:\n            self._loading_image = image\n\n    loading_image = property(_get_loading_image, _set_loading_image)\n    '''Image used for loading.\n    You can change it by doing::\n\n        Loader.loading_image = 'loading.png'\n\n    .. versionchanged:: 1.6.0\n        Not readonly anymore.\n    '''\n\n    def _get_error_image(self):\n        if not self._error_image:\n            error_png_fn = join(\n                'atlas://data/images/defaulttheme/image-missing')\n            self._error_image = ImageLoader.load(filename=error_png_fn)\n        return self._error_image\n\n    def _set_error_image(self, image):\n        if isinstance(image, string_types):\n            self._error_image = ImageLoader.load(filename=image)\n        else:\n            self._error_image = image\n\n    error_image = property(_get_error_image, _set_error_image)\n    '''Image used for error.\n    You can change it by doing::\n\n        Loader.error_image = 'error.png'\n\n    .. versionchanged:: 1.6.0\n        Not readonly anymore.\n    '''\n\n    def start(self):\n        '''Start the loader thread/process.'''\n        self._running = True\n\n    def run(self, *largs):\n        '''Main loop for the loader.'''\n        pass\n\n    def stop(self):\n        '''Stop the loader thread/process.'''\n        self._running = False\n\n    def pause(self):\n        '''Pause the loader, can be useful during interactions.\n\n        .. versionadded:: 1.6.0\n        '''\n        self._paused = True\n\n    def resume(self):\n        '''Resume the loader, after a :meth:`pause`.\n\n        .. versionadded:: 1.6.0\n        '''\n        self._paused = False\n        self._resume_cond.acquire()\n        self._resume_cond.notify_all()\n        self._resume_cond.release()\n\n    def _wait_for_resume(self):\n        while self._running and self._paused:\n            self._resume_cond.acquire()\n            self._resume_cond.wait(0.25)\n            self._resume_cond.release()\n\n    def _load(self, kwargs):\n        '''(internal) Loading function, called by the thread.\n        Will call _load_local() if the file is local,\n        or _load_urllib() if the file is on Internet.\n        '''\n\n        while len(self._q_done) >= (\n                self.max_upload_per_frame * self._num_workers):\n            sleep(0.1)\n\n        self._wait_for_resume()\n\n        filename = kwargs['filename']\n        load_callback = kwargs['load_callback']\n        post_callback = kwargs['post_callback']\n        try:\n            proto = filename.split(':', 1)[0]\n        except:\n            #if blank filename then return\n            return\n        if load_callback is not None:\n            data = load_callback(filename)\n        elif proto in ('http', 'https', 'ftp', 'smb'):\n            data = self._load_urllib(filename, kwargs['kwargs'])\n        else:\n            data = self._load_local(filename, kwargs['kwargs'])\n\n        if post_callback:\n            data = post_callback(data)\n\n        self._q_done.appendleft((filename, data))\n        self._trigger_update()\n\n    def _load_local(self, filename, kwargs):\n        '''(internal) Loading a local file'''\n        # With recent changes to CoreImage, we must keep data otherwise,\n        # we might be unable to recreate the texture afterwise.\n        return ImageLoader.load(filename, keep_data=True, **kwargs)\n\n    def _load_urllib(self, filename, kwargs):\n        '''(internal) Loading a network file. First download it, save it to a\n        temporary file, and pass it to _load_local().'''\n        if PY2:\n            import urllib2 as urllib_request\n\n            def gettype(info):\n                return info.gettype()\n        else:\n            import urllib.request as urllib_request\n\n            def gettype(info):\n                return info.get_content_type()\n        proto = filename.split(':', 1)[0]\n        if proto == 'smb':\n            try:\n                # note: it's important to load SMBHandler every time\n                # otherwise the data is occasionaly not loaded\n                from smb.SMBHandler import SMBHandler\n            except ImportError:\n                Logger.warning(\n                    'Loader: can not load PySMB: make sure it is installed')\n                return\n        import tempfile\n        data = fd = _out_osfd = None\n        try:\n            _out_filename = ''\n\n            if proto == 'smb':\n                # read from samba shares\n                fd = urllib_request.build_opener(SMBHandler).open(filename)\n            else:\n                # read from internet\n                fd = urllib_request.urlopen(filename)\n\n            if '#.' in filename:\n                # allow extension override from URL fragment\n                suffix = '.' + filename.split('#.')[-1]\n            else:\n                ctype = gettype(fd.info())\n                suffix = mimetypes.guess_extension(ctype)\n                if not suffix:\n                    # strip query string and split on path\n                    parts = filename.split('?')[0].split('/')[1:]\n                    while len(parts) > 1 and not parts[0]:\n                        # strip out blanks from '//'\n                        parts = parts[1:]\n                    if len(parts) > 1 and '.' in parts[-1]:\n                        # we don't want '.com', '.net', etc. as the extension\n                        suffix = '.' + parts[-1].split('.')[-1]\n            _out_osfd, _out_filename = tempfile.mkstemp(\n                prefix='kivyloader', suffix=suffix)\n\n            idata = fd.read()\n            fd.close()\n            fd = None\n\n            # write to local filename\n            write(_out_osfd, idata)\n            close(_out_osfd)\n            _out_osfd = None\n\n            # load data\n            data = self._load_local(_out_filename, kwargs)\n\n            # FIXME create a clean API for that\n            for imdata in data._data:\n                imdata.source = filename\n        except Exception:\n            Logger.exception('Loader: Failed to load image <%s>' % filename)\n            # close file when remote file not found or download error\n            try:\n                close(_out_osfd)\n            except OSError:\n                pass\n            return self.error_image\n        finally:\n            if fd:\n                fd.close()\n            if _out_osfd:\n                close(_out_osfd)\n            if _out_filename != '':\n                unlink(_out_filename)\n\n        return data\n\n    def _update(self, *largs):\n        '''(internal) Check if a data is loaded, and pass to the client.'''\n        # want to start it ?\n        if self._start_wanted:\n            if not self._running:\n                self.start()\n            self._start_wanted = False\n\n        # in pause mode, don't unqueue anything.\n        if self._paused:\n            self._trigger_update()\n            return\n\n        for x in range(self.max_upload_per_frame):\n            try:\n                filename, data = self._q_done.pop()\n            except IndexError:\n                return\n\n            # create the image\n            image = data  # ProxyImage(data)\n            if not image.nocache:\n                Cache.append('kv.loader', filename, image)\n\n            # update client\n            for c_filename, client in self._client[:]:\n                if filename != c_filename:\n                    continue\n                # got one client to update\n                client.image = image\n                client.loaded = True\n                client.dispatch('on_load')\n                self._client.remove((c_filename, client))\n\n        self._trigger_update()\n\n    def image(self, filename, load_callback=None, post_callback=None,\n              **kwargs):\n        '''Load a image using the Loader. A ProxyImage is returned with a\n        loading image. You can use it as follows::\n\n            from kivy.app import App\n            from kivy.uix.image import Image\n            from kivy.loader import Loader\n\n            class TestApp(App):\n                def _image_loaded(self, proxyImage):\n                    if proxyImage.image.texture:\n                        self.image.texture = proxyImage.image.texture\n\n                def build(self):\n                    proxyImage = Loader.image(\"myPic.jpg\")\n                    proxyImage.bind(on_load=self._image_loaded)\n                    self.image = Image()\n                    return self.image\n\n            TestApp().run()\n\n        In order to cancel all background loading, call *Loader.stop()*.\n        '''\n        data = Cache.get('kv.loader', filename)\n        if data not in (None, False):\n            # found image, if data is not here, need to reload.\n            return ProxyImage(data,\n                              loading_image=self.loading_image,\n                              loaded=True, **kwargs)\n\n        client = ProxyImage(self.loading_image,\n                            loading_image=self.loading_image, **kwargs)\n        self._client.append((filename, client))\n\n        if data is None:\n            # if data is None, this is really the first time\n            self._q_load.appendleft({\n                'filename': filename,\n                'load_callback': load_callback,\n                'post_callback': post_callback,\n                'kwargs': kwargs})\n            if not kwargs.get('nocache', False):\n                Cache.append('kv.loader', filename, False)\n            self._start_wanted = True\n            self._trigger_update()\n        else:\n            # already queued for loading\n            pass\n\n        return client\n\n#\n# Loader implementation\n#\n\nif 'KIVY_DOC' in environ:\n\n    Loader = None\n\nelse:\n\n    #\n    # Try to use pygame as our first choice for loader\n    #\n\n    from kivy.compat import queue\n    from threading import Thread\n\n    class _Worker(Thread):\n        '''Thread executing tasks from a given tasks queue\n        '''\n        def __init__(self, pool, tasks):\n            Thread.__init__(self)\n            self.tasks = tasks\n            self.daemon = True\n            self.pool = pool\n            self.start()\n\n        def run(self):\n            while self.pool.running:\n                func, args, kargs = self.tasks.get()\n                try:\n                    func(*args, **kargs)\n                except Exception as e:\n                    print(e)\n                self.tasks.task_done()\n\n    class _ThreadPool(object):\n        '''Pool of threads consuming tasks from a queue\n        '''\n        def __init__(self, num_threads):\n            super(_ThreadPool, self).__init__()\n            self.running = True\n            self.tasks = queue.Queue()\n            for _ in range(num_threads):\n                _Worker(self, self.tasks)\n\n        def add_task(self, func, *args, **kargs):\n            '''Add a task to the queue\n            '''\n            self.tasks.put((func, args, kargs))\n\n        def stop(self):\n            self.running = False\n            self.tasks.join()\n\n    class LoaderThreadPool(LoaderBase):\n        def __init__(self):\n            super(LoaderThreadPool, self).__init__()\n            self.pool = None\n\n        def start(self):\n            super(LoaderThreadPool, self).start()\n            self.pool = _ThreadPool(self._num_workers)\n            Clock.schedule_interval(self.run, 0)\n\n        def stop(self):\n            super(LoaderThreadPool, self).stop()\n            Clock.unschedule(self.run)\n            self.pool.stop()\n\n        def run(self, *largs):\n            while self._running:\n                try:\n                    parameters = self._q_load.pop()\n                except:\n                    return\n                self.pool.add_task(self._load, parameters)\n\n    Loader = LoaderThreadPool()\n    Logger.info('Loader: using a thread pool of {} workers'.format(\n        Loader.num_workers))\n"
  },
  {
    "path": "tickeys/kivy/logger.py",
    "content": "'''\nLogger object\n=============\n\nDifferents logging levels are available : trace, debug, info, warning, error\nand critical.\n\nExamples of usage::\n\n    from kivy.logger import Logger\n\n    Logger.info('title: This is a info message.')\n    Logger.debug('title: This is a debug message.')\n\n    try:\n        raise Exception('bleh')\n    except Exception:\n        Logger.exception('Something happened!')\n\nThe message passed to the logger is split into two parts, separated by a colon\n(:). The first part is used as a title, and the second part is used as the\nmessage. This way, you can \"categorize\" your message easily.::\n\n    Logger.info('Application: This is a test')\n\n    # will appear as\n\n    [INFO   ] [Application ] This is a test\n\nLogger configuration\n--------------------\n\nThe Logger can be controlled via the Kivy configuration file::\n\n    [kivy]\n    log_level = info\n    log_enable = 1\n    log_dir = logs\n    log_name = kivy_%y-%m-%d_%_.txt\n\nMore information about the allowed values are described in the\n:mod:`kivy.config` module.\n\nLogger history\n--------------\n\nEven if the logger is not enabled, you still have access to the last 100\nmessages::\n\n    from kivy.logger import LoggerHistory\n\n    print(LoggerHistory.history)\n\n'''\n\nimport logging\nimport os\nimport sys\nimport kivy\nfrom kivy.compat import PY2\nfrom random import randint\nfrom functools import partial\n\n__all__ = ('Logger', 'LOG_LEVELS', 'COLORS', 'LoggerHistory')\n\nLogger = None\n\nBLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = list(range(8))\n\n#These are the sequences need to get colored ouput\nRESET_SEQ = \"\\033[0m\"\nCOLOR_SEQ = \"\\033[1;%dm\"\nBOLD_SEQ = \"\\033[1m\"\n\nprevious_stderr = sys.stderr\n\n\ndef formatter_message(message, use_color=True):\n    if use_color:\n        message = message.replace(\"$RESET\", RESET_SEQ)\n        message = message.replace(\"$BOLD\", BOLD_SEQ)\n    else:\n        message = message.replace(\"$RESET\", \"\").replace(\"$BOLD\", \"\")\n    return message\n\nCOLORS = {\n    'TRACE': MAGENTA,\n    'WARNING': YELLOW,\n    'INFO': GREEN,\n    'DEBUG': CYAN,\n    'CRITICAL': RED,\n    'ERROR': RED}\n\nlogging.TRACE = 9\nLOG_LEVELS = {\n    'trace': logging.TRACE,\n    'debug': logging.DEBUG,\n    'info': logging.INFO,\n    'warning': logging.WARNING,\n    'error': logging.ERROR,\n    'critical': logging.CRITICAL}\n\n\nclass FileHandler(logging.Handler):\n    history = []\n    filename = 'log.txt'\n    fd = None\n\n    def purge_logs(self, directory):\n        '''Purge log is called randomly to prevent the log directory from being\n        filled by lots and lots of log files.\n        You've a chance of 1 in 20 that purge log will be fired.\n        '''\n        if randint(0, 20) != 0:\n            return\n\n        # Use config ?\n        maxfiles = 100\n\n        print('Purge log fired. Analysing...')\n        join = os.path.join\n        unlink = os.unlink\n\n        # search all log files\n        l = [join(directory, x) for x in os.listdir(directory)]\n        if len(l) > maxfiles:\n            # get creation time on every files\n            l = [{'fn': x, 'ctime': os.path.getctime(x)} for x in l]\n\n            # sort by date\n            l = sorted(l, key=lambda x: x['ctime'])\n\n            # get the oldest (keep last maxfiles)\n            l = l[:-maxfiles]\n            print('Purge %d log files' % len(l))\n\n            # now, unlink every files in the list\n            for filename in l:\n                unlink(filename['fn'])\n\n        print('Purge finished!')\n\n    def _configure(self, *largs, **kwargs):\n        from time import strftime\n        from kivy.config import Config\n        log_dir = Config.get('kivy', 'log_dir')\n        log_name = Config.get('kivy', 'log_name')\n\n        _dir = kivy.kivy_home_dir\n        if log_dir and os.path.isabs(log_dir):\n            _dir = log_dir\n        else:\n            _dir = os.path.join(_dir, log_dir)\n        if not os.path.exists(_dir):\n            os.makedirs(_dir)\n\n        self.purge_logs(_dir)\n\n        pattern = log_name.replace('%_', '@@NUMBER@@')\n        pattern = os.path.join(_dir, strftime(pattern))\n        n = 0\n        while True:\n            filename = pattern.replace('@@NUMBER@@', str(n))\n            if not os.path.exists(filename):\n                break\n            n += 1\n            if n > 10000:  # prevent maybe flooding ?\n                raise Exception('Too many logfile, remove them')\n\n        if FileHandler.filename == filename and FileHandler.fd is not None:\n            return\n        FileHandler.filename = filename\n        if FileHandler.fd is not None:\n            FileHandler.fd.close()\n        FileHandler.fd = open(filename, 'w')\n\n        Logger.info('Logger: Record log in %s' % filename)\n\n    def _write_message(self, record):\n        if FileHandler.fd in (None, False):\n            return\n\n        FileHandler.fd.write('[%-18s] ' % record.levelname)\n        try:\n            FileHandler.fd.write(record.msg)\n        except UnicodeEncodeError:\n            if PY2:\n                FileHandler.fd.write(record.msg.encode('utf8'))\n        FileHandler.fd.write('\\n')\n        FileHandler.fd.flush()\n\n    def emit(self, message):\n        # during the startup, store the message in the history\n        if Logger.logfile_activated is None:\n            FileHandler.history += [message]\n            return\n\n        # startup done, if the logfile is not activated, avoid history.\n        if Logger.logfile_activated is False:\n            FileHandler.history = []\n            return\n\n        if FileHandler.fd is None:\n            try:\n                self._configure()\n                from kivy.config import Config\n                Config.add_callback(self._configure, 'kivy', 'log_dir')\n                Config.add_callback(self._configure, 'kivy', 'log_name')\n            except Exception:\n                # deactivate filehandler...\n                FileHandler.fd = False\n                Logger.exception('Error while activating FileHandler logger')\n                return\n            while FileHandler.history:\n                _message = FileHandler.history.pop()\n                self._write_message(_message)\n\n        self._write_message(message)\n\n\nclass LoggerHistory(logging.Handler):\n\n    history = []\n\n    def emit(self, message):\n        LoggerHistory.history = [message] + LoggerHistory.history[:100]\n\n\nclass ColoredFormatter(logging.Formatter):\n\n    def __init__(self, msg, use_color=True):\n        logging.Formatter.__init__(self, msg)\n        self.use_color = use_color\n\n    def format(self, record):\n        try:\n            msg = record.msg.split(':', 1)\n            if len(msg) == 2:\n                record.msg = '[%-12s]%s' % (msg[0], msg[1])\n        except:\n            pass\n        levelname = record.levelname\n        if record.levelno == logging.TRACE:\n            levelname = 'TRACE'\n            record.levelname = levelname\n        if self.use_color and levelname in COLORS:\n            levelname_color = (\n                COLOR_SEQ % (30 + COLORS[levelname]) + levelname + RESET_SEQ)\n            record.levelname = levelname_color\n        return logging.Formatter.format(self, record)\n\n\nclass ConsoleHandler(logging.StreamHandler):\n\n    def filter(self, record):\n        try:\n            msg = record.msg\n            k = msg.split(':', 1)\n            if k[0] == 'stderr' and len(k) == 2:\n                previous_stderr.write(k[1] + '\\n')\n                return False\n        except:\n            pass\n        return True\n\n\nclass LogFile(object):\n\n    def __init__(self, channel, func):\n        self.buffer = ''\n        self.func = func\n        self.channel = channel\n        self.errors = ''\n\n    def write(self, s):\n        s = self.buffer + s\n        self.flush()\n        f = self.func\n        channel = self.channel\n        lines = s.split('\\n')\n        for l in lines[:-1]:\n            f('%s: %s' % (channel, l))\n        self.buffer = lines[-1]\n\n    def flush(self):\n        return\n\n\ndef logger_config_update(section, key, value):\n    if LOG_LEVELS.get(value) is None:\n        raise AttributeError('Loglevel {0!r} doesn\\'t exists'.format(value))\n    Logger.setLevel(level=LOG_LEVELS.get(value))\n\n#: Kivy default logger instance\nLogger = logging.getLogger('kivy')\nLogger.logfile_activated = None\nLogger.trace = partial(Logger.log, logging.TRACE)\n\n# set the Kivy logger as the default\nlogging.root = Logger\n\n# add default kivy logger\nLogger.addHandler(LoggerHistory())\nif 'KIVY_NO_FILELOG' not in os.environ:\n    Logger.addHandler(FileHandler())\n\n# Use the custom handler instead of streaming one.\nif 'KIVY_NO_CONSOLELOG' not in os.environ:\n    if hasattr(sys, '_kivy_logging_handler'):\n        Logger.addHandler(getattr(sys, '_kivy_logging_handler'))\n    else:\n        use_color = (\n            os.name != 'nt' and\n            os.environ.get('KIVY_BUILD') not in ('android', 'ios') and\n            os.environ.get('TERM') in (\n                'xterm', 'rxvt', 'rxvt-unicode', 'xterm-256color'))\n        color_fmt = formatter_message(\n            '[%(levelname)-18s] %(message)s', use_color)\n        formatter = ColoredFormatter(color_fmt, use_color=use_color)\n        console = ConsoleHandler()\n        console.setFormatter(formatter)\n        Logger.addHandler(console)\n\n# install stderr handlers\nsys.stderr = LogFile('stderr', Logger.warning)\n\n#: Kivy history handler\nLoggerHistory = LoggerHistory\n"
  },
  {
    "path": "tickeys/kivy/metrics.py",
    "content": "'''\nMetrics\n=======\n\n.. versionadded:: 1.5.0\n\nA screen is defined by its physical size, density and resolution. These\nfactors are essential for creating UI's with correct size everywhere.\n\nIn Kivy, all the graphics pipelines work with pixels. But using pixels as a\nmeasurement unit is problematic because sizes change according to the\nscreen.\n\nDimensions\n----------\n\nIf you want to design your UI for different screen sizes, you will want better\nmeasurement units to work with. Kivy provides some more scalable alternatives.\n\n:Units:\n    `pt`\n        Points - 1/72 of an inch based on the physical size of the screen.\n        Prefer to use sp instead of pt.\n    `mm`\n        Millimeters - Based on the physical size of the screen.\n    `cm`\n        Centimeters - Based on the physical size of the screen.\n    `in`\n        Inches - Based on the physical size of the screen.\n    `dp`\n        Density-independent Pixels - An abstract unit that is based on the\n        physical density of the screen. With a :attr:`~MetricsBase.density` of\n        1, 1dp is equal to 1px. When running on a higher density screen, the\n        number of pixels used to draw 1dp is scaled up a factor appropriate to\n        the screen's dpi, and the inverse for a lower dpi.\n        The ratio of dp-to-pixels will change with the screen density, but not\n        necessarily in direct proportion. Using the dp unit is a simple\n        solution to making the view dimensions in your layout resize\n        properly for different screen densities. In others words, it\n        provides consistency for the real-world size of your UI across\n        different devices.\n    `sp`\n        Scale-independent Pixels - This is like the dp unit, but it is also\n        scaled by the user's font size preference. We recommend you use this\n        unit when specifying font sizes, so the font size will be adjusted to\n        both the screen density and the user's preference.\n\nExamples\n--------\n\nHere is an example of creating a label with a sp font_size and setting the\nheight manually with a 10dp margin::\n\n    #:kivy 1.5.0\n    <MyWidget>:\n        Label:\n            text: 'Hello world'\n            font_size: '15sp'\n            size_hint_y: None\n            height: self.texture_size[1] + dp(10)\n\nManual control of metrics\n-------------------------\n\nThe metrics cannot be changed at runtime. Once a value has been converted to\npixels, you can't retrieve the original value anymore. This stems from the fact\nthat the DPI and density of a device cannot be changed at runtime.\n\nWe provide some environment variables to control metrics:\n\n- `KIVY_METRICS_DENSITY`: if set, this value will be used for\n  :attr:`~MetricsBase.density` instead of the systems one. On android,\n  the value varies between 0.75, 1, 1.5 and 2.\n\n- `KIVY_METRICS_FONTSCALE`: if set, this value will be used for\n  :attr:`~MetricsBase.fontscale` instead of the systems one. On android, the\n  value varies between 0.8 and 1.2.\n\n- `KIVY_DPI`: if set, this value will be used for :attr:`~MetricsBase.dpi`.\n  Please\n  note that setting the DPI will not impact the dp/sp notation because these\n  are based on the screen density.\n\nFor example, if you want to simulate a high-density screen (like the HTC One\nX)::\n\n    KIVY_DPI=320 KIVY_METRICS_DENSITY=2 python main.py --size 1280x720\n\nOr a medium-density (like Motorola Droid 2)::\n\n    KIVY_DPI=240 KIVY_METRICS_DENSITY=1.5 python main.py --size 854x480\n\nYou can also simulate an alternative user preference for fontscale as follows::\n\n    KIVY_METRICS_FONTSCALE=1.2 python main.py\n\n'''\n\n\n__all__ = ('Metrics', 'MetricsBase', 'pt', 'inch', 'cm', 'mm', 'dp', 'sp',\n           'metrics')\n\n\nfrom os import environ\nfrom kivy.utils import reify, platform\nfrom kivy.properties import dpi2px\n\n\ndef pt(value):\n    '''Convert from points to pixels\n    '''\n    return dpi2px(value, 'pt')\n\n\ndef inch(value):\n    '''Convert from inches to pixels\n    '''\n    return dpi2px(value, 'in')\n\n\ndef cm(value):\n    '''Convert from centimeters to pixels\n    '''\n    return dpi2px(value, 'cm')\n\n\ndef mm(value):\n    '''Convert from millimeters to pixels\n    '''\n    return dpi2px(value, 'mm')\n\n\ndef dp(value):\n    '''Convert from density-independent pixels to pixels\n    '''\n    return dpi2px(value, 'dp')\n\n\ndef sp(value):\n    '''Convert from scale-independent pixels to pixels\n    '''\n    return dpi2px(value, 'sp')\n\n\nclass MetricsBase(object):\n    '''Class that contains the default attributes for Metrics. Don't use this\n    class directly, but use the `Metrics` instance.\n    '''\n\n    @reify\n    def dpi(self):\n        '''Return the DPI of the screen. Depending on the platform, the DPI can\n        be taken from the Window provider (Desktop mainly) or from a\n        platform-specific module (like android/ios).\n        '''\n        custom_dpi = environ.get('KIVY_DPI')\n        if custom_dpi:\n            return float(custom_dpi)\n\n        if platform == 'android':\n            import android\n            return android.get_dpi()\n        elif platform == 'ios':\n            import ios\n            return ios.get_dpi()\n\n        # for all other platforms..\n        from kivy.base import EventLoop\n        EventLoop.ensure_window()\n        return EventLoop.window.dpi\n\n    @reify\n    def dpi_rounded(self):\n        '''Return the DPI of the screen, rounded to the nearest of 120, 160,\n        240 or 320.\n        '''\n        dpi = self.dpi\n        if dpi < 140:\n            return 120\n        elif dpi < 200:\n            return 160\n        elif dpi < 280:\n            return 240\n        return 320\n\n    @reify\n    def density(self):\n        '''Return the density of the screen. This value is 1 by default\n        on desktops but varies on android depending on the screen.\n        '''\n        custom_density = environ.get('KIVY_METRICS_DENSITY')\n        if custom_density:\n            return float(custom_density)\n\n        if platform == 'android':\n            import jnius\n            Hardware = jnius.autoclass('org.renpy.android.Hardware')\n            return Hardware.metrics.scaledDensity\n        elif platform == 'ios':\n            # 0.75 is for mapping the same density as android tablet\n            import ios\n            return ios.get_scale() * 0.75\n        elif platform == 'macosx':\n            from kivy.base import EventLoop\n            EventLoop.ensure_window()\n            return  EventLoop.window.dpi / 96.\n\n        return 1.0\n\n    @reify\n    def fontscale(self):\n        '''Return the fontscale user preference. This value is 1 by default but\n        can vary between 0.8 and 1.2.\n        '''\n        custom_fontscale = environ.get('KIVY_METRICS_FONTSCALE')\n        if custom_fontscale:\n            return float(custom_fontscale)\n\n        if platform == 'android':\n            from jnius import autoclass\n            PythonActivity = autoclass('org.renpy.android.PythonActivity')\n            config = PythonActivity.mActivity.getResources().getConfiguration()\n            return config.fontScale\n\n        return 1.0\n\n\n#: Default instance of :class:`MetricsBase`, used everywhere in the code\n#: .. versionadded:: 1.7.0\nMetrics = MetricsBase()\n\n#: default instance of :class:`MetricsBase`, used everywhere in the code\n#: (deprecated, use `Metrics` instead.)\nmetrics = Metrics\n"
  },
  {
    "path": "tickeys/kivy/modules/__init__.py",
    "content": "'''\nModules\n=======\n\nModules are classes that can be loaded when a Kivy application is starting. The\nloading of modules is managed by the config file. Currently, we include:\n\n    * :class:`~kivy.modules.touchring`: Draw a circle around each touch.\n    * :class:`~kivy.modules.monitor`: Add a red topbar that indicates the FPS\n      and a small graph indicating input activity.\n    * :class:`~kivy.modules.keybinding`: Bind some keys to actions, such as a\n      screenshot.\n    * :class:`~kivy.modules.recorder`: Record and playback a sequence of\n      events.\n    * :class:`~kivy.modules.screen`: Emulate the characteristics (dpi/density/\n      resolution) of different screens.\n    * :class:`~kivy.modules.inspector`: Examines your widget hierarchy and\n      widget properties.\n    * :class:`~kivy.modules.webdebugger`: Realtime examination of your app\n      internals via a web browser.\n\nModules are automatically loaded from the Kivy path and User path:\n\n    * `PATH_TO_KIVY/kivy/modules`\n    * `HOME/.kivy/mods`\n\nActivating a module\n-------------------\n\nThere are various ways in which you can activate a kivy module.\n\nActivate a module in the config\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nTo activate a module this way, you can edit your configuration file (in your\n`HOME/.kivy/config.ini`)::\n\n    [modules]\n    # uncomment to activate\n    touchring =\n    # monitor =\n    # keybinding =\n\nOnly the name of the module followed by \"=\" is sufficient to activate the\nmodule.\n\nActivate a module in Python\n^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nBefore starting your application, preferably at the start of your import, you\ncan do something like this::\n\n    import kivy\n    kivy.require('1.0.8')\n\n    # Activate the touchring module\n    from kivy.config import Config\n    Config.set('modules', 'touchring', '')\n\nActivate a module via the commandline\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWhen starting your application from the commandline, you can add a\n*-m <modulename>* to the arguments. For example::\n\n    python main.py -m webdebugger\n\n.. note::\n    Some modules, such as the screen, may require additional parameters. They\n    will, however, print these parameters to the console when launched without\n    them.\n\n\nCreate your own module\n----------------------\n\nCreate a file in your `HOME/.kivy/mods`, and create 2 functions::\n\n    def start(win, ctx):\n        pass\n\n    def stop(win, ctx):\n        pass\n\nStart/stop are functions that will be called for every window opened in\nKivy. When you are starting a module, you can use these to store and\nmanage the module state. Use the `ctx` variable as a dictionary. This\ncontext is unique for each instance/start() call of the module, and will\nbe passed to stop() too.\n\n'''\n\n__all__ = ('Modules', )\n\nfrom kivy.config import Config\nfrom kivy.logger import Logger\nimport kivy\nimport os\nimport sys\n\n\nclass ModuleContext:\n    '''Context of a module\n\n    You can access to the config with self.config.\n    '''\n\n    def __init__(self):\n        self.config = {}\n\n    def __repr__(self):\n        return repr(self.config)\n\n\nclass ModuleBase:\n    '''Handle Kivy modules. It will automatically load and instanciate the\n    module for the general window.'''\n\n    def __init__(self, **kwargs):\n        self.mods = {}\n        self.wins = []\n\n    def add_path(self, path):\n        '''Add a path to search for modules in'''\n        if not os.path.exists(path):\n            return\n        if path not in sys.path:\n            sys.path.append(path)\n        dirs = os.listdir(path)\n        for module in dirs:\n            name, ext = os.path.splitext(module)\n            # accept only python extensions\n            if ext not in ('.py', '.pyo', '.pyc') or name == '__init__':\n                continue\n            self.mods[name] = {\n                'name': name,\n                'activated': False,\n                'context': ModuleContext()}\n\n    def list(self):\n        '''Return the list of available modules'''\n        return self.mods\n\n    def import_module(self, name):\n        try:\n            modname = 'kivy.modules.{0}'.format(name)\n            module = __import__(name=modname)\n            module = sys.modules[modname]\n        except ImportError:\n            try:\n                module = __import__(name=name)\n                module = sys.modules[name]\n            except ImportError:\n                Logger.exception('Modules: unable to import <%s>' % name)\n                raise\n        # basic check on module\n        if not hasattr(module, 'start'):\n            Logger.warning('Modules: Module <%s> missing start() function' %\n                           name)\n            return\n        if not hasattr(module, 'stop'):\n            err = 'Modules: Module <%s> missing stop() function' % name\n            Logger.warning(err)\n            return\n        self.mods[name]['module'] = module\n\n    def activate_module(self, name, win):\n        '''Activate a module on a window'''\n        if name not in self.mods:\n            Logger.warning('Modules: Module <%s> not found' % name)\n            return\n\n        mod = self.mods[name]\n\n        # ensure the module has been configured\n        if 'module' not in mod:\n            self._configure_module(name)\n\n        pymod = mod['module']\n        if not mod['activated']:\n            context = mod['context']\n            msg = 'Modules: Start <{0}> with config {1}'.format(\n                  name, context)\n            Logger.debug(msg)\n            pymod.start(win, context)\n            mod['activated'] = True\n\n    def deactivate_module(self, name, win):\n        '''Deactivate a module from a window'''\n        if not name in self.mods:\n            Logger.warning('Modules: Module <%s> not found' % name)\n            return\n        if not 'module' in self.mods[name]:\n            return\n\n        module = self.mods[name]['module']\n        if self.mods[name]['activated']:\n            module.stop(win, self.mods[name]['context'])\n            self.mods[name]['activated'] = False\n\n    def register_window(self, win):\n        '''Add the window to the window list'''\n        if win not in self.wins:\n            self.wins.append(win)\n        self.update()\n\n    def unregister_window(self, win):\n        '''Remove the window from the window list'''\n        if win in self.wins:\n            self.wins.remove(win)\n        self.update()\n\n    def update(self):\n        '''Update the status of the module for each window'''\n        modules_to_activate = [x[0] for x in Config.items('modules')]\n        for win in self.wins:\n            for name in self.mods:\n                if not name in modules_to_activate:\n                    self.deactivate_module(name, win)\n            for name in modules_to_activate:\n                try:\n                    self.activate_module(name, win)\n                except:\n                    import traceback\n                    traceback.print_exc()\n                    raise\n\n    def configure(self):\n        '''(internal) Configure all the modules before using them.\n        '''\n        modules_to_configure = [x[0] for x in Config.items('modules')]\n        for name in modules_to_configure:\n            if name not in self.mods:\n                Logger.warning('Modules: Module <%s> not found' % name)\n                continue\n            self._configure_module(name)\n\n    def _configure_module(self, name):\n        if 'module' not in self.mods[name]:\n            try:\n                self.import_module(name)\n            except ImportError:\n                return\n\n        # convert configuration like:\n        # -m mjpegserver:port=8080,fps=8\n        # and pass it in context.config token\n        config = dict()\n\n        args = Config.get('modules', name)\n        if args != '':\n            values = Config.get('modules', name).split(',')\n            for value in values:\n                x = value.split('=', 1)\n                if len(x) == 1:\n                    config[x[0]] = True\n                else:\n                    config[x[0]] = x[1]\n\n        self.mods[name]['context'].config = config\n\n        # call configure if module have one\n        if hasattr(self.mods[name]['module'], 'configure'):\n            self.mods[name]['module'].configure(config)\n\n    def usage_list(self):\n        print()\n        print('Available modules')\n        print('=================')\n        for module in self.list():\n            if not 'module' in self.mods[module]:\n                self.import_module(module)\n            text = self.mods[module]['module'].__doc__.strip(\"\\n \")\n            print('%-12s: %s' % (module, text))\n        print()\n\nModules = ModuleBase()\nModules.add_path(kivy.kivy_modules_dir)\nif not 'KIVY_DOC' in os.environ:\n    Modules.add_path(kivy.kivy_usermodules_dir)\n\nif __name__ == '__main__':\n    print(Modules.list())\n"
  },
  {
    "path": "tickeys/kivy/modules/_webdebugger.py",
    "content": "# -*- coding: utf-8 -*-\n\nimport threading\nimport json\nfrom gc import get_objects, garbage\nfrom kivy.clock import Clock\nfrom kivy.cache import Cache\nfrom collections import OrderedDict\nfrom kivy.logger import Logger\n\ntry:\n    from flask import Flask, render_template_string, make_response\nexcept ImportError:\n    Logger.error('WebDebugger: unable to import Flask. Install it!')\n    raise\n\nhistory_max = 250\n\n\nclass MissingOrderedDict(OrderedDict):\n\n    def __missing__(self, key):\n        self[key] = [0] * history_max\n        return self[key]\n\n\nmetrics = MissingOrderedDict()\napp = Flask(__name__)\n\n\n@app.route('/')\ndef index():\n    return render_template_string(html_index)\n\n\n@app.route('/metrics.json')\ndef metrics_json():\n    resp = make_response(json.dumps(metrics), 200)\n    resp.headers['Content-Type'] = 'text/json'\n    return resp\n\n\n@app.route('/f/<name>')\ndef getfile(name):\n    name = name.replace('.', '_')\n    text = globals()[name]\n    resp = make_response(text, 200)\n    if name.endswith('_js'):\n        resp.headers['Content-Type'] = 'text/javascript'\n    elif name.endswith('_jpg'):\n        resp.headers['Content-Type'] = 'image/jpeg'\n    return resp\n\n\nclass FlaskThread(threading.Thread):\n\n    def run(self):\n        Clock.schedule_interval(self.dump_metrics, .1)\n        app.run(debug=True, use_debugger=True, use_reloader=False)\n\n    def dump_metrics(self, dt):\n        m = metrics\n        m['Python objects'].append(len(get_objects()))\n        m['Python garbage'].append(len(garbage))\n        m['FPS (internal)'].append(Clock.get_fps())\n        m['FPS (real)'].append(Clock.get_rfps())\n        m['Events'].append(sum([len(x) for x in Clock._events.values()]))\n        for category in Cache._categories:\n            m['Cache ' + category].append(\n                len(Cache._objects.get(category, [])))\n        for values in m.values():\n            values.pop(0)\n            values[0] = 0\n\n\ndef start(win, ctx):\n    ctx.thread = FlaskThread()\n    ctx.thread.daemon = True\n    ctx.thread.start()\n\n\ndef stop(win, ctx):\n    pass\n\n# -----------------------------------------------------------------------------\n# DATA FILES\n# -----------------------------------------------------------------------------\n\nhtml_index = '''\n<html>\n<head>\n<title>Kivy - Web Debugger</title>\n<script type='text/javascript' src='/f/jquery.js'></script>\n<script type='text/javascript' src='/f/raphael.js'></script>\n<script type='text/javascript' src='/f/g_raphael.js'></script>\n<script type='text/javascript' src='/f/g_raphael_line.js'></script>\n<style type='text/css'>\nbody {\n    font-family: Arial, Helvetica, sans-serif;\n    font-size: 13px;\n    color: #eee;\n    background: url('/f/background.jpg') repeat-x #718693;\n}\n\n.panel {\n    width: 400px;\n    float: left;\n    background-color: #BCCAD5;\n    margin: 0px 10px 10px 0px;\n    padding: 20px;\n    -moz-border-radius: 16px;\n    -webkit-border-radius: 16px;\n    border-radius: 16px;\n}\n\n.panel h2 {\n    margin: 0px;\n    padding: 0px 0px 10px 0px;\n    color: #516673;\n}\n\n</style>\n<script type='text/javascript'>\n\nvar graphics = {};\nvar rid = 0;\nvar ids = {}\n\nfunction request_metrics() {\n    $.ajax({\n    url: '/metrics.json',\n    error: function(xhr, status) {\n        $('#error').html('Connection lost').show();\n        setTimeout('request_metrics()', 1000);\n    },\n    success: function(data) {\n        $('#error').hide();\n        for (var key in data) {\n            if ( typeof(graphics[key]) == 'undefined' ) {\n                rid += 1;\n                $('<div class=\"panel panel' + rid + '\"><div id=\"r' + rid + '\"></div></div>').appendTo($('#metrics'));\n                $('.panel' + rid).prepend(\n                    $('<h2 id=\"h' + rid + '\"></h2>').html(key));\n                graphics[key] = Raphael('r' + rid, 400, 150);\n                ids[key] = rid;\n            }\n\n            var indices = [];\n            for (var i = 0; i < data[key].length; i++)\n                indices[i] = i;\n            var r = graphics[key];\n            $('#h'+ids[key]).html(key + ': ' + data[key][i-1]);\n            r.clear();\n            r.linechart(26, 0, 340, 150, indices, data[key], {\n                shade: true, axis: \"0 1 0 1\" });\n        }\n        setTimeout('request_metrics()', 250);\n    }\n    });\n}\n\nrequest_metrics();\n\n</script>\n</head>\n<body>\n<h1>Kivy - Web Debugger</h1>\n<div id='error'></div>\n\n<h2>Metrics</h2>\n<div id='metrics'>\n</div>\n</body>\n</html>\n'''\n\njquery_js = r'''\n/*! jQuery v1.7.1 jquery.com | jquery.org/license */\n(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f(\"<\"+a+\">\").appendTo(b),e=d.css(\"display\");d.remove();if(e===\"none\"||e===\"\"){cl||(cl=c.createElement(\"iframe\"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode===\"CSS1Compat\"?\"<!doctype html>\":\"\")+\"<html><body>\"),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,\"display\"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject(\"Microsoft.XMLHTTP\")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h==\"string\"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k===\"*\")k=l;else if(l!==\"*\"&&l!==k){m=l+\" \"+k,n=e[m]||e[\"* \"+k];if(!n){p=b;for(o in e){j=o.split(\" \");if(j[0]===l||j[0]===\"*\"){p=e[j[1]+\" \"+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error(\"No conversion from \"+m.replace(\" \",\" to \")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function cb(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]===\"*\")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader(\"content-type\"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+\" \"+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function ca(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bE.test(a)?d(a,e):ca(a+\"[\"+(typeof e==\"object\"||f.isArray(e)?b:\"\")+\"]\",e,c,d)});else if(!c&&b!=null&&typeof b==\"object\")for(var e in b)ca(a+\"[\"+e+\"]\",b[e],c,d);else d(a,b)}function b_(a,c){var d,e,g=f.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((g[d]?a:e||(e={}))[d]=c[d]);e&&f.extend(!0,a,e)}function b$(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bT,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l==\"string\"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=b$(a,c,d,e,l,g)));(k||!l)&&!g[\"*\"]&&(l=b$(a,c,d,e,\"*\",g));return l}function bZ(a){return function(b,c){typeof b!=\"string\"&&(c=b,b=\"*\");if(f.isFunction(c)){var d=b.toLowerCase().split(bP),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\\+/.test(h),j&&(h=h.substr(1)||\"*\"),i=a[h]=a[h]||[],i[j?\"unshift\":\"push\"](c)}}}function bC(a,b,c){var d=b===\"width\"?a.offsetWidth:a.offsetHeight,e=b===\"width\"?bx:by,g=0,h=e.length;if(d>0){if(c!==\"border\")for(;g<h;g++)c||(d-=parseFloat(f.css(a,\"padding\"+e[g]))||0),c===\"margin\"?d+=parseFloat(f.css(a,c+e[g]))||0:d-=parseFloat(f.css(a,\"border\"+e[g]+\"Width\"))||0;return d+\"px\"}d=bz(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0;if(c)for(;g<h;g++)d+=parseFloat(f.css(a,\"padding\"+e[g]))||0,c!==\"padding\"&&(d+=parseFloat(f.css(a,\"border\"+e[g]+\"Width\"))||0),c===\"margin\"&&(d+=parseFloat(f.css(a,c+e[g]))||0);return d+\"px\"}function bp(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:\"script\"}):f.globalEval((b.text||b.textContent||b.innerHTML||\"\").replace(bf,\"/*$0*/\")),b.parentNode&&b.parentNode.removeChild(b)}function bo(a){var b=c.createElement(\"div\");bh.appendChild(b),b.innerHTML=a.outerHTML;return b.firstChild}function bn(a){var b=(a.nodeName||\"\").toLowerCase();b===\"input\"?bm(a):b!==\"script\"&&typeof a.getElementsByTagName!=\"undefined\"&&f.grep(a.getElementsByTagName(\"input\"),bm)}function bm(a){if(a.type===\"checkbox\"||a.type===\"radio\")a.defaultChecked=a.checked}function bl(a){return typeof a.getElementsByTagName!=\"undefined\"?a.getElementsByTagName(\"*\"):typeof a.querySelectorAll!=\"undefined\"?a.querySelectorAll(\"*\"):[]}function bk(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c===\"object\")b.outerHTML=a.outerHTML;else if(c!==\"input\"||a.type!==\"checkbox\"&&a.type!==\"radio\"){if(c===\"option\")b.selected=a.defaultSelected;else if(c===\"input\"||c===\"textarea\")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bj(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c,d,e,g=f._data(a),h=f._data(b,g),i=g.events;if(i){delete h.handle,h.events={};for(c in i)for(d=0,e=i[c].length;d<e;d++)f.event.add(b,c+(i[c][d].namespace?\".\":\"\")+i[c][d].namespace,i[c][d],i[c][d].data)}h.data&&(h.data=f.extend({},h.data))}}function bi(a,b){return f.nodeName(a,\"table\")?a.getElementsByTagName(\"tbody\")[0]||a.appendChild(a.ownerDocument.createElement(\"tbody\")):a}function U(a){var b=V.split(\"|\"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function T(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b==\"string\"){var d=f.grep(a,function(a){return a.nodeType===1});if(O.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+\"defer\",e=b+\"queue\",g=b+\"mark\",h=f._data(a,d);h&&(c===\"queue\"||!f._data(a,e))&&(c===\"mark\"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b===\"data\"&&f.isEmptyObject(a[b]))continue;if(b!==\"toJSON\")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e=\"data-\"+c.replace(k,\"-$1\").toLowerCase();d=a.getAttribute(e);if(typeof d==\"string\"){try{d=d===\"true\"?!0:d===\"false\"?!1:d===\"null\"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\\s+/);for(c=0,d=a.length;c<d;c++)b[a[c]]=!0;return b}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll(\"left\")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\\w\\W]+>)[^>]*$|#([\\w\\-]*)$)/,j=/\\S/,k=/^\\s+/,l=/\\s+$/,m=/^<(\\w+)\\s*\\/?>(?:<\\/\\1>)?$/,n=/^[\\],:{}\\s]*$/,o=/\\\\(?:[\"\\\\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/\"[^\"\\\\\\n\\r]*\"|true|false|null|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?/g,q=/(?:^|:|,)(?:\\s*\\[)+/g,r=/(webkit)[ \\/]([\\w.]+)/,s=/(opera)(?:.*version)?[ \\/]([\\w.]+)/,t=/(msie) ([\\w.]+)/,u=/(mozilla)(?:.*? rv:([\\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+\"\").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a===\"body\"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a==\"string\"){a.charAt(0)!==\"<\"||a.charAt(a.length-1)!==\">\"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:\"\",jquery:\"1.7.1\",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b===\"find\"?d.selector=this.selector+(this.selector?\" \":\"\")+c:b&&(d.selector=this.selector+\".\"+b+\"(\"+c+\")\");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),\"slice\",F.call(arguments).join(\",\"))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i==\"boolean\"&&(l=i,i=arguments[1]||{},j=2),typeof i!=\"object\"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger(\"ready\").off(\"ready\")}},bindReady:function(){if(!A){A=e.Callbacks(\"once memory\");if(c.readyState===\"complete\")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener(\"DOMContentLoaded\",B,!1),a.addEventListener(\"load\",e.ready,!1);else if(c.attachEvent){c.attachEvent(\"onreadystatechange\",B),a.attachEvent(\"onload\",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)===\"function\"},isArray:Array.isArray||function(a){return e.type(a)===\"array\"},isWindow:function(a){return a&&typeof a==\"object\"&&\"setInterval\"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||\"object\"},isPlainObject:function(a){if(!a||e.type(a)!==\"object\"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,\"constructor\")&&!D.call(a.constructor.prototype,\"isPrototypeOf\"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!=\"string\"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,\"@\").replace(p,\"]\").replace(q,\"\")))return(new Function(\"return \"+b))();e.error(\"Invalid JSON: \"+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,\"text/xml\")):(d=new ActiveXObject(\"Microsoft.XMLDOM\"),d.async=\"false\",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName(\"parsererror\").length)&&e.error(\"Invalid XML: \"+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,\"ms-\").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:G?function(a){return a==null?\"\":G.call(a)}:function(a){return a==null?\"\":(a+\"\").replace(k,\"\").replace(l,\"\")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d===\"string\"||d===\"function\"||d===\"regexp\"||e.isWindow(a)?E.call(c,a):e.merge(c,a)}return c},inArray:function(a,b,c){var d;if(b){if(H)return H.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length==\"number\")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j==\"number\"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c==\"string\"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=F.call(arguments,2),g=function(){return a.apply(c,f.concat(F.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h){var i=a.length;if(typeof c==\"object\"){for(var j in c)e.access(a,j,c[j],f,g,d);return a}if(d!==b){f=!h&&f&&e.isFunction(d);for(var k=0;k<i;k++)g(a[k],c,f?d.call(a[k],k,g(a[k],c)):d,h);return a}return i?g(a[0],c):b},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf(\"compatible\")<0&&u.exec(a)||[];return{browser:b[1]||\"\",version:b[2]||\"0\"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each(\"Boolean Number String Function Array Date RegExp Object\".split(\" \"),function(a,b){I[\"[object \"+b+\"]\"]=b.toLowerCase()}),z=e.uaMatch(y),z.browser&&(e.browser[z.browser]=!0,e.browser.version=z.version),e.browser.webkit&&(e.browser.safari=!0),j.test(\" \")&&(k=/^[\\s\\xA0]+/,l=/[\\s\\xA0]+$/),h=e(c),c.addEventListener?B=function(){c.removeEventListener(\"DOMContentLoaded\",B,!1),e.ready()}:c.attachEvent&&(B=function(){c.readyState===\"complete\"&&(c.detachEvent(\"onreadystatechange\",B),e.ready())});return e}(),g={};f.Callbacks=function(a){a=a?g[a]||h(a):{};var c=[],d=[],e,i,j,k,l,m=function(b){var d,e,g,h,i;for(d=0,e=b.length;d<e;d++)g=b[d],h=f.type(g),h===\"array\"?m(g):h===\"function\"&&(!a.unique||!o.has(g))&&c.push(g)},n=function(b,f){f=f||[],e=!a.memory||[b,f],i=!0,l=j||0,j=0,k=c.length;for(;c&&l<k;l++)if(c[l].apply(b,f)===!1&&a.stopOnFalse){e=!0;break}i=!1,c&&(a.once?e===!0?o.disable():c=[]:d&&d.length&&(e=d.shift(),o.fireWith(e[0],e[1])))},o={add:function(){if(c){var a=c.length;m(arguments),i?k=c.length:e&&e!==!0&&(j=a,n(e[0],e[1]))}return this},remove:function(){if(c){var b=arguments,d=0,e=b.length;for(;d<e;d++)for(var f=0;f<c.length;f++)if(b[d]===c[f]){i&&f<=k&&(k--,f<=l&&l--),c.splice(f--,1);if(a.unique)break}}return this},has:function(a){if(c){var b=0,d=c.length;for(;b<d;b++)if(a===c[b])return!0}return!1},empty:function(){c=[];return this},disable:function(){c=d=e=b;return this},disabled:function(){return!c},lock:function(){d=b,(!e||e===!0)&&o.disable();return this},locked:function(){return!d},fireWith:function(b,c){d&&(i?a.once||d.push([b,c]):(!a.once||!e)&&n(b,c));return this},fire:function(){o.fireWith(this,arguments);return this},fired:function(){return!!e}};return o};var i=[].slice;f.extend({Deferred:function(a){var b=f.Callbacks(\"once memory\"),c=f.Callbacks(\"once memory\"),d=f.Callbacks(\"memory\"),e=\"pending\",g={resolve:b,reject:c,notify:d},h={done:b.add,fail:c.add,progress:d.add,state:function(){return e},isResolved:b.fired,isRejected:c.fired,then:function(a,b,c){i.done(a).fail(b).progress(c);return this},always:function(){i.done.apply(i,arguments).fail.apply(i,arguments);return this},pipe:function(a,b,c){return f.Deferred(function(d){f.each({done:[a,\"resolve\"],fail:[b,\"reject\"],progress:[c,\"notify\"]},function(a,b){var c=b[0],e=b[1],g;f.isFunction(c)?i[a](function(){g=c.apply(this,arguments),g&&f.isFunction(g.promise)?g.promise().then(d.resolve,d.reject,d.notify):d[e+\"With\"](this===i?d:this,[g])}):i[a](d[e])})}).promise()},promise:function(a){if(a==null)a=h;else for(var b in h)a[b]=h[b];return a}},i=h.promise({}),j;for(j in g)i[j]=g[j].fire,i[j+\"With\"]=g[j].fireWith;i.done(function(){e=\"resolved\"},c.disable,d.lock).fail(function(){e=\"rejected\"},b.disable,d.lock),a&&a.call(i,i);return i},when:function(a){function m(a){return function(b){e[a]=arguments.length>1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c<d;c++)b[c]&&b[c].promise&&f.isFunction(b[c].promise)?b[c].promise().then(l(c),j.reject,m(c)):--g;g||j.resolveWith(j,b)}else j!==a&&j.resolveWith(j,d?[a]:[]);return k}}),f.support=function(){var b,d,e,g,h,i,j,k,l,m,n,o,p,q=c.createElement(\"div\"),r=c.documentElement;q.setAttribute(\"className\",\"t\"),q.innerHTML=\"   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>\",d=q.getElementsByTagName(\"*\"),e=q.getElementsByTagName(\"a\")[0];if(!d||!d.length||!e)return{};g=c.createElement(\"select\"),h=g.appendChild(c.createElement(\"option\")),i=q.getElementsByTagName(\"input\")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName(\"tbody\").length,htmlSerialize:!!q.getElementsByTagName(\"link\").length,style:/top/.test(e.getAttribute(\"style\")),hrefNormalized:e.getAttribute(\"href\")===\"/a\",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value===\"on\",optSelected:h.selected,getSetAttribute:q.className!==\"t\",enctype:!!c.createElement(\"form\").enctype,html5Clone:c.createElement(\"nav\").cloneNode(!0).outerHTML!==\"<:nav></:nav>\",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent(\"onclick\",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent(\"onclick\")),i=c.createElement(\"input\"),i.value=\"t\",i.setAttribute(\"type\",\"radio\"),b.radioValue=i.value===\"t\",i.setAttribute(\"checked\",\"checked\"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML=\"\",a.getComputedStyle&&(j=c.createElement(\"div\"),j.style.width=\"0\",j.style.marginRight=\"0\",q.style.width=\"2px\",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n=\"on\"+o,p=n in q,p||(q.setAttribute(n,\"return;\"),p=typeof q[n]==\"function\"),b[o+\"Bubbles\"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName(\"body\")[0];!r||(j=1,k=\"position:absolute;top:0;left:0;width:1px;height:1px;margin:0;\",m=\"visibility:hidden;border:0;\",n=\"style='\"+k+\"border:5px solid #000;padding:0;'\",o=\"<div \"+n+\"><div></div></div>\"+\"<table \"+n+\" cellpadding='0' cellspacing='0'>\"+\"<tr><td></td></tr></table>\",a=c.createElement(\"div\"),a.style.cssText=m+\"width:0;height:0;position:static;top:0;margin-top:\"+j+\"px\",r.insertBefore(a,r.firstChild),q=c.createElement(\"div\"),a.appendChild(q),q.innerHTML=\"<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>\",l=q.getElementsByTagName(\"td\"),p=l[0].offsetHeight===0,l[0].style.display=\"\",l[1].style.display=\"none\",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML=\"\",q.style.width=q.style.paddingLeft=\"1px\",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!=\"undefined\"&&(q.style.display=\"inline\",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display=\"\",q.innerHTML=\"<div style='width:4px;'></div>\",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position=\"fixed\",e.style.top=\"20px\",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top=\"\",d.style.overflow=\"hidden\",d.style.position=\"relative\",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\\{.*\\}|\\[.*\\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:\"jQuery\"+(f.fn.jquery+Math.random()).replace(/\\D/g,\"\"),noData:{embed:!0,object:\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c==\"string\",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c===\"events\";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c==\"object\"||typeof c==\"function\")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(\" \")));for(e=0,g=b.length;e<g;e++)delete d[b[e]];if(!(c?m:f.isEmptyObject)(d))return}}if(!c){delete j[k].data;if(!m(j[k]))return}f.support.deleteExpando||!j.setInterval?delete j[k]:j[k]=null,i&&(f.support.deleteExpando?delete a[h]:a.removeAttribute?a.removeAttribute(h):a[h]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute(\"classid\")===b}return!0}}),f.fn.extend({data:function(a,c){var d,e,g,h=null;if(typeof a==\"undefined\"){if(this.length){h=f.data(this[0]);if(this[0].nodeType===1&&!f._data(this[0],\"parsedAttrs\")){e=this[0].attributes;for(var i=0,j=e.length;i<j;i++)g=e[i].name,g.indexOf(\"data-\")===0&&(g=f.camelCase(g.substring(5)),l(this[0],g,h[g]));f._data(this[0],\"parsedAttrs\",!0)}}return h}if(typeof a==\"object\")return this.each(function(){f.data(this,a)});d=a.split(\".\"),d[1]=d[1]?\".\"+d[1]:\"\";if(c===b){h=this.triggerHandler(\"getData\"+d[1]+\"!\",[d[0]]),h===b&&this.length&&(h=f.data(this[0],a),h=l(this[0],a,h));return h===b&&d[1]?this.data(d[0]):h}return this.each(function(){var b=f(this),e=[d[0],c];b.triggerHandler(\"setData\"+d[1]+\"!\",e),f.data(this,a,c),b.triggerHandler(\"changeData\"+d[1]+\"!\",e)})},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||\"fx\")+\"mark\",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||\"fx\";var d=c+\"mark\",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,\"mark\"))}},queue:function(a,b,c){var d;if(a){b=(b||\"fx\")+\"queue\",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||\"fx\";var c=f.queue(a,b),d=c.shift(),e={};d===\"inprogress\"&&(d=c.shift()),d&&(b===\"fx\"&&c.unshift(\"inprogress\"),f._data(a,b+\".run\",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+\"queue \"+b+\".run\",!0),n(a,b,\"queue\"))}}),f.fn.extend({queue:function(a,c){typeof a!=\"string\"&&(c=a,a=\"fx\");if(c===b)return f.queue(this[0],a);return this.each(function(){var b=f.queue(this,a,c);a===\"fx\"&&b[0]!==\"inprogress\"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||\"fx\";return this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||\"fx\",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!=\"string\"&&(c=a,a=b),a=a||\"fx\";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+\"defer\",j=a+\"queue\",k=a+\"mark\",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f.Callbacks(\"once memory\"),!0))h++,l.add(m);m();return d.promise()}});var o=/[\\n\\t\\r]/g,p=/\\s+/,q=/\\r/g,r=/^(?:button|input)$/i,s=/^(?:button|input|object|select|textarea)$/i,t=/^a(?:rea)?$/i,u=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,v=f.support.getSetAttribute,w,x,y;f.fn.extend({attr:function(a,b){return f.access(this,a,b,!0,f.attr)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,a,b,!0,f.prop)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a==\"string\"){b=a.split(p);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{g=\" \"+e.className+\" \";for(h=0,i=b.length;h<i;h++)~g.indexOf(\" \"+b[h]+\" \")||(g+=b[h]+\" \");e.className=f.trim(g)}}}return this},removeClass:function(a){var c,d,e,g,h,i,j;if(f.isFunction(a))return this.each(function(b){f(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a==\"string\"||a===b){c=(a||\"\").split(p);for(d=0,e=this.length;d<e;d++){g=this[d];if(g.nodeType===1&&g.className)if(a){h=(\" \"+g.className+\" \").replace(o,\" \");for(i=0,j=c.length;i<j;i++)h=h.replace(\" \"+c[i]+\" \",\" \");g.className=f.trim(h)}else g.className=\"\"}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b==\"boolean\";if(f.isFunction(a))return this.each(function(c){f(this).toggleClass(a.call(this,c,this.className,b),b)});return this.each(function(){if(c===\"string\"){var e,g=0,h=f(this),i=b,j=a.split(p);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?\"addClass\":\"removeClass\"](e)}else if(c===\"undefined\"||c===\"boolean\")this.className&&f._data(this,\"__className__\",this.className),this.className=this.className||a===!1?\"\":f._data(this,\"__className__\")||\"\"})},hasClass:function(a){var b=\" \"+a+\" \",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(\" \"+this[c].className+\" \").replace(o,\" \").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h=\"\":typeof h==\"number\"?h+=\"\":f.isArray(h)&&(h=f.map(h,function(a){return a==null?\"\":a+\"\"})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!(\"set\"in c)||c.set(this,h,\"value\")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&\"get\"in c&&(d=c.get(g,\"value\"))!==b)return d;d=g.value;return typeof d==\"string\"?d.replace(q,\"\"):d==null?\"\":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type===\"select-one\";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c<d;c++){e=i[c];if(e.selected&&(f.support.optDisabled?!e.disabled:e.getAttribute(\"disabled\")===null)&&(!e.parentNode.disabled||!f.nodeName(e.parentNode,\"optgroup\"))){b=f(e).val();if(j)return b;h.push(b)}}if(j&&!h.length&&i.length)return f(i[g]).val();return h},set:function(a,b){var c=f.makeArray(b);f(a).find(\"option\").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute==\"undefined\")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&\"set\"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,\"\"+d);return d}if(h&&\"get\"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h<g;h++)e=d[h],e&&(c=f.propFix[e]||e,f.attr(a,e,\"\"),a.removeAttribute(v?e:c),u.test(e)&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(r.test(a.nodeName)&&a.parentNode)f.error(\"type property can't be changed\");else if(!f.support.radioValue&&b===\"radio\"&&f.nodeName(a,\"input\")){var c=a.value;a.setAttribute(\"type\",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(w&&f.nodeName(a,\"button\"))return w.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(w&&f.nodeName(a,\"button\"))return w.set(a,b,c);a.value=b}}},propFix:{tabindex:\"tabIndex\",readonly:\"readOnly\",\"for\":\"htmlFor\",\"class\":\"className\",maxlength:\"maxLength\",cellspacing:\"cellSpacing\",cellpadding:\"cellPadding\",rowspan:\"rowSpan\",colspan:\"colSpan\",usemap:\"useMap\",frameborder:\"frameBorder\",contenteditable:\"contentEditable\"},prop:function(a,c,d){var e,g,h,i=a.nodeType;if(!!a&&i!==3&&i!==8&&i!==2){h=i!==1||!f.isXMLDoc(a),h&&(c=f.propFix[c]||c,g=f.propHooks[c]);return d!==b?g&&\"set\"in g&&(e=g.set(a,d,c))!==b?e:a[c]=d:g&&\"get\"in g&&(e=g.get(a,c))!==null?e:a[c]}},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode(\"tabindex\");return c&&c.specified?parseInt(c.value,10):s.test(a.nodeName)||t.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabindex=f.propHooks.tabIndex,x={get:function(a,c){var d,e=f.prop(a,c);return e===!0||typeof e!=\"boolean\"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},v||(y={name:!0,id:!0},w=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&(y[c]?d.nodeValue!==\"\":d.specified)?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+\"\"}},f.attrHooks.tabindex.set=w.set,f.each([\"width\",\"height\"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===\"\"){a.setAttribute(b,\"auto\");return c}}})}),f.attrHooks.contenteditable={get:w.get,set:function(a,b,c){b===\"\"&&(b=\"false\"),w.set(a,b,c)}}),f.support.hrefNormalized||f.each([\"href\",\"src\",\"width\",\"height\"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=\"\"+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.enctype||(f.propFix.enctype=\"encoding\"),f.support.checkOn||f.each([\"radio\",\"checkbox\"],function(){f.valHooks[this]={get:function(a){return a.getAttribute(\"value\")===null?\"on\":a.value}}}),f.each([\"radio\",\"checkbox\"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\\.]*)?(?:\\.(.+))?$/,B=/\\bhover(\\.\\S+)?\\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\\w*)(?:#([\\w\\-]+))?(?:\\.([\\w\\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||\"\").toLowerCase(),b[3]=b[3]&&new RegExp(\"(?:^|\\\\s)\"+b[3]+\"(?:\\\\s|$)\"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c[\"class\"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,\"mouseenter$1 mouseleave$1\")};\nf.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!=\"undefined\"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(\" \");for(k=0;k<c.length;k++){l=A.exec(c[k])||[],m=l[1],n=(l[2]||\"\").split(\".\").sort(),s=f.event.special[m]||{},m=(g?s.delegateType:s.bindType)||m,s=f.event.special[m]||{},o=f.extend({type:m,origType:l[1],data:e,handler:d,guid:d.guid,selector:g,quick:G(g),namespace:n.join(\".\")},p),r=j[m];if(!r){r=j[m]=[],r.delegateCount=0;if(!s.setup||s.setup.call(a,e,n,i)===!1)a.addEventListener?a.addEventListener(m,i,!1):a.attachEvent&&a.attachEvent(\"on\"+m,i)}s.add&&(s.add.call(a,o),o.handler.guid||(o.handler.guid=d.guid)),g?r.splice(r.delegateCount++,0,o):r.push(o),f.event.global[m]=!0}a=null}},global:{},remove:function(a,b,c,d,e){var g=f.hasData(a)&&f._data(a),h,i,j,k,l,m,n,o,p,q,r,s;if(!!g&&!!(o=g.events)){b=f.trim(I(b||\"\")).split(\" \");for(h=0;h<b.length;h++){i=A.exec(b[h])||[],j=k=i[1],l=i[2];if(!j){for(j in o)f.event.remove(a,j+b[h],c,d,!0);continue}p=f.event.special[j]||{},j=(d?p.delegateType:p.bindType)||j,r=o[j]||[],m=r.length,l=l?new RegExp(\"(^|\\\\.)\"+l.split(\".\").sort().join(\"\\\\.(?:.*\\\\.)?\")+\"(\\\\.|$)\"):null;for(n=0;n<r.length;n++)s=r[n],(e||k===s.origType)&&(!c||c.guid===s.guid)&&(!l||l.test(s.namespace))&&(!d||d===s.selector||d===\"**\"&&s.selector)&&(r.splice(n--,1),s.selector&&r.delegateCount--,p.remove&&p.remove.call(a,s));r.length===0&&m!==r.length&&((!p.teardown||p.teardown.call(a,l)===!1)&&f.removeEvent(a,j,g.handle),delete o[j])}f.isEmptyObject(o)&&(q=g.handle,q&&(q.elem=null),f.removeData(a,[\"events\",\"handle\"],!0))}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){if(!e||e.nodeType!==3&&e.nodeType!==8){var h=c.type||c,i=[],j,k,l,m,n,o,p,q,r,s;if(E.test(h+f.event.triggered))return;h.indexOf(\"!\")>=0&&(h=h.slice(0,-1),k=!0),h.indexOf(\".\")>=0&&(i=h.split(\".\"),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c==\"object\"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join(\".\"),c.namespace_re=c.namespace?new RegExp(\"(^|\\\\.)\"+i.join(\"\\\\.(?:.*\\\\.)?\")+\"(\\\\.|$)\"):null,o=h.indexOf(\":\")<0?\"on\"+h:\"\";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;l<r.length&&!c.isPropagationStopped();l++)m=r[l][0],c.type=r[l][1],q=(f._data(m,\"events\")||{})[c.type]&&f._data(m,\"handle\"),q&&q.apply(m,d),q=o&&m[o],q&&f.acceptData(m)&&q.apply(m,d)===!1&&c.preventDefault();c.type=h,!g&&!c.isDefaultPrevented()&&(!p._default||p._default.apply(e.ownerDocument,d)===!1)&&(h!==\"click\"||!f.nodeName(e,\"a\"))&&f.acceptData(e)&&o&&e[h]&&(h!==\"focus\"&&h!==\"blur\"||c.target.offsetWidth!==0)&&!f.isWindow(e)&&(n=e[o],n&&(e[o]=null),f.event.triggered=h,e[h](),f.event.triggered=b,n&&(e[o]=n));return c.result}},dispatch:function(c){c=f.event.fix(c||a.event);var d=(f._data(this,\"events\")||{})[c.type]||[],e=d.delegateCount,g=[].slice.call(arguments,0),h=!c.exclusive&&!c.namespace,i=[],j,k,l,m,n,o,p,q,r,s,t;g[0]=c,c.delegateTarget=this;if(e&&!c.target.disabled&&(!c.button||c.type!==\"click\")){m=f(this),m.context=this.ownerDocument||this;for(l=c.target;l!=this;l=l.parentNode||this){o={},q=[],m[0]=l;for(j=0;j<e;j++)r=d[j],s=r.selector,o[s]===b&&(o[s]=r.quick?H(l,r.quick):m.is(s)),o[s]&&q.push(r);q.length&&i.push({elem:l,matches:q})}}d.length>e&&i.push({elem:this,matches:d.slice(e)});for(j=0;j<i.length&&!c.isPropagationStopped();j++){p=i[j],c.currentTarget=p.elem;for(k=0;k<p.matches.length&&!c.isImmediatePropagationStopped();k++){r=p.matches[k];if(h||!c.namespace&&!r.namespace||c.namespace_re&&c.namespace_re.test(r.namespace))c.data=r.data,c.handleObj=r,n=((f.event.special[r.origType]||{}).handle||r.handler).apply(p.elem,g),n!==b&&(c.result=n,n===!1&&(c.preventDefault(),c.stopPropagation()))}}return c.result},props:\"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which\".split(\" \"),fixHooks:{},keyHooks:{props:\"char charCode key keyCode\".split(\" \"),filter:function(a,b){a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode);return a}},mouseHooks:{props:\"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement\".split(\" \"),filter:function(a,d){var e,f,g,h=d.button,i=d.fromElement;a.pageX==null&&d.clientX!=null&&(e=a.target.ownerDocument||c,f=e.documentElement,g=e.body,a.pageX=d.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=d.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?d.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0);return a}},fix:function(a){if(a[f.expando])return a;var d,e,g=a,h=f.event.fixHooks[a.type]||{},i=h.props?this.props.concat(h.props):this.props;a=f.Event(g);for(d=i.length;d;)e=i[--d],a[e]=g[e];a.target||(a.target=g.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey===b&&(a.metaKey=a.ctrlKey);return h.filter?h.filter(a,g):a},special:{ready:{setup:f.bindReady},load:{noBubble:!0},focus:{delegateType:\"focusin\"},blur:{delegateType:\"focusout\"},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=f.extend(new f.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?f.event.trigger(e,null,b):f.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},f.event.handle=f.event.dispatch,f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent(\"on\"+b,c)},f.Event=function(a,b){if(!(this instanceof f.Event))return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?K:J):this.type=a,b&&f.extend(this,b),this.timeStamp=a&&a.timeStamp||f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=K;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=K;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=K,this.stopPropagation()},isDefaultPrevented:J,isPropagationStopped:J,isImmediatePropagationStopped:J},f.each({mouseenter:\"mouseover\",mouseleave:\"mouseout\"},function(a,b){f.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c=this,d=a.relatedTarget,e=a.handleObj,g=e.selector,h;if(!d||d!==c&&!f.contains(c,d))a.type=e.origType,h=e.handler.apply(this,arguments),a.type=b;return h}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(){if(f.nodeName(this,\"form\"))return!1;f.event.add(this,\"click._submit keypress._submit\",function(a){var c=a.target,d=f.nodeName(c,\"input\")||f.nodeName(c,\"button\")?c.form:b;d&&!d._submit_attached&&(f.event.add(d,\"submit._submit\",function(a){this.parentNode&&!a.isTrigger&&f.event.simulate(\"submit\",this.parentNode,a,!0)}),d._submit_attached=!0)})},teardown:function(){if(f.nodeName(this,\"form\"))return!1;f.event.remove(this,\"._submit\")}}),f.support.changeBubbles||(f.event.special.change={setup:function(){if(z.test(this.nodeName)){if(this.type===\"checkbox\"||this.type===\"radio\")f.event.add(this,\"propertychange._change\",function(a){a.originalEvent.propertyName===\"checked\"&&(this._just_changed=!0)}),f.event.add(this,\"click._change\",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1,f.event.simulate(\"change\",this,a,!0))});return!1}f.event.add(this,\"beforeactivate._change\",function(a){var b=a.target;z.test(b.nodeName)&&!b._change_attached&&(f.event.add(b,\"change._change\",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&f.event.simulate(\"change\",this.parentNode,a,!0)}),b._change_attached=!0)})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!==\"radio\"&&b.type!==\"checkbox\")return a.handleObj.handler.apply(this,arguments)},teardown:function(){f.event.remove(this,\"._change\");return z.test(this.nodeName)}}),f.support.focusinBubbles||f.each({focus:\"focusin\",blur:\"focusout\"},function(a,b){var d=0,e=function(a){f.event.simulate(b,a.target,f.event.fix(a),!0)};f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.fn.extend({on:function(a,c,d,e,g){var h,i;if(typeof a==\"object\"){typeof c!=\"string\"&&(d=c,c=b);for(i in a)this.on(i,c,d,a[i],g);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c==\"string\"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=J;else if(!e)return this;g===1&&(h=e,e=function(a){f().off(a);return h.apply(this,arguments)},e.guid=h.guid||(h.guid=f.guid++));return this.each(function(){f.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on.call(this,a,b,c,d,1)},off:function(a,c,d){if(a&&a.preventDefault&&a.handleObj){var e=a.handleObj;f(a.delegateTarget).off(e.namespace?e.type+\".\"+e.namespace:e.type,e.selector,e.handler);return this}if(typeof a==\"object\"){for(var g in a)this.off(g,c,a[g]);return this}if(c===!1||typeof c==\"function\")d=c,c=b;d===!1&&(d=J);return this.each(function(){f.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){f(this.context).on(a,this.selector,b,c);return this},die:function(a,b){f(this.context).off(a,this.selector||\"**\",b);return this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length==1?this.off(a,\"**\"):this.off(b,a,c)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f._data(this,\"lastToggle\"+a.guid)||0)%d;f._data(this,\"lastToggle\"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),f.each(\"blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu\".split(\" \"),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}if(j.nodeType===1){g||(j[d]=c,j.sizset=h);if(typeof b!=\"string\"){if(j===b){k=!0;break}}else if(m.filter(b,[j]).length>0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}j.nodeType===1&&!g&&(j[d]=c,j.sizset=h);if(j.nodeName.toLowerCase()===b){k=j;break}j=j[a]}e[h]=k}}}var a=/((?:\\((?:\\([^()]+\\)|[^()]+)+\\)|\\[(?:\\[[^\\[\\]]*\\]|['\"][^'\"]*['\"]|[^\\[\\]'\"]+)+\\]|\\\\.|[^ >+~,(\\[\\\\]+)+|[>+~])(\\s*,\\s*)?((?:.|\\r|\\n)*)/g,d=\"sizcache\"+(Math.random()+\"\").replace(\".\",\"\"),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\\\/g,k=/\\r\\n/g,l=/\\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!=\"string\")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(\"\"),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]===\"~\"||w[0]===\"+\")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q=\"\",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)===\"[object Array]\")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},m.matches=function(a,b){return m(a,null,null,b)},m.matchesSelector=function(a,b){return m(b,null,null,[a]).length>0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e<f;e++){h=o.order[e];if(g=o.leftMatch[h].exec(a)){i=g[1],g.splice(1,1);if(i.substr(i.length-1)!==\"\\\\\"){g[1]=(g[1]||\"\").replace(j,\"\"),d=o.find[h](g,b,c);if(d!=null){a=a.replace(o.match[h],\"\");break}}}}d||(d=typeof b.getElementsByTagName!=\"undefined\"?b.getElementsByTagName(\"*\"):[]);return{set:d,expr:a}},m.filter=function(a,c,d,e){var f,g,h,i,j,k,l,n,p,q=a,r=[],s=c,t=c&&c[0]&&m.isXML(c[0]);while(a&&c.length){for(h in o.filter)if((f=o.leftMatch[h].exec(a))!=null&&f[2]){k=o.filter[h],l=f[1],g=!1,f.splice(1,1);if(l.substr(l.length-1)===\"\\\\\")continue;s===r&&(r=[]);if(o.preFilter[h]){f=o.preFilter[h](f,s,d,r,e,t);if(!f)g=i=!0;else if(f===!0)continue}if(f)for(n=0;(j=s[n])!=null;n++)j&&(i=k(j,f,n,s),p=e^i,d&&i!=null?p?g=!0:s[n]=!1:p&&(r.push(j),g=!0));if(i!==b){d||(s=r),a=a.replace(o.match[h],\"\");if(!g)return[];break}}if(a===q)if(g==null)m.error(a);else break;q=a}return s},m.error=function(a){throw new Error(\"Syntax error, unrecognized expression: \"+a)};var n=m.getText=function(a){var b,c,d=a.nodeType,e=\"\";if(d){if(d===1||d===9){if(typeof a.textContent==\"string\")return a.textContent;if(typeof a.innerText==\"string\")return a.innerText.replace(k,\"\");for(a=a.firstChild;a;a=a.nextSibling)e+=n(a)}else if(d===3||d===4)return a.nodeValue}else for(b=0;c=a[b];b++)c.nodeType!==8&&(e+=n(c));return e},o=m.selectors={order:[\"ID\",\"NAME\",\"TAG\"],match:{ID:/#((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)/,CLASS:/\\.((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)/,NAME:/\\[name=['\"]*((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)['\"]*\\]/,ATTR:/\\[\\s*((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)\\s*(?:(\\S?=)\\s*(?:(['\"])(.*?)\\3|(#?(?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)*)|)|)\\s*\\]/,TAG:/^((?:[\\w\\u00c0-\\uFFFF\\*\\-]|\\\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\\(\\s*(even|odd|(?:[+\\-]?\\d+|(?:[+\\-]?\\d*)?n\\s*(?:[+\\-]\\s*\\d+)?))\\s*\\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\))?(?=[^\\-]|$)/,PSEUDO:/:((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)(?:\\((['\"]?)((?:\\([^\\)]+\\)|[^\\(\\)]*)+)\\2\\))?/},leftMatch:{},attrMap:{\"class\":\"className\",\"for\":\"htmlFor\"},attrHandle:{href:function(a){return a.getAttribute(\"href\")},type:function(a){return a.getAttribute(\"type\")}},relative:{\"+\":function(a,b){var c=typeof b==\"string\",d=c&&!l.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&m.filter(b,a,!0)},\">\":function(a,b){var c,d=typeof b==\"string\",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&m.filter(b,a,!0)}},\"\":function(a,b,c){var d,f=e++,g=x;typeof b==\"string\"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g(\"parentNode\",b,f,a,d,c)},\"~\":function(a,b,c){var d,f=e++,g=x;typeof b==\"string\"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g(\"previousSibling\",b,f,a,d,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!=\"undefined\"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!=\"undefined\"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute(\"name\")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!=\"undefined\")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=\" \"+a[1].replace(j,\"\")+\" \";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(\" \"+h.className+\" \").replace(/[\\t\\n\\r]/g,\" \").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,\"\")},TAG:function(a,b){return a[1].replace(j,\"\").toLowerCase()},CHILD:function(a){if(a[1]===\"nth\"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\\+|\\s*/g,\"\");var b=/(-?)(\\d*)(?:n([+\\-]?\\d*))?/.exec(a[2]===\"even\"&&\"2n\"||a[2]===\"odd\"&&\"2n+1\"||!/\\D/.test(a[2])&&\"0n+\"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,\"\");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||\"\").replace(j,\"\"),a[2]===\"~=\"&&(a[4]=\" \"+a[4]+\" \");return a},PSEUDO:function(b,c,d,e,f){if(b[1]===\"not\")if((a.exec(b[3])||\"\").length>1||/^\\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!==\"hidden\"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute(\"type\"),c=a.type;return a.nodeName.toLowerCase()===\"input\"&&\"text\"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()===\"input\"&&\"radio\"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()===\"input\"&&\"checkbox\"===a.type},file:function(a){return a.nodeName.toLowerCase()===\"input\"&&\"file\"===a.type},password:function(a){return a.nodeName.toLowerCase()===\"input\"&&\"password\"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b===\"input\"||b===\"button\")&&\"submit\"===a.type},image:function(a){return a.nodeName.toLowerCase()===\"input\"&&\"image\"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b===\"input\"||b===\"button\")&&\"reset\"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b===\"input\"&&\"button\"===a.type||b===\"button\"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e===\"contains\")return(a.textContent||a.innerText||n([a])||\"\").indexOf(b[3])>=0;if(e===\"not\"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}m.error(e)},CHILD:function(a,b){var c,e,f,g,h,i,j,k=b[1],l=a;switch(k){case\"only\":case\"first\":while(l=l.previousSibling)if(l.nodeType===1)return!1;if(k===\"first\")return!0;l=a;case\"last\":while(l=l.nextSibling)if(l.nodeType===1)return!1;return!0;case\"nth\":c=b[2],e=b[3];if(c===1&&e===0)return!0;f=b[0],g=a.parentNode;if(g&&(g[d]!==f||!a.nodeIndex)){i=0;for(l=g.firstChild;l;l=l.nextSibling)l.nodeType===1&&(l.nodeIndex=++i);g[d]=f}j=a.nodeIndex-e;return c===0?j===0:j%c===0&&j/c>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute(\"id\")===b},TAG:function(a,b){return b===\"*\"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(\" \"+(a.className||a.getAttribute(\"class\"))+\" \").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+\"\",f=b[2],g=b[4];return d==null?f===\"!=\":!f&&m.attr?d!=null:f===\"=\"?e===g:f===\"*=\"?e.indexOf(g)>=0:f===\"~=\"?(\" \"+e+\" \").indexOf(g)>=0:g?f===\"!=\"?e!==g:f===\"^=\"?e.indexOf(g)===0:f===\"$=\"?e.substr(e.length-g.length)===g:f===\"|=\"?e===g||e.substr(0,g.length+1)===g+\"-\":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return\"\\\\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\\[]*\\])(?![^\\(]*\\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\\r|\\n)*?)/.source+o.match[r].source.replace(/\\\\(\\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)===\"[object Array]\")Array.prototype.push.apply(d,a);else if(typeof a.length==\"number\")for(var e=a.length;c<e;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var u,v;c.documentElement.compareDocumentPosition?u=function(a,b){if(a===b){h=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(u=function(a,b){if(a===b){h=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,i=b.parentNode,j=g;if(g===i)return v(a,b);if(!g)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return v(e[k],f[k]);return k===c?v(a,f[k],-1):v(e[k],b,1)},v=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),function(){var a=c.createElement(\"div\"),d=\"script\"+(new Date).getTime(),e=c.documentElement;a.innerHTML=\"<a name='\"+d+\"'/>\",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!=\"undefined\"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!=\"undefined\"&&e.getAttributeNode(\"id\").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!=\"undefined\"&&a.getAttributeNode(\"id\");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement(\"div\");a.appendChild(c.createComment(\"\")),a.getElementsByTagName(\"*\").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]===\"*\"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML=\"<a href='#'></a>\",a.firstChild&&typeof a.firstChild.getAttribute!=\"undefined\"&&a.firstChild.getAttribute(\"href\")!==\"#\"&&(o.attrHandle.href=function(a){return a.getAttribute(\"href\",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement(\"div\"),d=\"__sizzle__\";b.innerHTML=\"<p class='TEST'></p>\";if(!b.querySelectorAll||b.querySelectorAll(\".TEST\").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\\w+$)|^\\.([\\w\\-]+$)|^#([\\w\\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b===\"body\"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!==\"object\"){var k=e,l=e.getAttribute(\"id\"),n=l||d,p=e.parentNode,q=/^\\s*[+~]/.test(b);l?n=n.replace(/'/g,\"\\\\$&\"):e.setAttribute(\"id\",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll(\"[id='\"+n+\"'] \"+b),f)}catch(r){}finally{l||k.removeAttribute(\"id\")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement(\"div\"),\"div\"),e=!1;try{b.call(c.documentElement,\"[test!='']:sizzle\")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\\=\\s*([^'\"\\]]*)\\s*\\]/g,\"='$1']\");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement(\"div\");a.innerHTML=\"<div class='test e'></div><div class='test'></div>\";if(!!a.getElementsByClassName&&a.getElementsByClassName(\"e\").length!==0){a.lastChild.className=\"e\";if(a.getElementsByClassName(\"e\").length===1)return;o.order.splice(1,0,\"CLASS\"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!=\"undefined\"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!==\"HTML\":!1};var y=function(a,b,c){var d,e=[],f=\"\",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,\"\");a=o.relative[a]?a+\"*\":a;for(var h=0,i=g.length;h<i;h++)m(a,g[h],e,c);return m.filter(f,e)};m.attr=f.attr,m.selectors.attrMap={},f.find=m,f.expr=m.selectors,f.expr[\":\"]=f.expr.filters,f.unique=m.uniqueSort,f.text=m.getText,f.isXMLDoc=m.isXML,f.contains=m.contains}();var L=/Until$/,M=/^(?:parents|prevUntil|prevAll)/,N=/,/,O=/^.[^:#\\[\\.,]*$/,P=Array.prototype.slice,Q=f.expr.match.POS,R={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!=\"string\")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack(\"\",\"find\",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(T(this,a,!1),\"not\",a)},filter:function(a){return this.pushStack(T(this,a,!0),\"filter\",a)},is:function(a){return!!a&&(typeof a==\"string\"?Q.test(a)?f(a,this.context).index(this[0])>=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d<a.length;d++)f(g).is(a[d])&&c.push({selector:a[d],elem:g,level:h});g=g.parentNode,h++}return c}var i=Q.test(a)||typeof a!=\"string\"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(i?i.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,\"closest\",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a==\"string\")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a==\"string\"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,\"parentNode\")},parentsUntil:function(a,b,c){return f.dir(a,\"parentNode\",c)},next:function(a){return f.nth(a,2,\"nextSibling\")},prev:function(a){return f.nth(a,2,\"previousSibling\")},nextAll:function(a){return f.dir(a,\"nextSibling\")},prevAll:function(a){return f.dir(a,\"previousSibling\")},nextUntil:function(a,b,c){return f.dir(a,\"nextSibling\",c)},prevUntil:function(a,b,c){return f.dir(a,\"previousSibling\",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,\"iframe\")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d==\"string\"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(\",\"))}}),f.extend({filter:function(a,b,c){c&&(a=\":not(\"+a+\")\");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V=\"abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video\",W=/ jQuery\\d+=\"(?:\\d+|null)\"/g,X=/^\\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:]+)[^>]*)\\/>/ig,Z=/<([\\w:]+)/,$=/<tbody/i,_=/<|&#?\\w+;/,ba=/<(?:script|style)/i,bb=/<(?:script|object|embed|option|style)/i,bc=new RegExp(\"<(?:\"+V+\")\",\"i\"),bd=/checked\\s*(?:[^=]|=\\s*.checked.)/i,be=/\\/(java|ecma)script/i,bf=/^\\s*<!(?:\\[CDATA\\[|\\-\\-)/,bg={option:[1,\"<select multiple='multiple'>\",\"</select>\"],legend:[1,\"<fieldset>\",\"</fieldset>\"],thead:[1,\"<table>\",\"</table>\"],tr:[2,\"<table><tbody>\",\"</tbody></table>\"],td:[3,\"<table><tbody><tr>\",\"</tr></tbody></table>\"],col:[2,\"<table><tbody></tbody><colgroup>\",\"</colgroup></table>\"],area:[1,\"<map>\",\"</map>\"],_default:[0,\"\",\"\"]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,\"div<div>\",\"</div>\"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!=\"object\"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,\"body\")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,\"before\",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,\"after\",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName(\"*\")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function()\n{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName(\"*\"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,\"\"):null;if(typeof a==\"string\"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||[\"\",\"\"])[1].toLowerCase()]){a=a.replace(Y,\"<$1></$2>\");try{for(var c=0,d=this.length;c<d;c++)this[c].nodeType===1&&(f.cleanData(this[c].getElementsByTagName(\"*\")),this[c].innerHTML=a)}catch(e){this.empty().append(a)}}else f.isFunction(a)?this.each(function(b){var c=f(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!=\"string\"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),\"replaceWith\",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j==\"string\"&&bd.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,\"tr\");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bi(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,bp)}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i,j=a[0];b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof j==\"string\"&&j.length<512&&i===c&&j.charAt(0)===\"<\"&&!bb.test(j)&&(f.support.checkClone||!bd.test(j))&&(f.support.html5Clone||!bc.test(j))&&(g=!0,h=f.fragments[j],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean(a,i,e,d)),g&&(f.fragments[j]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:\"append\",prependTo:\"prepend\",insertBefore:\"before\",insertAfter:\"after\",replaceAll:\"replaceWith\"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test(\"<\"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement==\"undefined\"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k==\"number\"&&(k+=\"\");if(!k)continue;if(typeof k==\"string\")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,\"<$1></$2>\");var l=(Z.exec(k)||[\"\",\"\"])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement(\"div\");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l===\"table\"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===\"<table>\"&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],\"tbody\")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)==\"number\")for(i=0;i<r;i++)bn(k[i]);else bn(k);k.nodeType?h.push(k):h=f.merge(h,k)}if(d){g=function(a){return!a.type||be.test(a.type)};for(j=0;h[j];j++)if(e&&f.nodeName(h[j],\"script\")&&(!h[j].type||h[j].type.toLowerCase()===\"text/javascript\"))e.push(h[j].parentNode?h[j].parentNode.removeChild(h[j]):h[j]);else{if(h[j].nodeType===1){var s=f.grep(h[j].getElementsByTagName(\"script\"),g);h.splice.apply(h,[j+1,0].concat(s))}d.appendChild(h[j])}}return h},cleanData:function(a){var b,c,d=f.cache,e=f.event.special,g=f.support.deleteExpando;for(var h=0,i;(i=a[h])!=null;h++){if(i.nodeName&&f.noData[i.nodeName.toLowerCase()])continue;c=i[f.expando];if(c){b=d[c];if(b&&b.events){for(var j in b.events)e[j]?f.event.remove(i,j):f.removeEvent(i,j,b.handle);b.handle&&(b.handle.elem=null)}g?delete i[f.expando]:i.removeAttribute&&i.removeAttribute(f.expando),delete d[c]}}}});var bq=/alpha\\([^)]*\\)/i,br=/opacity=([^)]*)/,bs=/([A-Z]|^ms)/g,bt=/^-?\\d+(?:px)?$/i,bu=/^-?\\d/,bv=/^([\\-+])=([\\-+.\\de]+)/,bw={position:\"absolute\",visibility:\"hidden\",display:\"block\"},bx=[\"Left\",\"Right\"],by=[\"Top\",\"Bottom\"],bz,bA,bB;f.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return f.access(this,a,c,!0,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)})},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bz(a,\"opacity\",\"opacity\");return c===\"\"?\"1\":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{\"float\":f.support.cssFloat?\"cssFloat\":\"styleFloat\"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&\"get\"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h===\"string\"&&(g=bv.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h=\"number\");if(d==null||h===\"number\"&&isNaN(d))return;h===\"number\"&&!f.cssNumber[i]&&(d+=\"px\");if(!k||!(\"set\"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c===\"cssFloat\"&&(c=\"float\");if(g&&\"get\"in g&&(e=g.get(a,!0,d))!==b)return e;if(bz)return bz(a,c)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]}}),f.curCSS=f.css,f.each([\"height\",\"width\"],function(a,b){f.cssHooks[b]={get:function(a,c,d){var e;if(c){if(a.offsetWidth!==0)return bC(a,b,d);f.swap(a,bw,function(){e=bC(a,b,d)});return e}},set:function(a,b){if(!bt.test(b))return b;b=parseFloat(b);if(b>=0)return b+\"px\"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||\"\")?parseFloat(RegExp.$1)/100+\"\":b?\"1\":\"\"},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?\"alpha(opacity=\"+b*100+\")\":\"\",g=d&&d.filter||c.filter||\"\";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,\"\"))===\"\"){c.removeAttribute(\"filter\");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+\" \"+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:\"inline-block\"},function(){b?c=bz(a,\"margin-right\",\"marginRight\"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,\"-$1\").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===\"\"&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b===\"fontSize\"?\"1em\":f||0,f=g.pixelLeft+\"px\",g.left=c,d&&(a.runtimeStyle.left=d));return f===\"\"?\"auto\":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,\"display\"))===\"none\"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\\[\\]$/,bF=/\\r?\\n/g,bG=/#.*$/,bH=/^(.*?):[ \\t]*([^\\r\\n]*)\\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\\-storage|.+\\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\\/\\//,bM=/\\?/,bN=/<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\\w\\+\\.\\-]+:)(?:\\/\\/([^\\/?#:]*)(?::(\\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=[\"*/\"]+[\"*\"];try{bV=e.href}catch(bY){bV=c.createElement(\"a\"),bV.href=\"\",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!=\"string\"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(\" \");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h=\"GET\";c&&(f.isFunction(c)?(d=c,c=b):typeof c==\"object\"&&(c=f.param(c,f.ajaxSettings.traditional),h=\"POST\"));var i=this;f.ajax({url:a,type:h,dataType:\"html\",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f(\"<div>\").append(c.replace(bN,\"\")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,\"\\r\\n\")}}):{name:b.name,value:c.replace(bF,\"\\r\\n\")}}).get()}}),f.each(\"ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend\".split(\" \"),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each([\"get\",\"post\"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,\"script\")},getJSON:function(a,b,c){return f.get(a,b,c,\"json\")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:\"GET\",contentType:\"application/x-www-form-urlencoded\",processData:!0,async:!0,accepts:{xml:\"application/xml, text/xml\",html:\"text/html\",text:\"text/plain\",json:\"application/json, text/javascript\",\"*\":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:\"responseXML\",text:\"responseText\"},converters:{\"* text\":a.String,\"text html\":!0,\"text json\":f.parseJSON,\"text xml\":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||\"\",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader(\"Last-Modified\"))f.lastModified[k]=y;if(z=v.getResponseHeader(\"Etag\"))f.etag[k]=z}if(a===304)w=\"notmodified\",o=!0;else try{r=cc(d,x),w=\"success\",o=!0}catch(A){w=\"parsererror\",u=A}}else{u=w;if(!w||a)w=\"error\",a<0&&(a=0)}v.status=a,v.statusText=\"\"+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger(\"ajax\"+(o?\"Success\":\"Error\"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger(\"ajaxComplete\",[v,d]),--f.active||f.event.trigger(\"ajaxStop\"))}}typeof a==\"object\"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks(\"once memory\"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||\"abort\",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+\"\").replace(bG,\"\").replace(bL,bW[1]+\"//\"),d.dataTypes=f.trim(d.dataType||\"*\").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]===\"http:\"?80:443))==(bW[3]||(bW[1]===\"http:\"?80:443)))),d.data&&d.processData&&typeof d.data!=\"string\"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger(\"ajaxStart\");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?\"&\":\"?\")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,\"$1_=\"+x);d.url=y+(y===d.url?(bM.test(d.url)?\"&\":\"?\")+\"_=\"+x:\"\")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader(\"Content-Type\",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader(\"If-Modified-Since\",f.lastModified[k]),f.etag[k]&&v.setRequestHeader(\"If-None-Match\",f.etag[k])),v.setRequestHeader(\"Accept\",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!==\"*\"?\", \"+bX+\"; q=0.01\":\"\"):d.accepts[\"*\"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,\"No Transport\");else{v.readyState=1,t&&g.trigger(\"ajaxSend\",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort(\"timeout\")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+\"=\"+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join(\"&\").replace(bD,\"+\")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\\=)\\?(&|$)|\\?\\?/i;f.ajaxSetup({jsonp:\"callback\",jsonpCallback:function(){return f.expando+\"_\"+cd++}}),f.ajaxPrefilter(\"json jsonp\",function(b,c,d){var e=b.contentType===\"application/x-www-form-urlencoded\"&&typeof b.data==\"string\";if(b.dataTypes[0]===\"jsonp\"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l=\"$1\"+h+\"$2\";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\\?/.test(j)?\"&\":\"?\")+b.jsonp+\"=\"+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters[\"script json\"]=function(){g||f.error(h+\" was not called\");return g[0]},b.dataTypes[0]=\"json\";return\"script\"}}),f.ajaxSetup({accepts:{script:\"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"},contents:{script:/javascript|ecmascript/},converters:{\"text script\":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter(\"script\",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type=\"GET\",a.global=!1)}),f.ajaxTransport(\"script\",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName(\"head\")[0]||c.documentElement;return{send:function(f,g){d=c.createElement(\"script\"),d.async=\"async\",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,\"success\")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&\"withCredentials\"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e[\"X-Requested-With\"]&&(e[\"X-Requested-With\"]=\"XMLHttpRequest\");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=\"\"}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\\-]=)?([\\d+.\\-]+)([a-z%]*)$/i,cp,cq=[[\"height\",\"marginTop\",\"marginBottom\",\"paddingTop\",\"paddingBottom\"],[\"width\",\"marginLeft\",\"marginRight\",\"paddingLeft\",\"paddingRight\"],[\"opacity\"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu(\"show\",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,\"olddisplay\")&&e===\"none\"&&(e=d.style.display=\"\"),e===\"\"&&f.css(d,\"display\")===\"none\"&&f._data(d,\"olddisplay\",cv(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===\"\"||e===\"none\")d.style.display=f._data(d,\"olddisplay\")||\"\"}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(cu(\"hide\",3),a,b,c);var d,e,g=0,h=this.length;for(;g<h;g++)d=this[g],d.style&&(e=f.css(d,\"display\"),e!==\"none\"&&!f._data(d,\"olddisplay\")&&f._data(d,\"olddisplay\",e));for(g=0;g<h;g++)this[g].style&&(this[g].style.display=\"none\");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a==\"boolean\";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(\":hidden\");f(this)[b?\"show\":\"hide\"]()}):this.animate(cu(\"toggle\",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(\":hidden\").css(\"opacity\",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){function g(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(\":hidden\"),g,h,i,j,k,l,m,n,o;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]),h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||\"swing\";if(h===\"hide\"&&d||h===\"show\"&&!d)return b.complete.call(this);c&&(g===\"height\"||g===\"width\")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,\"display\")===\"inline\"&&f.css(this,\"float\")===\"none\"&&(!f.support.inlineBlockNeedsLayout||cv(this.nodeName)===\"inline\"?this.style.display=\"inline-block\":this.style.zoom=1))}b.overflow!=null&&(this.style.overflow=\"hidden\");for(i in a)j=new f.fx(this,b,i),h=a[i],cn.test(h)?(o=f._data(this,\"toggle\"+i)||(h===\"toggle\"?d?\"show\":\"hide\":0),o?(f._data(this,\"toggle\"+i,o===\"show\"?\"hide\":\"show\"),j[o]()):j[h]()):(k=co.exec(h),l=j.cur(),k?(m=parseFloat(k[2]),n=k[3]||(f.cssNumber[i]?\"\":\"px\"),n!==\"px\"&&(f.style(this,i,(m||1)+n),l=(m||1)/j.cur()*l,f.style(this,i,l+n)),k[1]&&(m=(k[1]===\"-=\"?-1:1)*m+l),j.custom(l,m,n)):j.custom(l,h,\"\"));return!0}var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return e.queue===!1?this.each(g):this.queue(e.queue,g)},stop:function(a,c,d){typeof a!=\"string\"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||\"fx\",[]);return this.each(function(){function h(a,b,c){var e=b[c];f.removeData(a,c,!0),e.stop(d)}var b,c=!1,e=f.timers,g=f._data(this);d||f._unmark(!0,this);if(a==null)for(b in g)g[b]&&g[b].stop&&b.indexOf(\".run\")===b.length-4&&h(this,g,b);else g[b=a+\".run\"]&&g[b].stop&&h(this,g,b);for(b=e.length;b--;)e[b].elem===this&&(a==null||e[b].queue===a)&&(d?e[b](!0):e[b].saveState(),c=!0,e.splice(b,1));(!d||!c)&&f.dequeue(this,a)})}}),f.each({slideDown:cu(\"show\",1),slideUp:cu(\"hide\",1),slideToggle:cu(\"toggle\",1),fadeIn:{opacity:\"show\"},fadeOut:{opacity:\"hide\"},fadeToggle:{opacity:\"toggle\"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a==\"object\"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration==\"number\"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue=\"fx\";d.old=d.complete,d.complete=function(a){f.isFunction(d.old)&&d.old.call(this),d.queue?f.dequeue(this,d.queue):a!==!1&&f._unmark(this)};return d},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b===\"auto\"?0:b:a},custom:function(a,c,d){function h(a){return e.step(a)}var e=this,g=f.fx;this.startTime=cr||cs(),this.end=c,this.now=this.start=a,this.pos=this.state=0,this.unit=d||this.unit||(f.cssNumber[this.prop]?\"\":\"px\"),h.queue=this.options.queue,h.elem=this.elem,h.saveState=function(){e.options.hide&&f._data(e.elem,\"fxshow\"+e.prop)===b&&f._data(e.elem,\"fxshow\"+e.prop,e.start)},h()&&f.timers.push(h)&&!cp&&(cp=setInterval(g.tick,g.interval))},show:function(){var a=f._data(this.elem,\"fxshow\"+this.prop);this.options.orig[this.prop]=a||f.style(this.elem,this.prop),this.options.show=!0,a!==b?this.custom(this.cur(),a):this.custom(this.prop===\"width\"||this.prop===\"height\"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f._data(this.elem,\"fxshow\"+this.prop)||f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b,c,d,e=cr||cs(),g=!0,h=this.elem,i=this.options;if(a||e>=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each([\"\",\"X\",\"Y\"],function(a,b){h.style[\"overflow\"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,\"fxshow\"+b,!0),f.removeData(h,\"toggle\"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||f.fx.stop()},interval:13,stop:function(){clearInterval(cp),cp=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,\"opacity\",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=a.now+a.unit:a.elem[a.prop]=a.now}}}),f.each([\"width\",\"height\"],function(a,b){f.fx.step[b]=function(a){f.style(a.elem,b,Math.max(0,a.now)+a.unit)}}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var cw=/^t(?:able|d|h)$/i,cx=/^(?:body|html)$/i;\"getBoundingClientRect\"in c.documentElement?f.fn.offset=function(a){var b=this[0],c;if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);try{c=b.getBoundingClientRect()}catch(d){}var e=b.ownerDocument,g=e.documentElement;if(!c||!f.contains(g,b))return c?{top:c.top,left:c.left}:{top:0,left:0};var h=e.body,i=cy(e),j=g.clientTop||h.clientTop||0,k=g.clientLeft||h.clientLeft||0,l=i.pageYOffset||f.support.boxModel&&g.scrollTop||h.scrollTop,m=i.pageXOffset||f.support.boxModel&&g.scrollLeft||h.scrollLeft,n=c.top+l-j,o=c.left+m-k;return{top:n,left:o}}:f.fn.offset=function(a){var b=this[0];if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);var c,d=b.offsetParent,e=b,g=b.ownerDocument,h=g.documentElement,i=g.body,j=g.defaultView,k=j?j.getComputedStyle(b,null):b.currentStyle,l=b.offsetTop,m=b.offsetLeft;while((b=b.parentNode)&&b!==i&&b!==h){if(f.support.fixedPosition&&k.position===\"fixed\")break;c=j?j.getComputedStyle(b,null):b.currentStyle,l-=b.scrollTop,m-=b.scrollLeft,b===d&&(l+=b.offsetTop,m+=b.offsetLeft,f.support.doesNotAddBorder&&(!f.support.doesAddBorderForTableAndCells||!cw.test(b.nodeName))&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),e=d,d=b.offsetParent),f.support.subtractsBorderForOverflowNotVisible&&c.overflow!==\"visible\"&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),k=c}if(k.position===\"relative\"||k.position===\"static\")l+=i.offsetTop,m+=i.offsetLeft;f.support.fixedPosition&&k.position===\"fixed\"&&(l+=Math.max(h.scrollTop,i.scrollTop),m+=Math.max(h.scrollLeft,i.scrollLeft));return{top:l,left:m}},f.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,\"marginTop\"))||0,c+=parseFloat(f.css(a,\"marginLeft\"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,\"position\");d===\"static\"&&(a.style.position=\"relative\");var e=f(a),g=e.offset(),h=f.css(a,\"top\"),i=f.css(a,\"left\"),j=(d===\"absolute\"||d===\"fixed\")&&f.inArray(\"auto\",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),\"using\"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,\"marginTop\"))||0,c.left-=parseFloat(f.css(a,\"marginLeft\"))||0,d.top+=parseFloat(f.css(b[0],\"borderTopWidth\"))||0,d.left+=parseFloat(f.css(b[0],\"borderLeftWidth\"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,\"position\")===\"static\")a=a.offsetParent;return a})}}),f.each([\"Left\",\"Top\"],function(a,c){var d=\"scroll\"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?\"pageXOffset\"in g?g[a?\"pageYOffset\":\"pageXOffset\"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each([\"Height\",\"Width\"],function(a,c){var d=c.toLowerCase();f.fn[\"inner\"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,\"padding\")):this[d]():null},f.fn[\"outer\"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?\"margin\":\"border\")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement[\"client\"+c],h=e.document.body;return e.document.compatMode===\"CSS1Compat\"&&g||h&&h[\"client\"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement[\"client\"+c],e.body[\"scroll\"+c],e.documentElement[\"scroll\"+c],e.body[\"offset\"+c],e.documentElement[\"offset\"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a==\"string\"?a:a+\"px\")}}),a.jQuery=a.$=f,typeof define==\"function\"&&define.amd&&define.amd.jQuery&&define(\"jquery\",[],function(){return f})})(window);\n'''\n\ng_raphael_js = r'''\nRaphael.el.popup=function(d,k,h,g){var c=this.paper||this[0].paper,f,j,b,e,a;if(!c){return}switch(this.type){case\"text\":case\"circle\":case\"ellipse\":b=true;break;default:b=false}d=d==null?\"up\":d;k=k||5;f=this.getBBox();h=typeof h==\"number\"?h:(b?f.x+f.width/2:f.x);g=typeof g==\"number\"?g:(b?f.y+f.height/2:f.y);e=Math.max(f.width/2-k,0);a=Math.max(f.height/2-k,0);this.translate(h-f.x-(b?f.width/2:0),g-f.y-(b?f.height/2:0));f=this.getBBox();var i={up:[\"M\",h,g,\"l\",-k,-k,-e,0,\"a\",k,k,0,0,1,-k,-k,\"l\",0,-f.height,\"a\",k,k,0,0,1,k,-k,\"l\",k*2+e*2,0,\"a\",k,k,0,0,1,k,k,\"l\",0,f.height,\"a\",k,k,0,0,1,-k,k,\"l\",-e,0,\"z\"].join(\",\"),down:[\"M\",h,g,\"l\",k,k,e,0,\"a\",k,k,0,0,1,k,k,\"l\",0,f.height,\"a\",k,k,0,0,1,-k,k,\"l\",-(k*2+e*2),0,\"a\",k,k,0,0,1,-k,-k,\"l\",0,-f.height,\"a\",k,k,0,0,1,k,-k,\"l\",e,0,\"z\"].join(\",\"),left:[\"M\",h,g,\"l\",-k,k,0,a,\"a\",k,k,0,0,1,-k,k,\"l\",-f.width,0,\"a\",k,k,0,0,1,-k,-k,\"l\",0,-(k*2+a*2),\"a\",k,k,0,0,1,k,-k,\"l\",f.width,0,\"a\",k,k,0,0,1,k,k,\"l\",0,a,\"z\"].join(\",\"),right:[\"M\",h,g,\"l\",k,-k,0,-a,\"a\",k,k,0,0,1,k,-k,\"l\",f.width,0,\"a\",k,k,0,0,1,k,k,\"l\",0,k*2+a*2,\"a\",k,k,0,0,1,-k,k,\"l\",-f.width,0,\"a\",k,k,0,0,1,-k,-k,\"l\",0,-a,\"z\"].join(\",\")};j={up:{x:-!b*(f.width/2),y:-k*2-(b?f.height/2:f.height)},down:{x:-!b*(f.width/2),y:k*2+(b?f.height/2:f.height)},left:{x:-k*2-(b?f.width/2:f.width),y:-!b*(f.height/2)},right:{x:k*2+(b?f.width/2:f.width),y:-!b*(f.height/2)}}[d];this.translate(j.x,j.y);return c.path(i[d]).attr({fill:\"#000\",stroke:\"none\"}).insertBefore(this.node?this:this[0])};Raphael.el.tag=function(f,b,l,k){var i=3,e=this.paper||this[0].paper;if(!e){return}var c=e.path().attr({fill:\"#000\",stroke:\"#000\"}),j=this.getBBox(),m,h,a,g;switch(this.type){case\"text\":case\"circle\":case\"ellipse\":a=true;break;default:a=false}f=f||0;l=typeof l==\"number\"?l:(a?j.x+j.width/2:j.x);k=typeof k==\"number\"?k:(a?j.y+j.height/2:j.y);b=b==null?5:b;h=0.5522*b;if(j.height>=b*2){c.attr({path:[\"M\",l,k+b,\"a\",b,b,0,1,1,0,-b*2,b,b,0,1,1,0,b*2,\"m\",0,-b*2-i,\"a\",b+i,b+i,0,1,0,0,(b+i)*2,\"L\",l+b+i,k+j.height/2+i,\"l\",j.width+2*i,0,0,-j.height-2*i,-j.width-2*i,0,\"L\",l,k-b-i].join(\",\")})}else{m=Math.sqrt(Math.pow(b+i,2)-Math.pow(j.height/2+i,2));c.attr({path:[\"M\",l,k+b,\"c\",-h,0,-b,h-b,-b,-b,0,-h,b-h,-b,b,-b,h,0,b,b-h,b,b,0,h,h-b,b,-b,b,\"M\",l+m,k-j.height/2-i,\"a\",b+i,b+i,0,1,0,0,j.height+2*i,\"l\",b+i-m+j.width+2*i,0,0,-j.height-2*i,\"L\",l+m,k-j.height/2-i].join(\",\")})}f=360-f;c.rotate(f,l,k);if(this.attrs){this.attr(this.attrs.x?\"x\":\"cx\",l+b+i+(!a?this.type==\"text\"?j.width:0:j.width/2)).attr(\"y\",a?k:k-j.height/2);this.rotate(f,l,k);f>90&&f<270&&this.attr(this.attrs.x?\"x\":\"cx\",l-b-i-(!a?j.width:j.width/2)).rotate(180,l,k)}else{if(f>90&&f<270){this.translate(l-j.x-j.width-b-i,k-j.y-j.height/2);this.rotate(f-180,j.x+j.width+b+i,j.y+j.height/2)}else{this.translate(l-j.x+b+i,k-j.y-j.height/2);this.rotate(f,j.x-b-i,j.y+j.height/2)}}return c.insertBefore(this.node?this:this[0])};Raphael.el.drop=function(d,g,f){var e=this.getBBox(),c=this.paper||this[0].paper,a,j,b,i,h;if(!c){return}switch(this.type){case\"text\":case\"circle\":case\"ellipse\":a=true;break;default:a=false}d=d||0;g=typeof g==\"number\"?g:(a?e.x+e.width/2:e.x);f=typeof f==\"number\"?f:(a?e.y+e.height/2:e.y);j=Math.max(e.width,e.height)+Math.min(e.width,e.height);b=c.path([\"M\",g,f,\"l\",j,0,\"A\",j*0.4,j*0.4,0,1,0,g+j*0.7,f-j*0.7,\"z\"]).attr({fill:\"#000\",stroke:\"none\"}).rotate(22.5-d,g,f);d=(d+90)*Math.PI/180;i=(g+j*Math.sin(d))-(a?0:e.width/2);h=(f+j*Math.cos(d))-(a?0:e.height/2);this.attrs?this.attr(this.attrs.x?\"x\":\"cx\",i).attr(this.attrs.y?\"y\":\"cy\",h):this.translate(i-e.x,h-e.y);return b.insertBefore(this.node?this:this[0])};Raphael.el.flag=function(e,k,j){var g=3,c=this.paper||this[0].paper;if(!c){return}var b=c.path().attr({fill:\"#000\",stroke:\"#000\"}),i=this.getBBox(),f=i.height/2,a;switch(this.type){case\"text\":case\"circle\":case\"ellipse\":a=true;break;default:a=false}e=e||0;k=typeof k==\"number\"?k:(a?i.x+i.width/2:i.x);j=typeof j==\"number\"?j:(a?i.y+i.height/2:i.y);b.attr({path:[\"M\",k,j,\"l\",f+g,-f-g,i.width+2*g,0,0,i.height+2*g,-i.width-2*g,0,\"z\"].join(\",\")});e=360-e;b.rotate(e,k,j);if(this.attrs){this.attr(this.attrs.x?\"x\":\"cx\",k+f+g+(!a?this.type==\"text\"?i.width:0:i.width/2)).attr(\"y\",a?j:j-i.height/2);this.rotate(e,k,j);e>90&&e<270&&this.attr(this.attrs.x?\"x\":\"cx\",k-f-g-(!a?i.width:i.width/2)).rotate(180,k,j)}else{if(e>90&&e<270){this.translate(k-i.x-i.width-f-g,j-i.y-i.height/2);this.rotate(e-180,i.x+i.width+f+g,i.y+i.height/2)}else{this.translate(k-i.x+f+g,j-i.y-i.height/2);this.rotate(e,i.x-f-g,i.y+i.height/2)}}return b.insertBefore(this.node?this:this[0])};Raphael.el.label=function(){var c=this.getBBox(),b=this.paper||this[0].paper,a=Math.min(20,c.width+10,c.height+10)/2;if(!b){return}return b.rect(c.x-a/2,c.y-a/2,c.width+a,c.height+a,a).attr({stroke:\"none\",fill:\"#000\"}).insertBefore(this.node?this:this[0])};Raphael.el.blob=function(z,j,i){var g=this.getBBox(),B=Math.PI/180,n=this.paper||this[0].paper,r,A,q;if(!n){return}switch(this.type){case\"text\":case\"circle\":case\"ellipse\":A=true;break;default:A=false}r=n.path().attr({fill:\"#000\",stroke:\"none\"});z=(+z+1?z:45)+90;q=Math.min(g.height,g.width);j=typeof j==\"number\"?j:(A?g.x+g.width/2:g.x);i=typeof i==\"number\"?i:(A?g.y+g.height/2:g.y);var m=Math.max(g.width+q,q*25/12),t=Math.max(g.height+q,q*25/12),u=j+q*Math.sin((z-22.5)*B),b=i+q*Math.cos((z-22.5)*B),v=j+q*Math.sin((z+22.5)*B),d=i+q*Math.cos((z+22.5)*B),o=(v-u)/2,l=(d-b)/2,f=m/2,e=t/2,s=-Math.sqrt(Math.abs(f*f*e*e-f*f*l*l-e*e*o*o)/(f*f*l*l+e*e*o*o)),c=s*f*l/e+(v+u)/2,a=s*-e*o/f+(d+b)/2;r.attr({x:c,y:a,path:[\"M\",j,i,\"L\",v,d,\"A\",f,e,0,1,1,u,b,\"z\"].join(\",\")});this.translate(c-g.x-g.width/2,a-g.y-g.height/2);return r.insertBefore(this.node?this:this[0])};Raphael.fn.label=function(a,d,b){var c=this.set();b=this.text(a,d,b).attr(Raphael.g.txtattr);return c.push(b.label(),b)};Raphael.fn.popup=function(a,f,d,b,c){var e=this.set();d=this.text(a,f,d).attr(Raphael.g.txtattr);return e.push(d.popup(b,c),d)};Raphael.fn.tag=function(a,f,d,c,b){var e=this.set();d=this.text(a,f,d).attr(Raphael.g.txtattr);return e.push(d.tag(c,b),d)};Raphael.fn.flag=function(a,e,c,b){var d=this.set();c=this.text(a,e,c).attr(Raphael.g.txtattr);return d.push(c.flag(b),c)};Raphael.fn.drop=function(a,e,c,b){var d=this.set();c=this.text(a,e,c).attr(Raphael.g.txtattr);return d.push(c.drop(b),c)};Raphael.fn.blob=function(a,e,c,b){var d=this.set();c=this.text(a,e,c).attr(Raphael.g.txtattr);return d.push(c.blob(b),c)};Raphael.el.lighter=function(b){b=b||2;var a=[this.attrs.fill,this.attrs.stroke];this.fs=this.fs||[a[0],a[1]];a[0]=Raphael.rgb2hsb(Raphael.getRGB(a[0]).hex);a[1]=Raphael.rgb2hsb(Raphael.getRGB(a[1]).hex);a[0].b=Math.min(a[0].b*b,1);a[0].s=a[0].s/b;a[1].b=Math.min(a[1].b*b,1);a[1].s=a[1].s/b;this.attr({fill:\"hsb(\"+[a[0].h,a[0].s,a[0].b]+\")\",stroke:\"hsb(\"+[a[1].h,a[1].s,a[1].b]+\")\"});return this};Raphael.el.darker=function(b){b=b||2;var a=[this.attrs.fill,this.attrs.stroke];this.fs=this.fs||[a[0],a[1]];a[0]=Raphael.rgb2hsb(Raphael.getRGB(a[0]).hex);a[1]=Raphael.rgb2hsb(Raphael.getRGB(a[1]).hex);a[0].s=Math.min(a[0].s*b,1);a[0].b=a[0].b/b;a[1].s=Math.min(a[1].s*b,1);a[1].b=a[1].b/b;this.attr({fill:\"hsb(\"+[a[0].h,a[0].s,a[0].b]+\")\",stroke:\"hsb(\"+[a[1].h,a[1].s,a[1].b]+\")\"});return this};Raphael.el.resetBrightness=function(){if(this.fs){this.attr({fill:this.fs[0],stroke:this.fs[1]});delete this.fs}return this};(function(){var c=[\"lighter\",\"darker\",\"resetBrightness\"],a=[\"popup\",\"tag\",\"flag\",\"label\",\"drop\",\"blob\"];for(var b in a){(function(d){Raphael.st[d]=function(){return Raphael.el[d].apply(this,arguments)}})(a[b])}for(var b in c){(function(d){Raphael.st[d]=function(){for(var e=0;e<this.length;e++){this[e][d].apply(this[e],arguments)}return this}})(c[b])}})();Raphael.g={shim:{stroke:\"none\",fill:\"#000\",\"fill-opacity\":0},txtattr:{font:\"12px Arial, sans-serif\",fill:\"#fff\"},colors:(function(){var c=[0.6,0.2,0.05,0.1333,0.75,0],a=[];for(var b=0;b<10;b++){if(b<c.length){a.push(\"hsb(\"+c[b]+\",.75, .75)\")}else{a.push(\"hsb(\"+c[b-c.length]+\", 1, .5)\")}}return a})(),snapEnds:function(j,k,h){var e=j,l=k;if(e==l){return{from:e,to:l,power:0}}function m(d){return Math.abs(d-0.5)<0.25?~~(d)+0.5:Math.round(d)}var g=(l-e)/h,a=~~(g),c=a,b=0;if(a){while(c){b--;c=~~(g*Math.pow(10,b))/Math.pow(10,b)}b++}else{while(!a){b=b||1;a=~~(g*Math.pow(10,b))/Math.pow(10,b);b++}b&&b--}l=m(k*Math.pow(10,b))/Math.pow(10,b);if(l<k){l=m((k+0.5)*Math.pow(10,b))/Math.pow(10,b)}e=m((j-(b>0?0:0.5))*Math.pow(10,b))/Math.pow(10,b);return{from:e,to:l,power:b}},axis:function(p,o,k,D,e,G,g,J,h,a,q){a=a==null?2:a;h=h||\"t\";G=G||10;q=arguments[arguments.length-1];var C=h==\"|\"||h==\" \"?[\"M\",p+0.5,o,\"l\",0,0.001]:g==1||g==3?[\"M\",p+0.5,o,\"l\",0,-k]:[\"M\",p,o+0.5,\"l\",k,0],s=this.snapEnds(D,e,G),H=s.from,z=s.to,F=s.power,E=0,w={font:\"11px 'Fontin Sans', Fontin-Sans, sans-serif\"},v=q.set(),I;I=(z-H)/G;var n=H,m=F>0?F:0;r=k/G;if(+g==1||+g==3){var b=o,u=(g-1?1:-1)*(a+3+!!(g-1));while(b>=o-k){h!=\"-\"&&h!=\" \"&&(C=C.concat([\"M\",p-(h==\"+\"||h==\"|\"?a:!(g-1)*a*2),b+0.5,\"l\",a*2+1,0]));v.push(q.text(p+u,b,(J&&J[E++])||(Math.round(n)==n?n:+n.toFixed(m))).attr(w).attr({\"text-anchor\":g-1?\"start\":\"end\"}));n+=I;b-=r}if(Math.round(b+r-(o-k))){h!=\"-\"&&h!=\" \"&&(C=C.concat([\"M\",p-(h==\"+\"||h==\"|\"?a:!(g-1)*a*2),o-k+0.5,\"l\",a*2+1,0]));v.push(q.text(p+u,o-k,(J&&J[E])||(Math.round(n)==n?n:+n.toFixed(m))).attr(w).attr({\"text-anchor\":g-1?\"start\":\"end\"}))}}else{n=H;m=(F>0)*F;u=(g?-1:1)*(a+9+!g);var c=p,r=k/G,A=0,B=0;while(c<=p+k){h!=\"-\"&&h!=\" \"&&(C=C.concat([\"M\",c+0.5,o-(h==\"+\"?a:!!g*a*2),\"l\",0,a*2+1]));v.push(A=q.text(c,o+u,(J&&J[E++])||(Math.round(n)==n?n:+n.toFixed(m))).attr(w));var l=A.getBBox();if(B>=l.x-5){v.pop(v.length-1).remove()}else{B=l.x+l.width}n+=I;c+=r}if(Math.round(c-r-p-k)){h!=\"-\"&&h!=\" \"&&(C=C.concat([\"M\",p+k+0.5,o-(h==\"+\"?a:!!g*a*2),\"l\",0,a*2+1]));v.push(q.text(p+k,o+u,(J&&J[E])||(Math.round(n)==n?n:+n.toFixed(m))).attr(w))}}var K=q.path(C);K.text=v;K.all=q.set([K,v]);K.remove=function(){this.text.remove();this.constructor.prototype.remove.call(this)};return K},labelise:function(a,c,b){if(a){return(a+\"\").replace(/(##+(?:\\.#+)?)|(%%+(?:\\.%+)?)/g,function(d,f,e){if(f){return(+c).toFixed(f.replace(/^#+\\.?/g,\"\").length)}if(e){return(c*100/b).toFixed(e.replace(/^%+\\.?/g,\"\").length)+\"%\"}})}else{return(+c).toFixed(0)}}};\n'''\n\ng_raphael_line_js = r'''\n(function(){function a(g,n){var f=g.length/n,h=0,e=f,m=0,i=[];while(h<g.length){e--;if(e<0){m+=g[h]*(1+e);i.push(m/f);m=g[h++]*-e;e+=f}else{m+=g[h++]}}return i}function d(f,e,p,n,k,j){var h=(p-f)/2,g=(k-p)/2,q=Math.atan((p-f)/Math.abs(n-e)),o=Math.atan((k-p)/Math.abs(n-j));q=e<n?Math.PI-q:q;o=j<n?Math.PI-o:o;var i=Math.PI/2-((q+o)%(Math.PI*2))/2,s=h*Math.sin(i+q),m=h*Math.cos(i+q),r=g*Math.sin(i+o),l=g*Math.cos(i+o);return{x1:p-s,y1:n+m,x2:p+r,y2:n+l}}function b(f,P,O,e,h,A,z,J){var s=this;J=J||{};if(!f.raphael.is(A[0],\"array\")){A=[A]}if(!f.raphael.is(z[0],\"array\")){z=[z]}var q=J.gutter||10,B=Math.max(A[0].length,z[0].length),t=J.symbol||\"\",S=J.colors||s.colors,v=null,p=null,ad=f.set(),T=[];for(var ac=0,L=z.length;ac<L;ac++){B=Math.max(B,z[ac].length)}var ae=f.set();for(ac=0,L=z.length;ac<L;ac++){if(J.shade){ae.push(f.path().attr({stroke:\"none\",fill:S[ac],opacity:J.nostroke?1:0.3}))}if(z[ac].length>e-2*q){z[ac]=a(z[ac],e-2*q);B=e-2*q}if(A[ac]&&A[ac].length>e-2*q){A[ac]=a(A[ac],e-2*q)}}var W=Array.prototype.concat.apply([],A),U=Array.prototype.concat.apply([],z),u=s.snapEnds(Math.min.apply(Math,W),Math.max.apply(Math,W),A[0].length-1),E=u.from,o=u.to,N=s.snapEnds(Math.min.apply(Math,U),Math.max.apply(Math,U),z[0].length-1),C=N.from,n=N.to,Z=(e-q*2)/((o-E)||1),V=(h-q*2)/((n-C)||1);var G=f.set();if(J.axis){var m=(J.axis+\"\").split(/[,\\s]+/);+m[0]&&G.push(s.axis(P+q,O+q,e-2*q,E,o,J.axisxstep||Math.floor((e-2*q)/20),2,f));+m[1]&&G.push(s.axis(P+e-q,O+h-q,h-2*q,C,n,J.axisystep||Math.floor((h-2*q)/20),3,f));+m[2]&&G.push(s.axis(P+q,O+h-q,e-2*q,E,o,J.axisxstep||Math.floor((e-2*q)/20),0,f));+m[3]&&G.push(s.axis(P+q,O+h-q,h-2*q,C,n,J.axisystep||Math.floor((h-2*q)/20),1,f))}var M=f.set(),aa=f.set(),r;for(ac=0,L=z.length;ac<L;ac++){if(!J.nostroke){M.push(r=f.path().attr({stroke:S[ac],\"stroke-width\":J.width||2,\"stroke-linejoin\":\"round\",\"stroke-linecap\":\"round\",\"stroke-dasharray\":J.dash||\"\"}))}var g=Raphael.is(t,\"array\")?t[ac]:t,H=f.set();T=[];for(var ab=0,w=z[ac].length;ab<w;ab++){var l=P+q+((A[ac]||A[0])[ab]-E)*Z,k=O+h-q-(z[ac][ab]-C)*V;(Raphael.is(g,\"array\")?g[ab]:g)&&H.push(f[Raphael.is(g,\"array\")?g[ab]:g](l,k,(J.width||2)*3).attr({fill:S[ac],stroke:\"none\"}));if(J.smooth){if(ab&&ab!=w-1){var R=P+q+((A[ac]||A[0])[ab-1]-E)*Z,F=O+h-q-(z[ac][ab-1]-C)*V,Q=P+q+((A[ac]||A[0])[ab+1]-E)*Z,D=O+h-q-(z[ac][ab+1]-C)*V,af=d(R,F,l,k,Q,D);T=T.concat([af.x1,af.y1,l,k,af.x2,af.y2])}if(!ab){T=[\"M\",l,k,\"C\",l,k]}}else{T=T.concat([ab?\"L\":\"M\",l,k])}}if(J.smooth){T=T.concat([l,k,l,k])}aa.push(H);if(J.shade){ae[ac].attr({path:T.concat([\"L\",l,O+h-q,\"L\",P+q+((A[ac]||A[0])[0]-E)*Z,O+h-q,\"z\"]).join(\",\")})}!J.nostroke&&r.attr({path:T.join(\",\")})}function K(an){var ak=[];for(var al=0,ap=A.length;al<ap;al++){ak=ak.concat(A[al])}ak.sort();var aq=[],ah=[];for(al=0,ap=ak.length;al<ap;al++){ak[al]!=ak[al-1]&&aq.push(ak[al])&&ah.push(P+q+(ak[al]-E)*Z)}ak=aq;ap=ak.length;var ag=an||f.set();for(al=0;al<ap;al++){var Y=ah[al]-(ah[al]-(ah[al-1]||P))/2,ao=((ah[al+1]||P+e)-ah[al])/2+(ah[al]-(ah[al-1]||P))/2,x;an?(x={}):ag.push(x=f.rect(Y-1,O,Math.max(ao+1,1),h).attr({stroke:\"none\",fill:\"#000\",opacity:0}));x.values=[];x.symbols=f.set();x.y=[];x.x=ah[al];x.axis=ak[al];for(var aj=0,am=z.length;aj<am;aj++){aq=A[aj]||A[0];for(var ai=0,y=aq.length;ai<y;ai++){if(aq[ai]==ak[al]){x.values.push(z[aj][ai]);x.y.push(O+h-q-(z[aj][ai]-C)*V);x.symbols.push(ad.symbols[aj][ai])}}}an&&an.call(x)}!an&&(v=ag)}function I(al){var ah=al||f.set(),x;for(var aj=0,an=z.length;aj<an;aj++){for(var ai=0,ak=z[aj].length;ai<ak;ai++){var ag=P+q+((A[aj]||A[0])[ai]-E)*Z,am=P+q+((A[aj]||A[0])[ai?ai-1:1]-E)*Z,y=O+h-q-(z[aj][ai]-C)*V;al?(x={}):ah.push(x=f.circle(ag,y,Math.abs(am-ag)/2).attr({stroke:\"none\",fill:\"#000\",opacity:0}));x.x=ag;x.y=y;x.value=z[aj][ai];x.line=ad.lines[aj];x.shade=ad.shades[aj];x.symbol=ad.symbols[aj][ai];x.symbols=ad.symbols[aj];x.axis=(A[aj]||A[0])[ai];al&&al.call(x)}}!al&&(p=ah)}ad.push(M,ae,aa,G,v,p);ad.lines=M;ad.shades=ae;ad.symbols=aa;ad.axis=G;ad.hoverColumn=function(j,i){!v&&K();v.mouseover(j).mouseout(i);return this};ad.clickColumn=function(i){!v&&K();v.click(i);return this};ad.hrefColumn=function(Y){var ag=f.raphael.is(arguments[0],\"array\")?arguments[0]:arguments;if(!(arguments.length-1)&&typeof Y==\"object\"){for(var j in Y){for(var y=0,X=v.length;y<X;y++){if(v[y].axis==j){v[y].attr(\"href\",Y[j])}}}}!v&&K();for(y=0,X=ag.length;y<X;y++){v[y]&&v[y].attr(\"href\",ag[y])}return this};ad.hover=function(j,i){!p&&I();p.mouseover(j).mouseout(i);return this};ad.click=function(i){!p&&I();p.click(i);return this};ad.each=function(i){I(i);return this};ad.eachColumn=function(i){K(i);return this};return ad}var c=function(){};c.prototype=Raphael.g;b.prototype=new c;Raphael.fn.linechart=function(f,k,g,e,j,i,h){return new b(this,f,k,g,e,j,i,h)}})();\n'''\n\nraphael_js = r'''\n(function(a){var b=\"0.3.4\",c=\"hasOwnProperty\",d=/[\\.\\/]/,e=\"*\",f=function(){},g=function(a,b){return a-b},h,i,j={n:{}},k=function(a,b){var c=j,d=i,e=Array.prototype.slice.call(arguments,2),f=k.listeners(a),l=0,m=!1,n,o=[],p={},q=[],r=h,s=[];h=a,i=0;for(var t=0,u=f.length;t<u;t++)\"zIndex\"in f[t]&&(o.push(f[t].zIndex),f[t].zIndex<0&&(p[f[t].zIndex]=f[t]));o.sort(g);while(o[l]<0){n=p[o[l++]],q.push(n.apply(b,e));if(i){i=d;return q}}for(t=0;t<u;t++){n=f[t];if(\"zIndex\"in n)if(n.zIndex==o[l]){q.push(n.apply(b,e));if(i)break;do{l++,n=p[o[l]],n&&q.push(n.apply(b,e));if(i)break}while(n)}else p[n.zIndex]=n;else{q.push(n.apply(b,e));if(i)break}}i=d,h=r;return q.length?q:null};k.listeners=function(a){var b=a.split(d),c=j,f,g,h,i,k,l,m,n,o=[c],p=[];for(i=0,k=b.length;i<k;i++){n=[];for(l=0,m=o.length;l<m;l++){c=o[l].n,g=[c[b[i]],c[e]],h=2;while(h--)f=g[h],f&&(n.push(f),p=p.concat(f.f||[]))}o=n}return p},k.on=function(a,b){var c=a.split(d),e=j;for(var g=0,h=c.length;g<h;g++)e=e.n,!e[c[g]]&&(e[c[g]]={n:{}}),e=e[c[g]];e.f=e.f||[];for(g=0,h=e.f.length;g<h;g++)if(e.f[g]==b)return f;e.f.push(b);return function(a){+a==+a&&(b.zIndex=+a)}},k.stop=function(){i=1},k.nt=function(a){if(a)return(new RegExp(\"(?:\\\\.|\\\\/|^)\"+a+\"(?:\\\\.|\\\\/|$)\")).test(h);return h},k.off=k.unbind=function(a,b){var f=a.split(d),g,h,i,k,l,m,n,o=[j];for(k=0,l=f.length;k<l;k++)for(m=0;m<o.length;m+=i.length-2){i=[m,1],g=o[m].n;if(f[k]!=e)g[f[k]]&&i.push(g[f[k]]);else for(h in g)g[c](h)&&i.push(g[h]);o.splice.apply(o,i)}for(k=0,l=o.length;k<l;k++){g=o[k];while(g.n){if(b){if(g.f){for(m=0,n=g.f.length;m<n;m++)if(g.f[m]==b){g.f.splice(m,1);break}!g.f.length&&delete g.f}for(h in g.n)if(g.n[c](h)&&g.n[h].f){var p=g.n[h].f;for(m=0,n=p.length;m<n;m++)if(p[m]==b){p.splice(m,1);break}!p.length&&delete g.n[h].f}}else{delete g.f;for(h in g.n)g.n[c](h)&&g.n[h].f&&delete g.n[h].f}g=g.n}}},k.once=function(a,b){var c=function(){var d=b.apply(this,arguments);k.unbind(a,c);return d};return k.on(a,c)},k.version=b,k.toString=function(){return\"You are running Eve \"+b},typeof module!=\"undefined\"&&module.exports?module.exports=k:typeof define!=\"undefined\"?define(\"eve\",[],function(){return k}):a.eve=k})(this),function(){function cF(a){for(var b=0;b<cy.length;b++)cy[b].el.paper==a&&cy.splice(b--,1)}function cE(b,d,e,f,h,i){e=Q(e);var j,k,l,m=[],o,p,q,t=b.ms,u={},v={},w={};if(f)for(y=0,z=cy.length;y<z;y++){var x=cy[y];if(x.el.id==d.id&&x.anim==b){x.percent!=e?(cy.splice(y,1),l=1):k=x,d.attr(x.totalOrigin);break}}else f=+v;for(var y=0,z=b.percents.length;y<z;y++){if(b.percents[y]==e||b.percents[y]>f*b.top){e=b.percents[y],p=b.percents[y-1]||0,t=t/b.top*(e-p),o=b.percents[y+1],j=b.anim[e];break}f&&d.attr(b.anim[b.percents[y]])}if(!!j){if(!k){for(var A in j)if(j[g](A))if(U[g](A)||d.paper.customAttributes[g](A)){u[A]=d.attr(A),u[A]==null&&(u[A]=T[A]),v[A]=j[A];switch(U[A]){case C:w[A]=(v[A]-u[A])/t;break;case\"colour\":u[A]=a.getRGB(u[A]);var B=a.getRGB(v[A]);w[A]={r:(B.r-u[A].r)/t,g:(B.g-u[A].g)/t,b:(B.b-u[A].b)/t};break;case\"path\":var D=bR(u[A],v[A]),E=D[1];u[A]=D[0],w[A]=[];for(y=0,z=u[A].length;y<z;y++){w[A][y]=[0];for(var F=1,G=u[A][y].length;F<G;F++)w[A][y][F]=(E[y][F]-u[A][y][F])/t}break;case\"transform\":var H=d._,I=ca(H[A],v[A]);if(I){u[A]=I.from,v[A]=I.to,w[A]=[],w[A].real=!0;for(y=0,z=u[A].length;y<z;y++){w[A][y]=[u[A][y][0]];for(F=1,G=u[A][y].length;F<G;F++)w[A][y][F]=(v[A][y][F]-u[A][y][F])/t}}else{var J=d.matrix||new cb,K={_:{transform:H.transform},getBBox:function(){return d.getBBox(1)}};u[A]=[J.a,J.b,J.c,J.d,J.e,J.f],b$(K,v[A]),v[A]=K._.transform,w[A]=[(K.matrix.a-J.a)/t,(K.matrix.b-J.b)/t,(K.matrix.c-J.c)/t,(K.matrix.d-J.d)/t,(K.matrix.e-J.e)/t,(K.matrix.f-J.f)/t]}break;case\"csv\":var L=r(j[A])[s](c),M=r(u[A])[s](c);if(A==\"clip-rect\"){u[A]=M,w[A]=[],y=M.length;while(y--)w[A][y]=(L[y]-u[A][y])/t}v[A]=L;break;default:L=[][n](j[A]),M=[][n](u[A]),w[A]=[],y=d.paper.customAttributes[A].length;while(y--)w[A][y]=((L[y]||0)-(M[y]||0))/t}}var O=j.easing,P=a.easing_formulas[O];if(!P){P=r(O).match(N);if(P&&P.length==5){var R=P;P=function(a){return cC(a,+R[1],+R[2],+R[3],+R[4],t)}}else P=bf}q=j.start||b.start||+(new Date),x={anim:b,percent:e,timestamp:q,start:q+(b.del||0),status:0,initstatus:f||0,stop:!1,ms:t,easing:P,from:u,diff:w,to:v,el:d,callback:j.callback,prev:p,next:o,repeat:i||b.times,origin:d.attr(),totalOrigin:h},cy.push(x);if(f&&!k&&!l){x.stop=!0,x.start=new Date-t*f;if(cy.length==1)return cA()}l&&(x.start=new Date-x.ms*f),cy.length==1&&cz(cA)}else k.initstatus=f,k.start=new Date-k.ms*f;eve(\"raphael.anim.start.\"+d.id,d,b)}}function cD(a,b){var c=[],d={};this.ms=b,this.times=1;if(a){for(var e in a)a[g](e)&&(d[Q(e)]=a[e],c.push(Q(e)));c.sort(bd)}this.anim=d,this.top=c[c.length-1],this.percents=c}function cC(a,b,c,d,e,f){function o(a,b){var c,d,e,f,j,k;for(e=a,k=0;k<8;k++){f=m(e)-a;if(z(f)<b)return e;j=(3*i*e+2*h)*e+g;if(z(j)<1e-6)break;e=e-f/j}c=0,d=1,e=a;if(e<c)return c;if(e>d)return d;while(c<d){f=m(e);if(z(f-a)<b)return e;a>f?c=e:d=e,e=(d-c)/2+c}return e}function n(a,b){var c=o(a,b);return((l*c+k)*c+j)*c}function m(a){return((i*a+h)*a+g)*a}var g=3*b,h=3*(d-b)-g,i=1-g-h,j=3*c,k=3*(e-c)-j,l=1-j-k;return n(a,1/(200*f))}function cq(){return this.x+q+this.y+q+this.width+\" × \"+this.height}function cp(){return this.x+q+this.y}function cb(a,b,c,d,e,f){a!=null?(this.a=+a,this.b=+b,this.c=+c,this.d=+d,this.e=+e,this.f=+f):(this.a=1,this.b=0,this.c=0,this.d=1,this.e=0,this.f=0)}function bH(b,c,d){b=a._path2curve(b),c=a._path2curve(c);var e,f,g,h,i,j,k,l,m,n,o=d?0:[];for(var p=0,q=b.length;p<q;p++){var r=b[p];if(r[0]==\"M\")e=i=r[1],f=j=r[2];else{r[0]==\"C\"?(m=[e,f].concat(r.slice(1)),e=m[6],f=m[7]):(m=[e,f,e,f,i,j,i,j],e=i,f=j);for(var s=0,t=c.length;s<t;s++){var u=c[s];if(u[0]==\"M\")g=k=u[1],h=l=u[2];else{u[0]==\"C\"?(n=[g,h].concat(u.slice(1)),g=n[6],h=n[7]):(n=[g,h,g,h,k,l,k,l],g=k,h=l);var v=bG(m,n,d);if(d)o+=v;else{for(var w=0,x=v.length;w<x;w++)v[w].segment1=p,v[w].segment2=s,v[w].bez1=m,v[w].bez2=n;o=o.concat(v)}}}}}return o}function bG(b,c,d){var e=a.bezierBBox(b),f=a.bezierBBox(c);if(!a.isBBoxIntersect(e,f))return d?0:[];var g=bB.apply(0,b),h=bB.apply(0,c),i=~~(g/5),j=~~(h/5),k=[],l=[],m={},n=d?0:[];for(var o=0;o<i+1;o++){var p=a.findDotsAtSegment.apply(a,b.concat(o/i));k.push({x:p.x,y:p.y,t:o/i})}for(o=0;o<j+1;o++)p=a.findDotsAtSegment.apply(a,c.concat(o/j)),l.push({x:p.x,y:p.y,t:o/j});for(o=0;o<i;o++)for(var q=0;q<j;q++){var r=k[o],s=k[o+1],t=l[q],u=l[q+1],v=z(s.x-r.x)<.001?\"y\":\"x\",w=z(u.x-t.x)<.001?\"y\":\"x\",x=bD(r.x,r.y,s.x,s.y,t.x,t.y,u.x,u.y);if(x){if(m[x.x.toFixed(4)]==x.y.toFixed(4))continue;m[x.x.toFixed(4)]=x.y.toFixed(4);var y=r.t+z((x[v]-r[v])/(s[v]-r[v]))*(s.t-r.t),A=t.t+z((x[w]-t[w])/(u[w]-t[w]))*(u.t-t.t);y>=0&&y<=1&&A>=0&&A<=1&&(d?n++:n.push({x:x.x,y:x.y,t1:y,t2:A}))}}return n}function bF(a,b){return bG(a,b,1)}function bE(a,b){return bG(a,b)}function bD(a,b,c,d,e,f,g,h){if(!(x(a,c)<y(e,g)||y(a,c)>x(e,g)||x(b,d)<y(f,h)||y(b,d)>x(f,h))){var i=(a*d-b*c)*(e-g)-(a-c)*(e*h-f*g),j=(a*d-b*c)*(f-h)-(b-d)*(e*h-f*g),k=(a-c)*(f-h)-(b-d)*(e-g);if(!k)return;var l=i/k,m=j/k,n=+l.toFixed(2),o=+m.toFixed(2);if(n<+y(a,c).toFixed(2)||n>+x(a,c).toFixed(2)||n<+y(e,g).toFixed(2)||n>+x(e,g).toFixed(2)||o<+y(b,d).toFixed(2)||o>+x(b,d).toFixed(2)||o<+y(f,h).toFixed(2)||o>+x(f,h).toFixed(2))return;return{x:l,y:m}}}function bC(a,b,c,d,e,f,g,h,i){if(!(i<0||bB(a,b,c,d,e,f,g,h)<i)){var j=1,k=j/2,l=j-k,m,n=.01;m=bB(a,b,c,d,e,f,g,h,l);while(z(m-i)>n)k/=2,l+=(m<i?1:-1)*k,m=bB(a,b,c,d,e,f,g,h,l);return l}}function bB(a,b,c,d,e,f,g,h,i){i==null&&(i=1),i=i>1?1:i<0?0:i;var j=i/2,k=12,l=[-0.1252,.1252,-0.3678,.3678,-0.5873,.5873,-0.7699,.7699,-0.9041,.9041,-0.9816,.9816],m=[.2491,.2491,.2335,.2335,.2032,.2032,.1601,.1601,.1069,.1069,.0472,.0472],n=0;for(var o=0;o<k;o++){var p=j*l[o]+j,q=bA(p,a,c,e,g),r=bA(p,b,d,f,h),s=q*q+r*r;n+=m[o]*w.sqrt(s)}return j*n}function bA(a,b,c,d,e){var f=-3*b+9*c-9*d+3*e,g=a*f+6*b-12*c+6*d;return a*g-3*b+3*c}function by(a,b){var c=[];for(var d=0,e=a.length;e-2*!b>d;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4==d?f[3]={x:+a[0],y:+a[1]}:e-2==d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4==d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([\"C\",(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}function bx(){return this.hex}function bv(a,b,c){function d(){var e=Array.prototype.slice.call(arguments,0),f=e.join(\"␀\"),h=d.cache=d.cache||{},i=d.count=d.count||[];if(h[g](f)){bu(i,f);return c?c(h[f]):h[f]}i.length>=1e3&&delete h[i.shift()],i.push(f),h[f]=a[m](b,e);return c?c(h[f]):h[f]}return d}function bu(a,b){for(var c=0,d=a.length;c<d;c++)if(a[c]===b)return a.push(a.splice(c,1)[0])}function bm(a){if(Object(a)!==a)return a;var b=new a.constructor;for(var c in a)a[g](c)&&(b[c]=bm(a[c]));return b}function a(c){if(a.is(c,\"function\"))return b?c():eve.on(\"raphael.DOMload\",c);if(a.is(c,E))return a._engine.create[m](a,c.splice(0,3+a.is(c[0],C))).add(c);var d=Array.prototype.slice.call(arguments,0);if(a.is(d[d.length-1],\"function\")){var e=d.pop();return b?e.call(a._engine.create[m](a,d)):eve.on(\"raphael.DOMload\",function(){e.call(a._engine.create[m](a,d))})}return a._engine.create[m](a,arguments)}a.version=\"2.1.0\",a.eve=eve;var b,c=/[, ]+/,d={circle:1,rect:1,path:1,ellipse:1,text:1,image:1},e=/\\{(\\d+)\\}/g,f=\"prototype\",g=\"hasOwnProperty\",h={doc:document,win:window},i={was:Object.prototype[g].call(h.win,\"Raphael\"),is:h.win.Raphael},j=function(){this.ca=this.customAttributes={}},k,l=\"appendChild\",m=\"apply\",n=\"concat\",o=\"createTouch\"in h.doc,p=\"\",q=\" \",r=String,s=\"split\",t=\"click dblclick mousedown mousemove mouseout mouseover mouseup touchstart touchmove touchend touchcancel\"[s](q),u={mousedown:\"touchstart\",mousemove:\"touchmove\",mouseup:\"touchend\"},v=r.prototype.toLowerCase,w=Math,x=w.max,y=w.min,z=w.abs,A=w.pow,B=w.PI,C=\"number\",D=\"string\",E=\"array\",F=\"toString\",G=\"fill\",H=Object.prototype.toString,I={},J=\"push\",K=a._ISURL=/^url\\(['\"]?([^\\)]+?)['\"]?\\)$/i,L=/^\\s*((#[a-f\\d]{6})|(#[a-f\\d]{3})|rgba?\\(\\s*([\\d\\.]+%?\\s*,\\s*[\\d\\.]+%?\\s*,\\s*[\\d\\.]+%?(?:\\s*,\\s*[\\d\\.]+%?)?)\\s*\\)|hsba?\\(\\s*([\\d\\.]+(?:deg|\\xb0|%)?\\s*,\\s*[\\d\\.]+%?\\s*,\\s*[\\d\\.]+(?:%?\\s*,\\s*[\\d\\.]+)?)%?\\s*\\)|hsla?\\(\\s*([\\d\\.]+(?:deg|\\xb0|%)?\\s*,\\s*[\\d\\.]+%?\\s*,\\s*[\\d\\.]+(?:%?\\s*,\\s*[\\d\\.]+)?)%?\\s*\\))\\s*$/i,M={NaN:1,Infinity:1,\"-Infinity\":1},N=/^(?:cubic-)?bezier\\(([^,]+),([^,]+),([^,]+),([^\\)]+)\\)/,O=w.round,P=\"setAttribute\",Q=parseFloat,R=parseInt,S=r.prototype.toUpperCase,T=a._availableAttrs={\"arrow-end\":\"none\",\"arrow-start\":\"none\",blur:0,\"clip-rect\":\"0 0 1e9 1e9\",cursor:\"default\",cx:0,cy:0,fill:\"#fff\",\"fill-opacity\":1,font:'10px \"Arial\"',\"font-family\":'\"Arial\"',\"font-size\":\"10\",\"font-style\":\"normal\",\"font-weight\":400,gradient:0,height:0,href:\"http://raphaeljs.com/\",\"letter-spacing\":0,opacity:1,path:\"M0,0\",r:0,rx:0,ry:0,src:\"\",stroke:\"#000\",\"stroke-dasharray\":\"\",\"stroke-linecap\":\"butt\",\"stroke-linejoin\":\"butt\",\"stroke-miterlimit\":0,\"stroke-opacity\":1,\"stroke-width\":1,target:\"_blank\",\"text-anchor\":\"middle\",title:\"Raphael\",transform:\"\",width:0,x:0,y:0},U=a._availableAnimAttrs={blur:C,\"clip-rect\":\"csv\",cx:C,cy:C,fill:\"colour\",\"fill-opacity\":C,\"font-size\":C,height:C,opacity:C,path:\"path\",r:C,rx:C,ry:C,stroke:\"colour\",\"stroke-opacity\":C,\"stroke-width\":C,transform:\"transform\",width:C,x:C,y:C},V=/[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029]/g,W=/[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029]*,[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029]*/,X={hs:1,rg:1},Y=/,?([achlmqrstvxz]),?/gi,Z=/([achlmrqstvz])[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029,]*((-?\\d*\\.?\\d*(?:e[\\-+]?\\d+)?[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029]*,?[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029]*)+)/ig,$=/([rstm])[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029,]*((-?\\d*\\.?\\d*(?:e[\\-+]?\\d+)?[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029]*,?[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029]*)+)/ig,_=/(-?\\d*\\.?\\d*(?:e[\\-+]?\\d+)?)[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029]*,?[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029]*/ig,ba=a._radial_gradient=/^r(?:\\(([^,]+?)[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029]*,[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029]*([^\\)]+?)\\))?/,bb={},bc=function(a,b){return a.key-b.key},bd=function(a,b){return Q(a)-Q(b)},be=function(){},bf=function(a){return a},bg=a._rectPath=function(a,b,c,d,e){if(e)return[[\"M\",a+e,b],[\"l\",c-e*2,0],[\"a\",e,e,0,0,1,e,e],[\"l\",0,d-e*2],[\"a\",e,e,0,0,1,-e,e],[\"l\",e*2-c,0],[\"a\",e,e,0,0,1,-e,-e],[\"l\",0,e*2-d],[\"a\",e,e,0,0,1,e,-e],[\"z\"]];return[[\"M\",a,b],[\"l\",c,0],[\"l\",0,d],[\"l\",-c,0],[\"z\"]]},bh=function(a,b,c,d){d==null&&(d=c);return[[\"M\",a,b],[\"m\",0,-d],[\"a\",c,d,0,1,1,0,2*d],[\"a\",c,d,0,1,1,0,-2*d],[\"z\"]]},bi=a._getPath={path:function(a){return a.attr(\"path\")},circle:function(a){var b=a.attrs;return bh(b.cx,b.cy,b.r)},ellipse:function(a){var b=a.attrs;return bh(b.cx,b.cy,b.rx,b.ry)},rect:function(a){var b=a.attrs;return bg(b.x,b.y,b.width,b.height,b.r)},image:function(a){var b=a.attrs;return bg(b.x,b.y,b.width,b.height)},text:function(a){var b=a._getBBox();return bg(b.x,b.y,b.width,b.height)}},bj=a.mapPath=function(a,b){if(!b)return a;var c,d,e,f,g,h,i;a=bR(a);for(e=0,g=a.length;e<g;e++){i=a[e];for(f=1,h=i.length;f<h;f+=2)c=b.x(i[f],i[f+1]),d=b.y(i[f],i[f+1]),i[f]=c,i[f+1]=d}return a};a._g=h,a.type=h.win.SVGAngle||h.doc.implementation.hasFeature(\"http://www.w3.org/TR/SVG11/feature#BasicStructure\",\"1.1\")?\"SVG\":\"VML\";if(a.type==\"VML\"){var bk=h.doc.createElement(\"div\"),bl;bk.innerHTML='<v:shape adj=\"1\"/>',bl=bk.firstChild,bl.style.behavior=\"url(#default#VML)\";if(!bl||typeof bl.adj!=\"object\")return a.type=p;bk=null}a.svg=!(a.vml=a.type==\"VML\"),a._Paper=j,a.fn=k=j.prototype=a.prototype,a._id=0,a._oid=0,a.is=function(a,b){b=v.call(b);if(b==\"finite\")return!M[g](+a);if(b==\"array\")return a instanceof Array;return b==\"null\"&&a===null||b==typeof a&&a!==null||b==\"object\"&&a===Object(a)||b==\"array\"&&Array.isArray&&Array.isArray(a)||H.call(a).slice(8,-1).toLowerCase()==b},a.angle=function(b,c,d,e,f,g){if(f==null){var h=b-d,i=c-e;if(!h&&!i)return 0;return(180+w.atan2(-i,-h)*180/B+360)%360}return a.angle(b,c,f,g)-a.angle(d,e,f,g)},a.rad=function(a){return a%360*B/180},a.deg=function(a){return a*180/B%360},a.snapTo=function(b,c,d){d=a.is(d,\"finite\")?d:10;if(a.is(b,E)){var e=b.length;while(e--)if(z(b[e]-c)<=d)return b[e]}else{b=+b;var f=c%b;if(f<d)return c-f;if(f>b-d)return c-f+b}return c};var bn=a.createUUID=function(a,b){return function(){return\"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(a,b).toUpperCase()}}(/[xy]/g,function(a){var b=w.random()*16|0,c=a==\"x\"?b:b&3|8;return c.toString(16)});a.setWindow=function(b){eve(\"raphael.setWindow\",a,h.win,b),h.win=b,h.doc=h.win.document,a._engine.initWin&&a._engine.initWin(h.win)};var bo=function(b){if(a.vml){var c=/^\\s+|\\s+$/g,d;try{var e=new ActiveXObject(\"htmlfile\");e.write(\"<body>\"),e.close(),d=e.body}catch(f){d=createPopup().document.body}var g=d.createTextRange();bo=bv(function(a){try{d.style.color=r(a).replace(c,p);var b=g.queryCommandValue(\"ForeColor\");b=(b&255)<<16|b&65280|(b&16711680)>>>16;return\"#\"+(\"000000\"+b.toString(16)).slice(-6)}catch(e){return\"none\"}})}else{var i=h.doc.createElement(\"i\");i.title=\"Raphaël Colour Picker\",i.style.display=\"none\",h.doc.body.appendChild(i),bo=bv(function(a){i.style.color=a;return h.doc.defaultView.getComputedStyle(i,p).getPropertyValue(\"color\")})}return bo(b)},bp=function(){return\"hsb(\"+[this.h,this.s,this.b]+\")\"},bq=function(){return\"hsl(\"+[this.h,this.s,this.l]+\")\"},br=function(){return this.hex},bs=function(b,c,d){c==null&&a.is(b,\"object\")&&\"r\"in b&&\"g\"in b&&\"b\"in b&&(d=b.b,c=b.g,b=b.r);if(c==null&&a.is(b,D)){var e=a.getRGB(b);b=e.r,c=e.g,d=e.b}if(b>1||c>1||d>1)b/=255,c/=255,d/=255;return[b,c,d]},bt=function(b,c,d,e){b*=255,c*=255,d*=255;var f={r:b,g:c,b:d,hex:a.rgb(b,c,d),toString:br};a.is(e,\"finite\")&&(f.opacity=e);return f};a.color=function(b){var c;a.is(b,\"object\")&&\"h\"in b&&\"s\"in b&&\"b\"in b?(c=a.hsb2rgb(b),b.r=c.r,b.g=c.g,b.b=c.b,b.hex=c.hex):a.is(b,\"object\")&&\"h\"in b&&\"s\"in b&&\"l\"in b?(c=a.hsl2rgb(b),b.r=c.r,b.g=c.g,b.b=c.b,b.hex=c.hex):(a.is(b,\"string\")&&(b=a.getRGB(b)),a.is(b,\"object\")&&\"r\"in b&&\"g\"in b&&\"b\"in b?(c=a.rgb2hsl(b),b.h=c.h,b.s=c.s,b.l=c.l,c=a.rgb2hsb(b),b.v=c.b):(b={hex:\"none\"},b.r=b.g=b.b=b.h=b.s=b.v=b.l=-1)),b.toString=br;return b},a.hsb2rgb=function(a,b,c,d){this.is(a,\"object\")&&\"h\"in a&&\"s\"in a&&\"b\"in a&&(c=a.b,b=a.s,a=a.h,d=a.o),a*=360;var e,f,g,h,i;a=a%360/60,i=c*b,h=i*(1-z(a%2-1)),e=f=g=c-i,a=~~a,e+=[i,h,0,0,h,i][a],f+=[h,i,i,h,0,0][a],g+=[0,0,h,i,i,h][a];return bt(e,f,g,d)},a.hsl2rgb=function(a,b,c,d){this.is(a,\"object\")&&\"h\"in a&&\"s\"in a&&\"l\"in a&&(c=a.l,b=a.s,a=a.h);if(a>1||b>1||c>1)a/=360,b/=100,c/=100;a*=360;var e,f,g,h,i;a=a%360/60,i=2*b*(c<.5?c:1-c),h=i*(1-z(a%2-1)),e=f=g=c-i/2,a=~~a,e+=[i,h,0,0,h,i][a],f+=[h,i,i,h,0,0][a],g+=[0,0,h,i,i,h][a];return bt(e,f,g,d)},a.rgb2hsb=function(a,b,c){c=bs(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g;f=x(a,b,c),g=f-y(a,b,c),d=g==0?null:f==a?(b-c)/g:f==b?(c-a)/g+2:(a-b)/g+4,d=(d+360)%6*60/360,e=g==0?0:g/f;return{h:d,s:e,b:f,toString:bp}},a.rgb2hsl=function(a,b,c){c=bs(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g,h,i;g=x(a,b,c),h=y(a,b,c),i=g-h,d=i==0?null:g==a?(b-c)/i:g==b?(c-a)/i+2:(a-b)/i+4,d=(d+360)%6*60/360,f=(g+h)/2,e=i==0?0:f<.5?i/(2*f):i/(2-2*f);return{h:d,s:e,l:f,toString:bq}},a._path2string=function(){return this.join(\",\").replace(Y,\"$1\")};var bw=a._preload=function(a,b){var c=h.doc.createElement(\"img\");c.style.cssText=\"position:absolute;left:-9999em;top:-9999em\",c.onload=function(){b.call(this),this.onload=null,h.doc.body.removeChild(this)},c.onerror=function(){h.doc.body.removeChild(this)},h.doc.body.appendChild(c),c.src=a};a.getRGB=bv(function(b){if(!b||!!((b=r(b)).indexOf(\"-\")+1))return{r:-1,g:-1,b:-1,hex:\"none\",error:1,toString:bx};if(b==\"none\")return{r:-1,g:-1,b:-1,hex:\"none\",toString:bx};!X[g](b.toLowerCase().substring(0,2))&&b.charAt()!=\"#\"&&(b=bo(b));var c,d,e,f,h,i,j,k=b.match(L);if(k){k[2]&&(f=R(k[2].substring(5),16),e=R(k[2].substring(3,5),16),d=R(k[2].substring(1,3),16)),k[3]&&(f=R((i=k[3].charAt(3))+i,16),e=R((i=k[3].charAt(2))+i,16),d=R((i=k[3].charAt(1))+i,16)),k[4]&&(j=k[4][s](W),d=Q(j[0]),j[0].slice(-1)==\"%\"&&(d*=2.55),e=Q(j[1]),j[1].slice(-1)==\"%\"&&(e*=2.55),f=Q(j[2]),j[2].slice(-1)==\"%\"&&(f*=2.55),k[1].toLowerCase().slice(0,4)==\"rgba\"&&(h=Q(j[3])),j[3]&&j[3].slice(-1)==\"%\"&&(h/=100));if(k[5]){j=k[5][s](W),d=Q(j[0]),j[0].slice(-1)==\"%\"&&(d*=2.55),e=Q(j[1]),j[1].slice(-1)==\"%\"&&(e*=2.55),f=Q(j[2]),j[2].slice(-1)==\"%\"&&(f*=2.55),(j[0].slice(-3)==\"deg\"||j[0].slice(-1)==\"°\")&&(d/=360),k[1].toLowerCase().slice(0,4)==\"hsba\"&&(h=Q(j[3])),j[3]&&j[3].slice(-1)==\"%\"&&(h/=100);return a.hsb2rgb(d,e,f,h)}if(k[6]){j=k[6][s](W),d=Q(j[0]),j[0].slice(-1)==\"%\"&&(d*=2.55),e=Q(j[1]),j[1].slice(-1)==\"%\"&&(e*=2.55),f=Q(j[2]),j[2].slice(-1)==\"%\"&&(f*=2.55),(j[0].slice(-3)==\"deg\"||j[0].slice(-1)==\"°\")&&(d/=360),k[1].toLowerCase().slice(0,4)==\"hsla\"&&(h=Q(j[3])),j[3]&&j[3].slice(-1)==\"%\"&&(h/=100);return a.hsl2rgb(d,e,f,h)}k={r:d,g:e,b:f,toString:bx},k.hex=\"#\"+(16777216|f|e<<8|d<<16).toString(16).slice(1),a.is(h,\"finite\")&&(k.opacity=h);return k}return{r:-1,g:-1,b:-1,hex:\"none\",error:1,toString:bx}},a),a.hsb=bv(function(b,c,d){return a.hsb2rgb(b,c,d).hex}),a.hsl=bv(function(b,c,d){return a.hsl2rgb(b,c,d).hex}),a.rgb=bv(function(a,b,c){return\"#\"+(16777216|c|b<<8|a<<16).toString(16).slice(1)}),a.getColor=function(a){var b=this.getColor.start=this.getColor.start||{h:0,s:1,b:a||.75},c=this.hsb2rgb(b.h,b.s,b.b);b.h+=.075,b.h>1&&(b.h=0,b.s-=.2,b.s<=0&&(this.getColor.start={h:0,s:1,b:b.b}));return c.hex},a.getColor.reset=function(){delete this.start},a.parsePathString=function(b){if(!b)return null;var c=bz(b);if(c.arr)return bJ(c.arr);var d={a:7,c:6,h:1,l:2,m:2,r:4,q:4,s:4,t:2,v:1,z:0},e=[];a.is(b,E)&&a.is(b[0],E)&&(e=bJ(b)),e.length||r(b).replace(Z,function(a,b,c){var f=[],g=b.toLowerCase();c.replace(_,function(a,b){b&&f.push(+b)}),g==\"m\"&&f.length>2&&(e.push([b][n](f.splice(0,2))),g=\"l\",b=b==\"m\"?\"l\":\"L\");if(g==\"r\")e.push([b][n](f));else while(f.length>=d[g]){e.push([b][n](f.splice(0,d[g])));if(!d[g])break}}),e.toString=a._path2string,c.arr=bJ(e);return e},a.parseTransformString=bv(function(b){if(!b)return null;var c={r:3,s:4,t:2,m:6},d=[];a.is(b,E)&&a.is(b[0],E)&&(d=bJ(b)),d.length||r(b).replace($,function(a,b,c){var e=[],f=v.call(b);c.replace(_,function(a,b){b&&e.push(+b)}),d.push([b][n](e))}),d.toString=a._path2string;return d});var bz=function(a){var b=bz.ps=bz.ps||{};b[a]?b[a].sleep=100:b[a]={sleep:100},setTimeout(function(){for(var c in b)b[g](c)&&c!=a&&(b[c].sleep--,!b[c].sleep&&delete b[c])});return b[a]};a.findDotsAtSegment=function(a,b,c,d,e,f,g,h,i){var j=1-i,k=A(j,3),l=A(j,2),m=i*i,n=m*i,o=k*a+l*3*i*c+j*3*i*i*e+n*g,p=k*b+l*3*i*d+j*3*i*i*f+n*h,q=a+2*i*(c-a)+m*(e-2*c+a),r=b+2*i*(d-b)+m*(f-2*d+b),s=c+2*i*(e-c)+m*(g-2*e+c),t=d+2*i*(f-d)+m*(h-2*f+d),u=j*a+i*c,v=j*b+i*d,x=j*e+i*g,y=j*f+i*h,z=90-w.atan2(q-s,r-t)*180/B;(q>s||r<t)&&(z+=180);return{x:o,y:p,m:{x:q,y:r},n:{x:s,y:t},start:{x:u,y:v},end:{x:x,y:y},alpha:z}},a.bezierBBox=function(b,c,d,e,f,g,h,i){a.is(b,\"array\")||(b=[b,c,d,e,f,g,h,i]);var j=bQ.apply(null,b);return{x:j.min.x,y:j.min.y,x2:j.max.x,y2:j.max.y,width:j.max.x-j.min.x,height:j.max.y-j.min.y}},a.isPointInsideBBox=function(a,b,c){return b>=a.x&&b<=a.x2&&c>=a.y&&c<=a.y2},a.isBBoxIntersect=function(b,c){var d=a.isPointInsideBBox;return d(c,b.x,b.y)||d(c,b.x2,b.y)||d(c,b.x,b.y2)||d(c,b.x2,b.y2)||d(b,c.x,c.y)||d(b,c.x2,c.y)||d(b,c.x,c.y2)||d(b,c.x2,c.y2)||(b.x<c.x2&&b.x>c.x||c.x<b.x2&&c.x>b.x)&&(b.y<c.y2&&b.y>c.y||c.y<b.y2&&c.y>b.y)},a.pathIntersection=function(a,b){return bH(a,b)},a.pathIntersectionNumber=function(a,b){return bH(a,b,1)},a.isPointInsidePath=function(b,c,d){var e=a.pathBBox(b);return a.isPointInsideBBox(e,c,d)&&bH(b,[[\"M\",c,d],[\"H\",e.x2+10]],1)%2==1},a._removedFactory=function(a){return function(){eve(\"raphael.log\",null,\"Raphaël: you are calling to method “\"+a+\"” of removed object\",a)}};var bI=a.pathBBox=function(a){var b=bz(a);if(b.bbox)return b.bbox;if(!a)return{x:0,y:0,width:0,height:0,x2:0,y2:0};a=bR(a);var c=0,d=0,e=[],f=[],g;for(var h=0,i=a.length;h<i;h++){g=a[h];if(g[0]==\"M\")c=g[1],d=g[2],e.push(c),f.push(d);else{var j=bQ(c,d,g[1],g[2],g[3],g[4],g[5],g[6]);e=e[n](j.min.x,j.max.x),f=f[n](j.min.y,j.max.y),c=g[5],d=g[6]}}var k=y[m](0,e),l=y[m](0,f),o=x[m](0,e),p=x[m](0,f),q={x:k,y:l,x2:o,y2:p,width:o-k,height:p-l};b.bbox=bm(q);return q},bJ=function(b){var c=bm(b);c.toString=a._path2string;return c},bK=a._pathToRelative=function(b){var c=bz(b);if(c.rel)return bJ(c.rel);if(!a.is(b,E)||!a.is(b&&b[0],E))b=a.parsePathString(b);var d=[],e=0,f=0,g=0,h=0,i=0;b[0][0]==\"M\"&&(e=b[0][1],f=b[0][2],g=e,h=f,i++,d.push([\"M\",e,f]));for(var j=i,k=b.length;j<k;j++){var l=d[j]=[],m=b[j];if(m[0]!=v.call(m[0])){l[0]=v.call(m[0]);switch(l[0]){case\"a\":l[1]=m[1],l[2]=m[2],l[3]=m[3],l[4]=m[4],l[5]=m[5],l[6]=+(m[6]-e).toFixed(3),l[7]=+(m[7]-f).toFixed(3);break;case\"v\":l[1]=+(m[1]-f).toFixed(3);break;case\"m\":g=m[1],h=m[2];default:for(var n=1,o=m.length;n<o;n++)l[n]=+(m[n]-(n%2?e:f)).toFixed(3)}}else{l=d[j]=[],m[0]==\"m\"&&(g=m[1]+e,h=m[2]+f);for(var p=0,q=m.length;p<q;p++)d[j][p]=m[p]}var r=d[j].length;switch(d[j][0]){case\"z\":e=g,f=h;break;case\"h\":e+=+d[j][r-1];break;case\"v\":f+=+d[j][r-1];break;default:e+=+d[j][r-2],f+=+d[j][r-1]}}d.toString=a._path2string,c.rel=bJ(d);return d},bL=a._pathToAbsolute=function(b){var c=bz(b);if(c.abs)return bJ(c.abs);if(!a.is(b,E)||!a.is(b&&b[0],E))b=a.parsePathString(b);if(!b||!b.length)return[[\"M\",0,0]];var d=[],e=0,f=0,g=0,h=0,i=0;b[0][0]==\"M\"&&(e=+b[0][1],f=+b[0][2],g=e,h=f,i++,d[0]=[\"M\",e,f]);var j=b.length==3&&b[0][0]==\"M\"&&b[1][0].toUpperCase()==\"R\"&&b[2][0].toUpperCase()==\"Z\";for(var k,l,m=i,o=b.length;m<o;m++){d.push(k=[]),l=b[m];if(l[0]!=S.call(l[0])){k[0]=S.call(l[0]);switch(k[0]){case\"A\":k[1]=l[1],k[2]=l[2],k[3]=l[3],k[4]=l[4],k[5]=l[5],k[6]=+(l[6]+e),k[7]=+(l[7]+f);break;case\"V\":k[1]=+l[1]+f;break;case\"H\":k[1]=+l[1]+e;break;case\"R\":var p=[e,f][n](l.slice(1));for(var q=2,r=p.length;q<r;q++)p[q]=+p[q]+e,p[++q]=+p[q]+f;d.pop(),d=d[n](by(p,j));break;case\"M\":g=+l[1]+e,h=+l[2]+f;default:for(q=1,r=l.length;q<r;q++)k[q]=+l[q]+(q%2?e:f)}}else if(l[0]==\"R\")p=[e,f][n](l.slice(1)),d.pop(),d=d[n](by(p,j)),k=[\"R\"][n](l.slice(-2));else for(var s=0,t=l.length;s<t;s++)k[s]=l[s];switch(k[0]){case\"Z\":e=g,f=h;break;case\"H\":e=k[1];break;case\"V\":f=k[1];break;case\"M\":g=k[k.length-2],h=k[k.length-1];default:e=k[k.length-2],f=k[k.length-1]}}d.toString=a._path2string,c.abs=bJ(d);return d},bM=function(a,b,c,d){return[a,b,c,d,c,d]},bN=function(a,b,c,d,e,f){var g=1/3,h=2/3;return[g*a+h*c,g*b+h*d,g*e+h*c,g*f+h*d,e,f]},bO=function(a,b,c,d,e,f,g,h,i,j){var k=B*120/180,l=B/180*(+e||0),m=[],o,p=bv(function(a,b,c){var d=a*w.cos(c)-b*w.sin(c),e=a*w.sin(c)+b*w.cos(c);return{x:d,y:e}});if(!j){o=p(a,b,-l),a=o.x,b=o.y,o=p(h,i,-l),h=o.x,i=o.y;var q=w.cos(B/180*e),r=w.sin(B/180*e),t=(a-h)/2,u=(b-i)/2,v=t*t/(c*c)+u*u/(d*d);v>1&&(v=w.sqrt(v),c=v*c,d=v*d);var x=c*c,y=d*d,A=(f==g?-1:1)*w.sqrt(z((x*y-x*u*u-y*t*t)/(x*u*u+y*t*t))),C=A*c*u/d+(a+h)/2,D=A*-d*t/c+(b+i)/2,E=w.asin(((b-D)/d).toFixed(9)),F=w.asin(((i-D)/d).toFixed(9));E=a<C?B-E:E,F=h<C?B-F:F,E<0&&(E=B*2+E),F<0&&(F=B*2+F),g&&E>F&&(E=E-B*2),!g&&F>E&&(F=F-B*2)}else E=j[0],F=j[1],C=j[2],D=j[3];var G=F-E;if(z(G)>k){var H=F,I=h,J=i;F=E+k*(g&&F>E?1:-1),h=C+c*w.cos(F),i=D+d*w.sin(F),m=bO(h,i,c,d,e,0,g,I,J,[F,H,C,D])}G=F-E;var K=w.cos(E),L=w.sin(E),M=w.cos(F),N=w.sin(F),O=w.tan(G/4),P=4/3*c*O,Q=4/3*d*O,R=[a,b],S=[a+P*L,b-Q*K],T=[h+P*N,i-Q*M],U=[h,i];S[0]=2*R[0]-S[0],S[1]=2*R[1]-S[1];if(j)return[S,T,U][n](m);m=[S,T,U][n](m).join()[s](\",\");var V=[];for(var W=0,X=m.length;W<X;W++)V[W]=W%2?p(m[W-1],m[W],l).y:p(m[W],m[W+1],l).x;return V},bP=function(a,b,c,d,e,f,g,h,i){var j=1-i;return{x:A(j,3)*a+A(j,2)*3*i*c+j*3*i*i*e+A(i,3)*g,y:A(j,3)*b+A(j,2)*3*i*d+j*3*i*i*f+A(i,3)*h}},bQ=bv(function(a,b,c,d,e,f,g,h){var i=e-2*c+a-(g-2*e+c),j=2*(c-a)-2*(e-c),k=a-c,l=(-j+w.sqrt(j*j-4*i*k))/2/i,n=(-j-w.sqrt(j*j-4*i*k))/2/i,o=[b,h],p=[a,g],q;z(l)>\"1e12\"&&(l=.5),z(n)>\"1e12\"&&(n=.5),l>0&&l<1&&(q=bP(a,b,c,d,e,f,g,h,l),p.push(q.x),o.push(q.y)),n>0&&n<1&&(q=bP(a,b,c,d,e,f,g,h,n),p.push(q.x),o.push(q.y)),i=f-2*d+b-(h-2*f+d),j=2*(d-b)-2*(f-d),k=b-d,l=(-j+w.sqrt(j*j-4*i*k))/2/i,n=(-j-w.sqrt(j*j-4*i*k))/2/i,z(l)>\"1e12\"&&(l=.5),z(n)>\"1e12\"&&(n=.5),l>0&&l<1&&(q=bP(a,b,c,d,e,f,g,h,l),p.push(q.x),o.push(q.y)),n>0&&n<1&&(q=bP(a,b,c,d,e,f,g,h,n),p.push(q.x),o.push(q.y));return{min:{x:y[m](0,p),y:y[m](0,o)},max:{x:x[m](0,p),y:x[m](0,o)}}}),bR=a._path2curve=bv(function(a,b){var c=!b&&bz(a);if(!b&&c.curve)return bJ(c.curve);var d=bL(a),e=b&&bL(b),f={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},g={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},h=function(a,b){var c,d;if(!a)return[\"C\",b.x,b.y,b.x,b.y,b.x,b.y];!(a[0]in{T:1,Q:1})&&(b.qx=b.qy=null);switch(a[0]){case\"M\":b.X=a[1],b.Y=a[2];break;case\"A\":a=[\"C\"][n](bO[m](0,[b.x,b.y][n](a.slice(1))));break;case\"S\":c=b.x+(b.x-(b.bx||b.x)),d=b.y+(b.y-(b.by||b.y)),a=[\"C\",c,d][n](a.slice(1));break;case\"T\":b.qx=b.x+(b.x-(b.qx||b.x)),b.qy=b.y+(b.y-(b.qy||b.y)),a=[\"C\"][n](bN(b.x,b.y,b.qx,b.qy,a[1],a[2]));break;case\"Q\":b.qx=a[1],b.qy=a[2],a=[\"C\"][n](bN(b.x,b.y,a[1],a[2],a[3],a[4]));break;case\"L\":a=[\"C\"][n](bM(b.x,b.y,a[1],a[2]));break;case\"H\":a=[\"C\"][n](bM(b.x,b.y,a[1],b.y));break;case\"V\":a=[\"C\"][n](bM(b.x,b.y,b.x,a[1]));break;case\"Z\":a=[\"C\"][n](bM(b.x,b.y,b.X,b.Y))}return a},i=function(a,b){if(a[b].length>7){a[b].shift();var c=a[b];while(c.length)a.splice(b++,0,[\"C\"][n](c.splice(0,6)));a.splice(b,1),l=x(d.length,e&&e.length||0)}},j=function(a,b,c,f,g){a&&b&&a[g][0]==\"M\"&&b[g][0]!=\"M\"&&(b.splice(g,0,[\"M\",f.x,f.y]),c.bx=0,c.by=0,c.x=a[g][1],c.y=a[g][2],l=x(d.length,e&&e.length||0))};for(var k=0,l=x(d.length,e&&e.length||0);k<l;k++){d[k]=h(d[k],f),i(d,k),e&&(e[k]=h(e[k],g)),e&&i(e,k),j(d,e,f,g,k),j(e,d,g,f,k);var o=d[k],p=e&&e[k],q=o.length,r=e&&p.length;f.x=o[q-2],f.y=o[q-1],f.bx=Q(o[q-4])||f.x,f.by=Q(o[q-3])||f.y,g.bx=e&&(Q(p[r-4])||g.x),g.by=e&&(Q(p[r-3])||g.y),g.x=e&&p[r-2],g.y=e&&p[r-1]}e||(c.curve=bJ(d));return e?[d,e]:d},null,bJ),bS=a._parseDots=bv(function(b){var c=[];for(var d=0,e=b.length;d<e;d++){var f={},g=b[d].match(/^([^:]*):?([\\d\\.]*)/);f.color=a.getRGB(g[1]);if(f.color.error)return null;f.color=f.color.hex,g[2]&&(f.offset=g[2]+\"%\"),c.push(f)}for(d=1,e=c.length-1;d<e;d++)if(!c[d].offset){var h=Q(c[d-1].offset||0),i=0;for(var j=d+1;j<e;j++)if(c[j].offset){i=c[j].offset;break}i||(i=100,j=e),i=Q(i);var k=(i-h)/(j-d+1);for(;d<j;d++)h+=k,c[d].offset=h+\"%\"}return c}),bT=a._tear=function(a,b){a==b.top&&(b.top=a.prev),a==b.bottom&&(b.bottom=a.next),a.next&&(a.next.prev=a.prev),a.prev&&(a.prev.next=a.next)},bU=a._tofront=function(a,b){b.top!==a&&(bT(a,b),a.next=null,a.prev=b.top,b.top.next=a,b.top=a)},bV=a._toback=function(a,b){b.bottom!==a&&(bT(a,b),a.next=b.bottom,a.prev=null,b.bottom.prev=a,b.bottom=a)},bW=a._insertafter=function(a,b,c){bT(a,c),b==c.top&&(c.top=a),b.next&&(b.next.prev=a),a.next=b.next,a.prev=b,b.next=a},bX=a._insertbefore=function(a,b,c){bT(a,c),b==c.bottom&&(c.bottom=a),b.prev&&(b.prev.next=a),a.prev=b.prev,b.prev=a,a.next=b},bY=a.toMatrix=function(a,b){var c=bI(a),d={_:{transform:p},getBBox:function(){return c}};b$(d,b);return d.matrix},bZ=a.transformPath=function(a,b){return bj(a,bY(a,b))},b$=a._extractTransform=function(b,c){if(c==null)return b._.transform;c=r(c).replace(/\\.{3}|\\u2026/g,b._.transform||p);var d=a.parseTransformString(c),e=0,f=0,g=0,h=1,i=1,j=b._,k=new cb;j.transform=d||[];if(d)for(var l=0,m=d.length;l<m;l++){var n=d[l],o=n.length,q=r(n[0]).toLowerCase(),s=n[0]!=q,t=s?k.invert():0,u,v,w,x,y;q==\"t\"&&o==3?s?(u=t.x(0,0),v=t.y(0,0),w=t.x(n[1],n[2]),x=t.y(n[1],n[2]),k.translate(w-u,x-v)):k.translate(n[1],n[2]):q==\"r\"?o==2?(y=y||b.getBBox(1),k.rotate(n[1],y.x+y.width/2,y.y+y.height/2),e+=n[1]):o==4&&(s?(w=t.x(n[2],n[3]),x=t.y(n[2],n[3]),k.rotate(n[1],w,x)):k.rotate(n[1],n[2],n[3]),e+=n[1]):q==\"s\"?o==2||o==3?(y=y||b.getBBox(1),k.scale(n[1],n[o-1],y.x+y.width/2,y.y+y.height/2),h*=n[1],i*=n[o-1]):o==5&&(s?(w=t.x(n[3],n[4]),x=t.y(n[3],n[4]),k.scale(n[1],n[2],w,x)):k.scale(n[1],n[2],n[3],n[4]),h*=n[1],i*=n[2]):q==\"m\"&&o==7&&k.add(n[1],n[2],n[3],n[4],n[5],n[6]),j.dirtyT=1,b.matrix=k}b.matrix=k,j.sx=h,j.sy=i,j.deg=e,j.dx=f=k.e,j.dy=g=k.f,h==1&&i==1&&!e&&j.bbox?(j.bbox.x+=+f,j.bbox.y+=+g):j.dirtyT=1},b_=function(a){var b=a[0];switch(b.toLowerCase()){case\"t\":return[b,0,0];case\"m\":return[b,1,0,0,1,0,0];case\"r\":return a.length==4?[b,0,a[2],a[3]]:[b,0];case\"s\":return a.length==5?[b,1,1,a[3],a[4]]:a.length==3?[b,1,1]:[b,1]}},ca=a._equaliseTransform=function(b,c){c=r(c).replace(/\\.{3}|\\u2026/g,b),b=a.parseTransformString(b)||[],c=a.parseTransformString(c)||[];var d=x(b.length,c.length),e=[],f=[],g=0,h,i,j,k;for(;g<d;g++){j=b[g]||b_(c[g]),k=c[g]||b_(j);if(j[0]!=k[0]||j[0].toLowerCase()==\"r\"&&(j[2]!=k[2]||j[3]!=k[3])||j[0].toLowerCase()==\"s\"&&(j[3]!=k[3]||j[4]!=k[4]))return;e[g]=[],f[g]=[];for(h=0,i=x(j.length,k.length);h<i;h++)h in j&&(e[g][h]=j[h]),h in k&&(f[g][h]=k[h])}return{from:e,to:f}};a._getContainer=function(b,c,d,e){var f;f=e==null&&!a.is(b,\"object\")?h.doc.getElementById(b):b;if(f!=null){if(f.tagName)return c==null?{container:f,width:f.style.pixelWidth||f.offsetWidth,height:f.style.pixelHeight||f.offsetHeight}:{container:f,width:c,height:d};return{container:1,x:b,y:c,width:d,height:e}}},a.pathToRelative=bK,a._engine={},a.path2curve=bR,a.matrix=function(a,b,c,d,e,f){return new cb(a,b,c,d,e,f)},function(b){function d(a){var b=w.sqrt(c(a));a[0]&&(a[0]/=b),a[1]&&(a[1]/=b)}function c(a){return a[0]*a[0]+a[1]*a[1]}b.add=function(a,b,c,d,e,f){var g=[[],[],[]],h=[[this.a,this.c,this.e],[this.b,this.d,this.f],[0,0,1]],i=[[a,c,e],[b,d,f],[0,0,1]],j,k,l,m;a&&a instanceof cb&&(i=[[a.a,a.c,a.e],[a.b,a.d,a.f],[0,0,1]]);for(j=0;j<3;j++)for(k=0;k<3;k++){m=0;for(l=0;l<3;l++)m+=h[j][l]*i[l][k];g[j][k]=m}this.a=g[0][0],this.b=g[1][0],this.c=g[0][1],this.d=g[1][1],this.e=g[0][2],this.f=g[1][2]},b.invert=function(){var a=this,b=a.a*a.d-a.b*a.c;return new cb(a.d/b,-a.b/b,-a.c/b,a.a/b,(a.c*a.f-a.d*a.e)/b,(a.b*a.e-a.a*a.f)/b)},b.clone=function(){return new cb(this.a,this.b,this.c,this.d,this.e,this.f)},b.translate=function(a,b){this.add(1,0,0,1,a,b)},b.scale=function(a,b,c,d){b==null&&(b=a),(c||d)&&this.add(1,0,0,1,c,d),this.add(a,0,0,b,0,0),(c||d)&&this.add(1,0,0,1,-c,-d)},b.rotate=function(b,c,d){b=a.rad(b),c=c||0,d=d||0;var e=+w.cos(b).toFixed(9),f=+w.sin(b).toFixed(9);this.add(e,f,-f,e,c,d),this.add(1,0,0,1,-c,-d)},b.x=function(a,b){return a*this.a+b*this.c+this.e},b.y=function(a,b){return a*this.b+b*this.d+this.f},b.get=function(a){return+this[r.fromCharCode(97+a)].toFixed(4)},b.toString=function(){return a.svg?\"matrix(\"+[this.get(0),this.get(1),this.get(2),this.get(3),this.get(4),this.get(5)].join()+\")\":[this.get(0),this.get(2),this.get(1),this.get(3),0,0].join()},b.toFilter=function(){return\"progid:DXImageTransform.Microsoft.Matrix(M11=\"+this.get(0)+\", M12=\"+this.get(2)+\", M21=\"+this.get(1)+\", M22=\"+this.get(3)+\", Dx=\"+this.get(4)+\", Dy=\"+this.get(5)+\", sizingmethod='auto expand')\"},b.offset=function(){return[this.e.toFixed(4),this.f.toFixed(4)]},b.split=function(){var b={};b.dx=this.e,b.dy=this.f;var e=[[this.a,this.c],[this.b,this.d]];b.scalex=w.sqrt(c(e[0])),d(e[0]),b.shear=e[0][0]*e[1][0]+e[0][1]*e[1][1],e[1]=[e[1][0]-e[0][0]*b.shear,e[1][1]-e[0][1]*b.shear],b.scaley=w.sqrt(c(e[1])),d(e[1]),b.shear/=b.scaley;var f=-e[0][1],g=e[1][1];g<0?(b.rotate=a.deg(w.acos(g)),f<0&&(b.rotate=360-b.rotate)):b.rotate=a.deg(w.asin(f)),b.isSimple=!+b.shear.toFixed(9)&&(b.scalex.toFixed(9)==b.scaley.toFixed(9)||!b.rotate),b.isSuperSimple=!+b.shear.toFixed(9)&&b.scalex.toFixed(9)==b.scaley.toFixed(9)&&!b.rotate,b.noRotation=!+b.shear.toFixed(9)&&!b.rotate;return b},b.toTransformString=function(a){var b=a||this[s]();if(b.isSimple){b.scalex=+b.scalex.toFixed(4),b.scaley=+b.scaley.toFixed(4),b.rotate=+b.rotate.toFixed(4);return(b.dx||b.dy?\"t\"+[b.dx,b.dy]:p)+(b.scalex!=1||b.scaley!=1?\"s\"+[b.scalex,b.scaley,0,0]:p)+(b.rotate?\"r\"+[b.rotate,0,0]:p)}return\"m\"+[this.get(0),this.get(1),this.get(2),this.get(3),this.get(4),this.get(5)]}}(cb.prototype);var cc=navigator.userAgent.match(/Version\\/(.*?)\\s/)||navigator.userAgent.match(/Chrome\\/(\\d+)/);navigator.vendor==\"Apple Computer, Inc.\"&&(cc&&cc[1]<4||navigator.platform.slice(0,2)==\"iP\")||navigator.vendor==\"Google Inc.\"&&cc&&cc[1]<8?k.safari=function(){var a=this.rect(-99,-99,this.width+99,this.height+99).attr({stroke:\"none\"});setTimeout(function(){a.remove()})}:k.safari=be;var cd=function(){this.returnValue=!1},ce=function(){return this.originalEvent.preventDefault()},cf=function(){this.cancelBubble=!0},cg=function(){return this.originalEvent.stopPropagation()},ch=function(){if(h.doc.addEventListener)return function(a,b,c,d){var e=o&&u[b]?u[b]:b,f=function(e){var f=h.doc.documentElement.scrollTop||h.doc.body.scrollTop,i=h.doc.documentElement.scrollLeft||h.doc.body.scrollLeft,j=e.clientX+i,k=e.clientY+f;if(o&&u[g](b))for(var l=0,m=e.targetTouches&&e.targetTouches.length;l<m;l++)if(e.targetTouches[l].target==a){var n=e;e=e.targetTouches[l],e.originalEvent=n,e.preventDefault=ce,e.stopPropagation=cg;break}return c.call(d,e,j,k)};a.addEventListener(e,f,!1);return function(){a.removeEventListener(e,f,!1);return!0}};if(h.doc.attachEvent)return function(a,b,c,d){var e=function(a){a=a||h.win.event;var b=h.doc.documentElement.scrollTop||h.doc.body.scrollTop,e=h.doc.documentElement.scrollLeft||h.doc.body.scrollLeft,f=a.clientX+e,g=a.clientY+b;a.preventDefault=a.preventDefault||cd,a.stopPropagation=a.stopPropagation||cf;return c.call(d,a,f,g)};a.attachEvent(\"on\"+b,e);var f=function(){a.detachEvent(\"on\"+b,e);return!0};return f}}(),ci=[],cj=function(a){var b=a.clientX,c=a.clientY,d=h.doc.documentElement.scrollTop||h.doc.body.scrollTop,e=h.doc.documentElement.scrollLeft||h.doc.body.scrollLeft,f,g=ci.length;while(g--){f=ci[g];if(o){var i=a.touches.length,j;while(i--){j=a.touches[i];if(j.identifier==f.el._drag.id){b=j.clientX,c=j.clientY,(a.originalEvent?a.originalEvent:a).preventDefault();break}}}else a.preventDefault();var k=f.el.node,l,m=k.nextSibling,n=k.parentNode,p=k.style.display;h.win.opera&&n.removeChild(k),k.style.display=\"none\",l=f.el.paper.getElementByPoint(b,c),k.style.display=p,h.win.opera&&(m?n.insertBefore(k,m):n.appendChild(k)),l&&eve(\"raphael.drag.over.\"+f.el.id,f.el,l),b+=e,c+=d,eve(\"raphael.drag.move.\"+f.el.id,f.move_scope||f.el,b-f.el._drag.x,c-f.el._drag.y,b,c,a)}},ck=function(b){a.unmousemove(cj).unmouseup(ck);var c=ci.length,d;while(c--)d=ci[c],d.el._drag={},eve(\"raphael.drag.end.\"+d.el.id,d.end_scope||d.start_scope||d.move_scope||d.el,b);ci=[]},cl=a.el={};for(var cm=t.length;cm--;)(function(b){a[b]=cl[b]=function(c,d){a.is(c,\"function\")&&(this.events=this.events||[],this.events.push({name:b,f:c,unbind:ch(this.shape||this.node||h.doc,b,c,d||this)}));return this},a[\"un\"+b]=cl[\"un\"+b]=function(a){var c=this.events||[],d=c.length;while(d--)if(c[d].name==b&&c[d].f==a){c[d].unbind(),c.splice(d,1),!c.length&&delete this.events;return this}return this}})(t[cm]);cl.data=function(b,c){var d=bb[this.id]=bb[this.id]||{};if(arguments.length==1){if(a.is(b,\"object\")){for(var e in b)b[g](e)&&this.data(e,b[e]);return this}eve(\"raphael.data.get.\"+this.id,this,d[b],b);return d[b]}d[b]=c,eve(\"raphael.data.set.\"+this.id,this,c,b);return this},cl.removeData=function(a){a==null?bb[this.id]={}:bb[this.id]&&delete bb[this.id][a];return this},cl.hover=function(a,b,c,d){return this.mouseover(a,c).mouseout(b,d||c)},cl.unhover=function(a,b){return this.unmouseover(a).unmouseout(b)};var cn=[];cl.drag=function(b,c,d,e,f,g){function i(i){(i.originalEvent||i).preventDefault();var j=h.doc.documentElement.scrollTop||h.doc.body.scrollTop,k=h.doc.documentElement.scrollLeft||h.doc.body.scrollLeft;this._drag.x=i.clientX+k,this._drag.y=i.clientY+j,this._drag.id=i.identifier,!ci.length&&a.mousemove(cj).mouseup(ck),ci.push({el:this,move_scope:e,start_scope:f,end_scope:g}),c&&eve.on(\"raphael.drag.start.\"+this.id,c),b&&eve.on(\"raphael.drag.move.\"+this.id,b),d&&eve.on(\"raphael.drag.end.\"+this.id,d),eve(\"raphael.drag.start.\"+this.id,f||e||this,i.clientX+k,i.clientY+j,i)}this._drag={},cn.push({el:this,start:i}),this.mousedown(i);return this},cl.onDragOver=function(a){a?eve.on(\"raphael.drag.over.\"+this.id,a):eve.unbind(\"raphael.drag.over.\"+this.id)},cl.undrag=function(){var b=cn.length;while(b--)cn[b].el==this&&(this.unmousedown(cn[b].start),cn.splice(b,1),eve.unbind(\"raphael.drag.*.\"+this.id));!cn.length&&a.unmousemove(cj).unmouseup(ck)},k.circle=function(b,c,d){var e=a._engine.circle(this,b||0,c||0,d||0);this.__set__&&this.__set__.push(e);return e},k.rect=function(b,c,d,e,f){var g=a._engine.rect(this,b||0,c||0,d||0,e||0,f||0);this.__set__&&this.__set__.push(g);return g},k.ellipse=function(b,c,d,e){var f=a._engine.ellipse(this,b||0,c||0,d||0,e||0);this.__set__&&this.__set__.push(f);return f},k.path=function(b){b&&!a.is(b,D)&&!a.is(b[0],E)&&(b+=p);var c=a._engine.path(a.format[m](a,arguments),this);this.__set__&&this.__set__.push(c);return c},k.image=function(b,c,d,e,f){var g=a._engine.image(this,b||\"about:blank\",c||0,d||0,e||0,f||0);this.__set__&&this.__set__.push(g);return g},k.text=function(b,c,d){var e=a._engine.text(this,b||0,c||0,r(d));this.__set__&&this.__set__.push(e);return e},k.set=function(b){!a.is(b,\"array\")&&(b=Array.prototype.splice.call(arguments,0,arguments.length));var c=new cG(b);this.__set__&&this.__set__.push(c);return c},k.setStart=function(a){this.__set__=a||this.set()},k.setFinish=function(a){var b=this.__set__;delete this.__set__;return b},k.setSize=function(b,c){return a._engine.setSize.call(this,b,c)},k.setViewBox=function(b,c,d,e,f){return a._engine.setViewBox.call(this,b,c,d,e,f)},k.top=k.bottom=null,k.raphael=a;var co=function(a){var b=a.getBoundingClientRect(),c=a.ownerDocument,d=c.body,e=c.documentElement,f=e.clientTop||d.clientTop||0,g=e.clientLeft||d.clientLeft||0,i=b.top+(h.win.pageYOffset||e.scrollTop||d.scrollTop)-f,j=b.left+(h.win.pageXOffset||e.scrollLeft||d.scrollLeft)-g;return{y:i,x:j}};k.getElementByPoint=function(a,b){var c=this,d=c.canvas,e=h.doc.elementFromPoint(a,b);if(h.win.opera&&e.tagName==\"svg\"){var f=co(d),g=d.createSVGRect();g.x=a-f.x,g.y=b-f.y,g.width=g.height=1;var i=d.getIntersectionList(g,null);i.length&&(e=i[i.length-1])}if(!e)return null;while(e.parentNode&&e!=d.parentNode&&!e.raphael)e=e.parentNode;e==c.canvas.parentNode&&(e=d),e=e&&e.raphael?c.getById(e.raphaelid):null;return e},k.getById=function(a){var b=this.bottom;while(b){if(b.id==a)return b;b=b.next}return null},k.forEach=function(a,b){var c=this.bottom;while(c){if(a.call(b,c)===!1)return this;c=c.next}return this},k.getElementsByPoint=function(a,b){var c=this.set();this.forEach(function(d){d.isPointInside(a,b)&&c.push(d)});return c},cl.isPointInside=function(b,c){var d=this.realPath=this.realPath||bi[this.type](this);return a.isPointInsidePath(d,b,c)},cl.getBBox=function(a){if(this.removed)return{};var b=this._;if(a){if(b.dirty||!b.bboxwt)this.realPath=bi[this.type](this),b.bboxwt=bI(this.realPath),b.bboxwt.toString=cq,b.dirty=0;return b.bboxwt}if(b.dirty||b.dirtyT||!b.bbox){if(b.dirty||!this.realPath)b.bboxwt=0,this.realPath=bi[this.type](this);b.bbox=bI(bj(this.realPath,this.matrix)),b.bbox.toString=cq,b.dirty=b.dirtyT=0}return b.bbox},cl.clone=function(){if(this.removed)return null;var a=this.paper[this.type]().attr(this.attr());this.__set__&&this.__set__.push(a);return a},cl.glow=function(a){if(this.type==\"text\")return null;a=a||{};var b={width:(a.width||10)+(+this.attr(\"stroke-width\")||1),fill:a.fill||!1,opacity:a.opacity||.5,offsetx:a.offsetx||0,offsety:a.offsety||0,color:a.color||\"#000\"},c=b.width/2,d=this.paper,e=d.set(),f=this.realPath||bi[this.type](this);f=this.matrix?bj(f,this.matrix):f;for(var g=1;g<c+1;g++)e.push(d.path(f).attr({stroke:b.color,fill:b.fill?b.color:\"none\",\"stroke-linejoin\":\"round\",\"stroke-linecap\":\"round\",\"stroke-width\":+(b.width/c*g).toFixed(3),opacity:+(b.opacity/c).toFixed(3)}));return e.insertBefore(this).translate(b.offsetx,b.offsety)};var cr={},cs=function(b,c,d,e,f,g,h,i,j){return j==null?bB(b,c,d,e,f,g,h,i):a.findDotsAtSegment(b,c,d,e,f,g,h,i,bC(b,c,d,e,f,g,h,i,j))},ct=function(b,c){return function(d,e,f){d=bR(d);var g,h,i,j,k=\"\",l={},m,n=0;for(var o=0,p=d.length;o<p;o++){i=d[o];if(i[0]==\"M\")g=+i[1],h=+i[2];else{j=cs(g,h,i[1],i[2],i[3],i[4],i[5],i[6]);if(n+j>e){if(c&&!l.start){m=cs(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n),k+=[\"C\"+m.start.x,m.start.y,m.m.x,m.m.y,m.x,m.y];if(f)return k;l.start=k,k=[\"M\"+m.x,m.y+\"C\"+m.n.x,m.n.y,m.end.x,m.end.y,i[5],i[6]].join(),n+=j,g=+i[5],h=+i[6];continue}if(!b&&!c){m=cs(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n);return{x:m.x,y:m.y,alpha:m.alpha}}}n+=j,g=+i[5],h=+i[6]}k+=i.shift()+i}l.end=k,m=b?n:c?l:a.findDotsAtSegment(g,h,i[0],i[1],i[2],i[3],i[4],i[5],1),m.alpha&&(m={x:m.x,y:m.y,alpha:m.alpha});return m}},cu=ct(1),cv=ct(),cw=ct(0,1);a.getTotalLength=cu,a.getPointAtLength=cv,a.getSubpath=function(a,b,c){if(this.getTotalLength(a)-c<1e-6)return cw(a,b).end;var d=cw(a,c,1);return b?cw(d,b).end:d},cl.getTotalLength=function(){if(this.type==\"path\"){if(this.node.getTotalLength)return this.node.getTotalLength();return cu(this.attrs.path)}},cl.getPointAtLength=function(a){if(this.type==\"path\")return cv(this.attrs.path,a)},cl.getSubpath=function(b,c){if(this.type==\"path\")return a.getSubpath(this.attrs.path,b,c)};var cx=a.easing_formulas={linear:function(a){return a},\"<\":function(a){return A(a,1.7)},\">\":function(a){return A(a,.48)},\"<>\":function(a){var b=.48-a/1.04,c=w.sqrt(.1734+b*b),d=c-b,e=A(z(d),1/3)*(d<0?-1:1),f=-c-b,g=A(z(f),1/3)*(f<0?-1:1),h=e+g+.5;return(1-h)*3*h*h+h*h*h},backIn:function(a){var b=1.70158;return a*a*((b+1)*a-b)},backOut:function(a){a=a-1;var b=1.70158;return a*a*((b+1)*a+b)+1},elastic:function(a){if(a==!!a)return a;return A(2,-10*a)*w.sin((a-.075)*2*B/.3)+1},bounce:function(a){var b=7.5625,c=2.75,d;a<1/c?d=b*a*a:a<2/c?(a-=1.5/c,d=b*a*a+.75):a<2.5/c?(a-=2.25/c,d=b*a*a+.9375):(a-=2.625/c,d=b*a*a+.984375);return d}};cx.easeIn=cx[\"ease-in\"]=cx[\"<\"],cx.easeOut=cx[\"ease-out\"]=cx[\">\"],cx.easeInOut=cx[\"ease-in-out\"]=cx[\"<>\"],cx[\"back-in\"]=cx.backIn,cx[\"back-out\"]=cx.backOut;var cy=[],cz=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){setTimeout(a,16)},cA=function(){var b=+(new Date),c=0;for(;c<cy.length;c++){var d=cy[c];if(d.el.removed||d.paused)continue;var e=b-d.start,f=d.ms,h=d.easing,i=d.from,j=d.diff,k=d.to,l=d.t,m=d.el,o={},p,r={},s;d.initstatus?(e=(d.initstatus*d.anim.top-d.prev)/(d.percent-d.prev)*f,d.status=d.initstatus,delete d.initstatus,d.stop&&cy.splice(c--,1)):d.status=(d.prev+(d.percent-d.prev)*(e/f))/d.anim.top;if(e<0)continue;if(e<f){var t=h(e/f);for(var u in i)if(i[g](u)){switch(U[u]){case C:p=+i[u]+t*f*j[u];break;case\"colour\":p=\"rgb(\"+[cB(O(i[u].r+t*f*j[u].r)),cB(O(i[u].g+t*f*j[u].g)),cB(O(i[u].b+t*f*j[u].b))].join(\",\")+\")\";break;case\"path\":p=[];for(var v=0,w=i[u].length;v<w;v++){p[v]=[i[u][v][0]];for(var x=1,y=i[u][v].length;x<y;x++)p[v][x]=+i[u][v][x]+t*f*j[u][v][x];p[v]=p[v].join(q)}p=p.join(q);break;case\"transform\":if(j[u].real){p=[];for(v=0,w=i[u].length;v<w;v++){p[v]=[i[u][v][0]];for(x=1,y=i[u][v].length;x<y;x++)p[v][x]=i[u][v][x]+t*f*j[u][v][x]}}else{var z=function(a){return+i[u][a]+t*f*j[u][a]};p=[[\"m\",z(0),z(1),z(2),z(3),z(4),z(5)]]}break;case\"csv\":if(u==\"clip-rect\"){p=[],v=4;while(v--)p[v]=+i[u][v]+t*f*j[u][v]}break;default:var A=[][n](i[u]);p=[],v=m.paper.customAttributes[u].length;while(v--)p[v]=+A[v]+t*f*j[u][v]}o[u]=p}m.attr(o),function(a,b,c){setTimeout(function(){eve(\"raphael.anim.frame.\"+a,b,c)})}(m.id,m,d.anim)}else{(function(b,c,d){setTimeout(function(){eve(\"raphael.anim.frame.\"+c.id,c,d),eve(\"raphael.anim.finish.\"+c.id,c,d),a.is(b,\"function\")&&b.call(c)})})(d.callback,m,d.anim),m.attr(k),cy.splice(c--,1);if(d.repeat>1&&!d.next){for(s in k)k[g](s)&&(r[s]=d.totalOrigin[s]);d.el.attr(r),cE(d.anim,d.el,d.anim.percents[0],null,d.totalOrigin,d.repeat-1)}d.next&&!d.stop&&cE(d.anim,d.el,d.next,null,d.totalOrigin,d.repeat)}}a.svg&&m&&m.paper&&m.paper.safari(),cy.length&&cz(cA)},cB=function(a){return a>255?255:a<0?0:a};cl.animateWith=function(b,c,d,e,f,g){var h=this;if(h.removed){g&&g.call(h);return h}var i=d instanceof cD?d:a.animation(d,e,f,g),j,k;cE(i,h,i.percents[0],null,h.attr());for(var l=0,m=cy.length;l<m;l++)if(cy[l].anim==c&&cy[l].el==b){cy[m-1].start=cy[l].start;break}return h},cl.onAnimation=function(a){a?eve.on(\"raphael.anim.frame.\"+this.id,a):eve.unbind(\"raphael.anim.frame.\"+this.id);return this},cD.prototype.delay=function(a){var b=new cD(this.anim,this.ms);b.times=this.times,b.del=+a||0;return b},cD.prototype.repeat=function(a){var b=new cD(this.anim,this.ms);b.del=this.del,b.times=w.floor(x(a,0))||1;return b},a.animation=function(b,c,d,e){if(b instanceof cD)return b;if(a.is(d,\"function\")||!d)e=e||d||null,d=null;b=Object(b),c=+c||0;var f={},h,i;for(i in b)b[g](i)&&Q(i)!=i&&Q(i)+\"%\"!=i&&(h=!0,f[i]=b[i]);if(!h)return new cD(b,c);d&&(f.easing=d),e&&(f.callback=e);return new cD({100:f},c)},cl.animate=function(b,c,d,e){var f=this;if(f.removed){e&&e.call(f);return f}var g=b instanceof cD?b:a.animation(b,c,d,e);cE(g,f,g.percents[0],null,f.attr());return f},cl.setTime=function(a,b){a&&b!=null&&this.status(a,y(b,a.ms)/a.ms);return this},cl.status=function(a,b){var c=[],d=0,e,f;if(b!=null){cE(a,this,-1,y(b,1));return this}e=cy.length;for(;d<e;d++){f=cy[d];if(f.el.id==this.id&&(!a||f.anim==a)){if(a)return f.status;c.push({anim:f.anim,status:f.status})}}if(a)return 0;return c},cl.pause=function(a){for(var b=0;b<cy.length;b++)cy[b].el.id==this.id&&(!a||cy[b].anim==a)&&eve(\"raphael.anim.pause.\"+this.id,this,cy[b].anim)!==!1&&(cy[b].paused=!0);return this},cl.resume=function(a){for(var b=0;b<cy.length;b++)if(cy[b].el.id==this.id&&(!a||cy[b].anim==a)){var c=cy[b];eve(\"raphael.anim.resume.\"+this.id,this,c.anim)!==!1&&(delete c.paused,this.status(c.anim,c.status))}return this},cl.stop=function(a){for(var b=0;b<cy.length;b++)cy[b].el.id==this.id&&(!a||cy[b].anim==a)&&eve(\"raphael.anim.stop.\"+this.id,this,cy[b].anim)!==!1&&cy.splice(b--,1);return this},eve.on(\"raphael.remove\",cF),eve.on(\"raphael.clear\",cF),cl.toString=function(){return\"Raphaël’s object\"};var cG=function(a){this.items=[],this.length=0,this.type=\"set\";if(a)for(var b=0,c=a.length;b<c;b++)a[b]&&(a[b].constructor==cl.constructor||a[b].constructor==cG)&&(this[this.items.length]=this.items[this.items.length]=a[b],this.length++)},cH=cG.prototype;cH.push=function(){var a,b;for(var c=0,d=arguments.length;c<d;c++)a=arguments[c],a&&(a.constructor==cl.constructor||a.constructor==cG)&&(b=this.items.length,this[b]=this.items[b]=a,this.length++);return this},cH.pop=function(){this.length&&delete this[this.length--];return this.items.pop()},cH.forEach=function(a,b){for(var c=0,d=this.items.length;c<d;c++)if(a.call(b,this.items[c],c)===!1)return this;return this};for(var cI in cl)cl[g](cI)&&(cH[cI]=function(a){return function(){var b=arguments;return this.forEach(function(c){c[a][m](c,b)})}}(cI));cH.attr=function(b,c){if(b&&a.is(b,E)&&a.is(b[0],\"object\"))for(var d=0,e=b.length;d<e;d++)this.items[d].attr(b[d]);else for(var f=0,g=this.items.length;f<g;f++)this.items[f].attr(b,c);return this},cH.clear=function(){while(this.length)this.pop()},cH.splice=function(a,b,c){a=a<0?x(this.length+a,0):a,b=x(0,y(this.length-a,b));var d=[],e=[],f=[],g;for(g=2;g<arguments.length;g++)f.push(arguments[g]);for(g=0;g<b;g++)e.push(this[a+g]);for(;g<this.length-a;g++)d.push(this[a+g]);var h=f.length;for(g=0;g<h+d.length;g++)this.items[a+g]=this[a+g]=g<h?f[g]:d[g-h];g=this.items.length=this.length-=b-h;while(this[g])delete this[g++];return new cG(e)},cH.exclude=function(a){for(var b=0,c=this.length;b<c;b++)if(this[b]==a){this.splice(b,1);return!0}},cH.animate=function(b,c,d,e){(a.is(d,\"function\")||!d)&&(e=d||null);var f=this.items.length,g=f,h,i=this,j;if(!f)return this;e&&(j=function(){!--f&&e.call(i)}),d=a.is(d,D)?d:j;var k=a.animation(b,c,d,j);h=this.items[--g].animate(k);while(g--)this.items[g]&&!this.items[g].removed&&this.items[g].animateWith(h,k,k);return this},cH.insertAfter=function(a){var b=this.items.length;while(b--)this.items[b].insertAfter(a);return this},cH.getBBox=function(){var a=[],b=[],c=[],d=[];for(var e=this.items.length;e--;)if(!this.items[e].removed){var f=this.items[e].getBBox();a.push(f.x),b.push(f.y),c.push(f.x+f.width),d.push(f.y+f.height)}a=y[m](0,a),b=y[m](0,b),c=x[m](0,c),d=x[m](0,d);return{x:a,y:b,x2:c,y2:d,width:c-a,height:d-b}},cH.clone=function(a){a=new cG;for(var b=0,c=this.items.length;b<c;b++)a.push(this.items[b].clone());return a},cH.toString=function(){return\"Raphaël‘s set\"},a.registerFont=function(a){if(!a.face)return a;this.fonts=this.fonts||{};var b={w:a.w,face:{},glyphs:{}},c=a.face[\"font-family\"];for(var d in a.face)a.face[g](d)&&(b.face[d]=a.face[d]);this.fonts[c]?this.fonts[c].push(b):this.fonts[c]=[b];if(!a.svg){b.face[\"units-per-em\"]=R(a.face[\"units-per-em\"],10);for(var e in a.glyphs)if(a.glyphs[g](e)){var f=a.glyphs[e];b.glyphs[e]={w:f.w,k:{},d:f.d&&\"M\"+f.d.replace(/[mlcxtrv]/g,function(a){return{l:\"L\",c:\"C\",x:\"z\",t:\"m\",r:\"l\",v:\"c\"}[a]||\"M\"})+\"z\"};if(f.k)for(var h in f.k)f[g](h)&&(b.glyphs[e].k[h]=f.k[h])}}return a},k.getFont=function(b,c,d,e){e=e||\"normal\",d=d||\"normal\",c=+c||{normal:400,bold:700,lighter:300,bolder:800}[c]||400;if(!!a.fonts){var f=a.fonts[b];if(!f){var h=new RegExp(\"(^|\\\\s)\"+b.replace(/[^\\w\\d\\s+!~.:_-]/g,p)+\"(\\\\s|$)\",\"i\");for(var i in a.fonts)if(a.fonts[g](i)&&h.test(i)){f=a.fonts[i];break}}var j;if(f)for(var k=0,l=f.length;k<l;k++){j=f[k];if(j.face[\"font-weight\"]==c&&(j.face[\"font-style\"]==d||!j.face[\"font-style\"])&&j.face[\"font-stretch\"]==e)break}return j}},k.print=function(b,d,e,f,g,h,i){h=h||\"middle\",i=x(y(i||0,1),-1);var j=r(e)[s](p),k=0,l=0,m=p,n;a.is(f,e)&&(f=this.getFont(f));if(f){n=(g||16)/f.face[\"units-per-em\"];var o=f.face.bbox[s](c),q=+o[0],t=o[3]-o[1],u=0,v=+o[1]+(h==\"baseline\"?t+ +f.face.descent:t/2);for(var w=0,z=j.length;w<z;w++){if(j[w]==\"\\n\")k=0,B=0,l=0,u+=t;else{var A=l&&f.glyphs[j[w-1]]||{},B=f.glyphs[j[w]];k+=l?(A.w||f.w)+(A.k&&A.k[j[w]]||0)+f.w*i:0,l=1}B&&B.d&&(m+=a.transformPath(B.d,[\"t\",k*n,u*n,\"s\",n,n,q,v,\"t\",(b-q)/n,(d-v)/n]))}}return this.path(m).attr({fill:\"#000\",stroke:\"none\"})},k.add=function(b){if(a.is(b,\"array\")){var c=this.set(),e=0,f=b.length,h;for(;e<f;e++)h=b[e]||{},d[g](h.type)&&c.push(this[h.type]().attr(h))}return c},a.format=function(b,c){var d=a.is(c,E)?[0][n](c):arguments;b&&a.is(b,D)&&d.length-1&&(b=b.replace(e,function(a,b){return d[++b]==null?p:d[b]}));return b||p},a.fullfill=function(){var a=/\\{([^\\}]+)\\}/g,b=/(?:(?:^|\\.)(.+?)(?=\\[|\\.|$|\\()|\\[('|\")(.+?)\\2\\])(\\(\\))?/g,c=function(a,c,d){var e=d;c.replace(b,function(a,b,c,d,f){b=b||d,e&&(b in e&&(e=e[b]),typeof e==\"function\"&&f&&(e=e()))}),e=(e==null||e==d?a:e)+\"\";return e};return function(b,d){return String(b).replace(a,function(a,b){return c(a,b,d)})}}(),a.ninja=function(){i.was?h.win.Raphael=i.is:delete Raphael;return a},a.st=cH,function(b,c,d){function e(){/in/.test(b.readyState)?setTimeout(e,9):a.eve(\"raphael.DOMload\")}b.readyState==null&&b.addEventListener&&(b.addEventListener(c,d=function(){b.removeEventListener(c,d,!1),b.readyState=\"complete\"},!1),b.readyState=\"loading\"),e()}(document,\"DOMContentLoaded\"),i.was?h.win.Raphael=a:Raphael=a,eve.on(\"raphael.DOMload\",function(){b=!0})}(),window.Raphael.svg&&function(a){var b=\"hasOwnProperty\",c=String,d=parseFloat,e=parseInt,f=Math,g=f.max,h=f.abs,i=f.pow,j=/[, ]+/,k=a.eve,l=\"\",m=\" \",n=\"http://www.w3.org/1999/xlink\",o={block:\"M5,0 0,2.5 5,5z\",classic:\"M5,0 0,2.5 5,5 3.5,3 3.5,2z\",diamond:\"M2.5,0 5,2.5 2.5,5 0,2.5z\",open:\"M6,1 1,3.5 6,6\",oval:\"M2.5,0A2.5,2.5,0,0,1,2.5,5 2.5,2.5,0,0,1,2.5,0z\"},p={};a.toString=function(){return\"Your browser supports SVG.\\nYou are running Raphaël \"+this.version};var q=function(d,e){if(e){typeof d==\"string\"&&(d=q(d));for(var f in e)e[b](f)&&(f.substring(0,6)==\"xlink:\"?d.setAttributeNS(n,f.substring(6),c(e[f])):d.setAttribute(f,c(e[f])))}else d=a._g.doc.createElementNS(\"http://www.w3.org/2000/svg\",d),d.style&&(d.style.webkitTapHighlightColor=\"rgba(0,0,0,0)\");return d},r=function(b,e){var j=\"linear\",k=b.id+e,m=.5,n=.5,o=b.node,p=b.paper,r=o.style,s=a._g.doc.getElementById(k);if(!s){e=c(e).replace(a._radial_gradient,function(a,b,c){j=\"radial\";if(b&&c){m=d(b),n=d(c);var e=(n>.5)*2-1;i(m-.5,2)+i(n-.5,2)>.25&&(n=f.sqrt(.25-i(m-.5,2))*e+.5)&&n!=.5&&(n=n.toFixed(5)-1e-5*e)}return l}),e=e.split(/\\s*\\-\\s*/);if(j==\"linear\"){var t=e.shift();t=-d(t);if(isNaN(t))return null;var u=[0,0,f.cos(a.rad(t)),f.sin(a.rad(t))],v=1/(g(h(u[2]),h(u[3]))||1);u[2]*=v,u[3]*=v,u[2]<0&&(u[0]=-u[2],u[2]=0),u[3]<0&&(u[1]=-u[3],u[3]=0)}var w=a._parseDots(e);if(!w)return null;k=k.replace(/[\\(\\)\\s,\\xb0#]/g,\"_\"),b.gradient&&k!=b.gradient.id&&(p.defs.removeChild(b.gradient),delete b.gradient);if(!b.gradient){s=q(j+\"Gradient\",{id:k}),b.gradient=s,q(s,j==\"radial\"?{fx:m,fy:n}:{x1:u[0],y1:u[1],x2:u[2],y2:u[3],gradientTransform:b.matrix.invert()}),p.defs.appendChild(s);for(var x=0,y=w.length;x<y;x++)s.appendChild(q(\"stop\",{offset:w[x].offset?w[x].offset:x?\"100%\":\"0%\",\"stop-color\":w[x].color||\"#fff\"}))}}q(o,{fill:\"url(#\"+k+\")\",opacity:1,\"fill-opacity\":1}),r.fill=l,r.opacity=1,r.fillOpacity=1;return 1},s=function(a){var b=a.getBBox(1);q(a.pattern,{patternTransform:a.matrix.invert()+\" translate(\"+b.x+\",\"+b.y+\")\"})},t=function(d,e,f){if(d.type==\"path\"){var g=c(e).toLowerCase().split(\"-\"),h=d.paper,i=f?\"end\":\"start\",j=d.node,k=d.attrs,m=k[\"stroke-width\"],n=g.length,r=\"classic\",s,t,u,v,w,x=3,y=3,z=5;while(n--)switch(g[n]){case\"block\":case\"classic\":case\"oval\":case\"diamond\":case\"open\":case\"none\":r=g[n];break;case\"wide\":y=5;break;case\"narrow\":y=2;break;case\"long\":x=5;break;case\"short\":x=2}r==\"open\"?(x+=2,y+=2,z+=2,u=1,v=f?4:1,w={fill:\"none\",stroke:k.stroke}):(v=u=x/2,w={fill:k.stroke,stroke:\"none\"}),d._.arrows?f?(d._.arrows.endPath&&p[d._.arrows.endPath]--,d._.arrows.endMarker&&p[d._.arrows.endMarker]--):(d._.arrows.startPath&&p[d._.arrows.startPath]--,d._.arrows.startMarker&&p[d._.arrows.startMarker]--):d._.arrows={};if(r!=\"none\"){var A=\"raphael-marker-\"+r,B=\"raphael-marker-\"+i+r+x+y;a._g.doc.getElementById(A)?p[A]++:(h.defs.appendChild(q(q(\"path\"),{\"stroke-linecap\":\"round\",d:o[r],id:A})),p[A]=1);var C=a._g.doc.getElementById(B),D;C?(p[B]++,D=C.getElementsByTagName(\"use\")[0]):(C=q(q(\"marker\"),{id:B,markerHeight:y,markerWidth:x,orient:\"auto\",refX:v,refY:y/2}),D=q(q(\"use\"),{\"xlink:href\":\"#\"+A,transform:(f?\"rotate(180 \"+x/2+\" \"+y/2+\") \":l)+\"scale(\"+x/z+\",\"+y/z+\")\",\"stroke-width\":(1/((x/z+y/z)/2)).toFixed(4)}),C.appendChild(D),h.defs.appendChild(C),p[B]=1),q(D,w);var F=u*(r!=\"diamond\"&&r!=\"oval\");f?(s=d._.arrows.startdx*m||0,t=a.getTotalLength(k.path)-F*m):(s=F*m,t=a.getTotalLength(k.path)-(d._.arrows.enddx*m||0)),w={},w[\"marker-\"+i]=\"url(#\"+B+\")\";if(t||s)w.d=Raphael.getSubpath(k.path,s,t);q(j,w),d._.arrows[i+\"Path\"]=A,d._.arrows[i+\"Marker\"]=B,d._.arrows[i+\"dx\"]=F,d._.arrows[i+\"Type\"]=r,d._.arrows[i+\"String\"]=e}else f?(s=d._.arrows.startdx*m||0,t=a.getTotalLength(k.path)-s):(s=0,t=a.getTotalLength(k.path)-(d._.arrows.enddx*m||0)),d._.arrows[i+\"Path\"]&&q(j,{d:Raphael.getSubpath(k.path,s,t)}),delete d._.arrows[i+\"Path\"],delete d._.arrows[i+\"Marker\"],delete d._.arrows[i+\"dx\"],delete d._.arrows[i+\"Type\"],delete d._.arrows[i+\"String\"];for(w in p)if(p[b](w)&&!p[w]){var G=a._g.doc.getElementById(w);G&&G.parentNode.removeChild(G)}}},u={\"\":[0],none:[0],\"-\":[3,1],\".\":[1,1],\"-.\":[3,1,1,1],\"-..\":[3,1,1,1,1,1],\". \":[1,3],\"- \":[4,3],\"--\":[8,3],\"- .\":[4,3,1,3],\"--.\":[8,3,1,3],\"--..\":[8,3,1,3,1,3]},v=function(a,b,d){b=u[c(b).toLowerCase()];if(b){var e=a.attrs[\"stroke-width\"]||\"1\",f={round:e,square:e,butt:0}[a.attrs[\"stroke-linecap\"]||d[\"stroke-linecap\"]]||0,g=[],h=b.length;while(h--)g[h]=b[h]*e+(h%2?1:-1)*f;q(a.node,{\"stroke-dasharray\":g.join(\",\")})}},w=function(d,f){var i=d.node,k=d.attrs,m=i.style.visibility;i.style.visibility=\"hidden\";for(var o in f)if(f[b](o)){if(!a._availableAttrs[b](o))continue;var p=f[o];k[o]=p;switch(o){case\"blur\":d.blur(p);break;case\"href\":case\"title\":case\"target\":var u=i.parentNode;if(u.tagName.toLowerCase()!=\"a\"){var w=q(\"a\");u.insertBefore(w,i),w.appendChild(i),u=w}o==\"target\"?u.setAttributeNS(n,\"show\",p==\"blank\"?\"new\":p):u.setAttributeNS(n,o,p);break;case\"cursor\":i.style.cursor=p;break;case\"transform\":d.transform(p);break;case\"arrow-start\":t(d,p);break;case\"arrow-end\":t(d,p,1);break;case\"clip-rect\":var x=c(p).split(j);if(x.length==4){d.clip&&d.clip.parentNode.parentNode.removeChild(d.clip.parentNode);var z=q(\"clipPath\"),A=q(\"rect\");z.id=a.createUUID(),q(A,{x:x[0],y:x[1],width:x[2],height:x[3]}),z.appendChild(A),d.paper.defs.appendChild(z),q(i,{\"clip-path\":\"url(#\"+z.id+\")\"}),d.clip=A}if(!p){var B=i.getAttribute(\"clip-path\");if(B){var C=a._g.doc.getElementById(B.replace(/(^url\\(#|\\)$)/g,l));C&&C.parentNode.removeChild(C),q(i,{\"clip-path\":l}),delete d.clip}}break;case\"path\":d.type==\"path\"&&(q(i,{d:p?k.path=a._pathToAbsolute(p):\"M0,0\"}),d._.dirty=1,d._.arrows&&(\"startString\"in d._.arrows&&t(d,d._.arrows.startString),\"endString\"in d._.arrows&&t(d,d._.arrows.endString,1)));break;case\"width\":i.setAttribute(o,p),d._.dirty=1;if(k.fx)o=\"x\",p=k.x;else break;case\"x\":k.fx&&(p=-k.x-(k.width||0));case\"rx\":if(o==\"rx\"&&d.type==\"rect\")break;case\"cx\":i.setAttribute(o,p),d.pattern&&s(d),d._.dirty=1;break;case\"height\":i.setAttribute(o,p),d._.dirty=1;if(k.fy)o=\"y\",p=k.y;else break;case\"y\":k.fy&&(p=-k.y-(k.height||0));case\"ry\":if(o==\"ry\"&&d.type==\"rect\")break;case\"cy\":i.setAttribute(o,p),d.pattern&&s(d),d._.dirty=1;break;case\"r\":d.type==\"rect\"?q(i,{rx:p,ry:p}):i.setAttribute(o,p),d._.dirty=1;break;case\"src\":d.type==\"image\"&&i.setAttributeNS(n,\"href\",p);break;case\"stroke-width\":if(d._.sx!=1||d._.sy!=1)p/=g(h(d._.sx),h(d._.sy))||1;d.paper._vbSize&&(p*=d.paper._vbSize),i.setAttribute(o,p),k[\"stroke-dasharray\"]&&v(d,k[\"stroke-dasharray\"],f),d._.arrows&&(\"startString\"in d._.arrows&&t(d,d._.arrows.startString),\"endString\"in d._.arrows&&t(d,d._.arrows.endString,1));break;case\"stroke-dasharray\":v(d,p,f);break;case\"fill\":var D=c(p).match(a._ISURL);if(D){z=q(\"pattern\");var F=q(\"image\");z.id=a.createUUID(),q(z,{x:0,y:0,patternUnits:\"userSpaceOnUse\",height:1,width:1}),q(F,{x:0,y:0,\"xlink:href\":D[1]}),z.appendChild(F),function(b){a._preload(D[1],function(){var a=this.offsetWidth,c=this.offsetHeight;q(b,{width:a,height:c}),q(F,{width:a,height:c}),d.paper.safari()})}(z),d.paper.defs.appendChild(z),q(i,{fill:\"url(#\"+z.id+\")\"}),d.pattern=z,d.pattern&&s(d);break}var G=a.getRGB(p);if(!G.error)delete f.gradient,delete k.gradient,!a.is(k.opacity,\"undefined\")&&a.is(f.opacity,\"undefined\")&&q(i,{opacity:k.opacity}),!a.is(k[\"fill-opacity\"],\"undefined\")&&a.is(f[\"fill-opacity\"],\"undefined\")&&q(i,{\"fill-opacity\":k[\"fill-opacity\"]});else if((d.type==\"circle\"||d.type==\"ellipse\"||c(p).charAt()!=\"r\")&&r(d,p)){if(\"opacity\"in k||\"fill-opacity\"in k){var H=a._g.doc.getElementById(i.getAttribute(\"fill\").replace(/^url\\(#|\\)$/g,l));if(H){var I=H.getElementsByTagName(\"stop\");q(I[I.length-1],{\"stop-opacity\":(\"opacity\"in k?k.opacity:1)*(\"fill-opacity\"in k?k[\"fill-opacity\"]:1)})}}k.gradient=p,k.fill=\"none\";break}G[b](\"opacity\")&&q(i,{\"fill-opacity\":G.opacity>1?G.opacity/100:G.opacity});case\"stroke\":G=a.getRGB(p),i.setAttribute(o,G.hex),o==\"stroke\"&&G[b](\"opacity\")&&q(i,{\"stroke-opacity\":G.opacity>1?G.opacity/100:G.opacity}),o==\"stroke\"&&d._.arrows&&(\"startString\"in d._.arrows&&t(d,d._.arrows.startString),\"endString\"in d._.arrows&&t(d,d._.arrows.endString,1));break;case\"gradient\":(d.type==\"circle\"||d.type==\"ellipse\"||c(p).charAt()!=\"r\")&&r(d,p);break;case\"opacity\":k.gradient&&!k[b](\"stroke-opacity\")&&q(i,{\"stroke-opacity\":p>1?p/100:p});case\"fill-opacity\":if(k.gradient){H=a._g.doc.getElementById(i.getAttribute(\"fill\").replace(/^url\\(#|\\)$/g,l)),H&&(I=H.getElementsByTagName(\"stop\"),q(I[I.length-1],{\"stop-opacity\":p}));break};default:o==\"font-size\"&&(p=e(p,10)+\"px\");var J=o.replace(/(\\-.)/g,function(a){return a.substring(1).toUpperCase()});i.style[J]=p,d._.dirty=1,i.setAttribute(o,p)}}y(d,f),i.style.visibility=m},x=1.2,y=function(d,f){if(d.type==\"text\"&&!!(f[b](\"text\")||f[b](\"font\")||f[b](\"font-size\")||f[b](\"x\")||f[b](\"y\"))){var g=d.attrs,h=d.node,i=h.firstChild?e(a._g.doc.defaultView.getComputedStyle(h.firstChild,l).getPropertyValue(\"font-size\"),10):10;if(f[b](\"text\")){g.text=f.text;while(h.firstChild)h.removeChild(h.firstChild);var j=c(f.text).split(\"\\n\"),k=[],m;for(var n=0,o=j.length;n<o;n++)m=q(\"tspan\"),n&&q(m,{dy:i*x,x:g.x}),m.appendChild(a._g.doc.createTextNode(j[n])),h.appendChild(m),k[n]=m}else{k=h.getElementsByTagName(\"tspan\");for(n=0,o=k.length;n<o;n++)n?q(k[n],{dy:i*x,x:g.x}):q(k[0],{dy:0})}q(h,{x:g.x,y:g.y}),d._.dirty=1;var p=d._getBBox(),r=g.y-(p.y+p.height/2);r&&a.is(r,\"finite\")&&q(k[0],{dy:r})}},z=function(b,c){var d=0,e=0;this[0]=this.node=b,b.raphael=!0,this.id=a._oid++,b.raphaelid=this.id,this.matrix=a.matrix(),this.realPath=null,this.paper=c,this.attrs=this.attrs||{},this._={transform:[],sx:1,sy:1,deg:0,dx:0,dy:0,dirty:1},!c.bottom&&(c.bottom=this),this.prev=c.top,c.top&&(c.top.next=this),c.top=this,this.next=null},A=a.el;z.prototype=A,A.constructor=z,a._engine.path=function(a,b){var c=q(\"path\");b.canvas&&b.canvas.appendChild(c);var d=new z(c,b);d.type=\"path\",w(d,{fill:\"none\",stroke:\"#000\",path:a});return d},A.rotate=function(a,b,e){if(this.removed)return this;a=c(a).split(j),a.length-1&&(b=d(a[1]),e=d(a[2])),a=d(a[0]),e==null&&(b=e);if(b==null||e==null){var f=this.getBBox(1);b=f.x+f.width/2,e=f.y+f.height/2}this.transform(this._.transform.concat([[\"r\",a,b,e]]));return this},A.scale=function(a,b,e,f){if(this.removed)return this;a=c(a).split(j),a.length-1&&(b=d(a[1]),e=d(a[2]),f=d(a[3])),a=d(a[0]),b==null&&(b=a),f==null&&(e=f);if(e==null||f==null)var g=this.getBBox(1);e=e==null?g.x+g.width/2:e,f=f==null?g.y+g.height/2:f,this.transform(this._.transform.concat([[\"s\",a,b,e,f]]));return this},A.translate=function(a,b){if(this.removed)return this;a=c(a).split(j),a.length-1&&(b=d(a[1])),a=d(a[0])||0,b=+b||0,this.transform(this._.transform.concat([[\"t\",a,b]]));return this},A.transform=function(c){var d=this._;if(c==null)return d.transform;a._extractTransform(this,c),this.clip&&q(this.clip,{transform:this.matrix.invert()}),this.pattern&&s(this),this.node&&q(this.node,{transform:this.matrix});if(d.sx!=1||d.sy!=1){var e=this.attrs[b](\"stroke-width\")?this.attrs[\"stroke-width\"]:1;this.attr({\"stroke-width\":e})}return this},A.hide=function(){!this.removed&&this.paper.safari(this.node.style.display=\"none\");return this},A.show=function(){!\nthis.removed&&this.paper.safari(this.node.style.display=\"\");return this},A.remove=function(){if(!this.removed&&!!this.node.parentNode){var b=this.paper;b.__set__&&b.__set__.exclude(this),k.unbind(\"raphael.*.*.\"+this.id),this.gradient&&b.defs.removeChild(this.gradient),a._tear(this,b),this.node.parentNode.tagName.toLowerCase()==\"a\"?this.node.parentNode.parentNode.removeChild(this.node.parentNode):this.node.parentNode.removeChild(this.node);for(var c in this)this[c]=typeof this[c]==\"function\"?a._removedFactory(c):null;this.removed=!0}},A._getBBox=function(){if(this.node.style.display==\"none\"){this.show();var a=!0}var b={};try{b=this.node.getBBox()}catch(c){}finally{b=b||{}}a&&this.hide();return b},A.attr=function(c,d){if(this.removed)return this;if(c==null){var e={};for(var f in this.attrs)this.attrs[b](f)&&(e[f]=this.attrs[f]);e.gradient&&e.fill==\"none\"&&(e.fill=e.gradient)&&delete e.gradient,e.transform=this._.transform;return e}if(d==null&&a.is(c,\"string\")){if(c==\"fill\"&&this.attrs.fill==\"none\"&&this.attrs.gradient)return this.attrs.gradient;if(c==\"transform\")return this._.transform;var g=c.split(j),h={};for(var i=0,l=g.length;i<l;i++)c=g[i],c in this.attrs?h[c]=this.attrs[c]:a.is(this.paper.customAttributes[c],\"function\")?h[c]=this.paper.customAttributes[c].def:h[c]=a._availableAttrs[c];return l-1?h:h[g[0]]}if(d==null&&a.is(c,\"array\")){h={};for(i=0,l=c.length;i<l;i++)h[c[i]]=this.attr(c[i]);return h}if(d!=null){var m={};m[c]=d}else c!=null&&a.is(c,\"object\")&&(m=c);for(var n in m)k(\"raphael.attr.\"+n+\".\"+this.id,this,m[n]);for(n in this.paper.customAttributes)if(this.paper.customAttributes[b](n)&&m[b](n)&&a.is(this.paper.customAttributes[n],\"function\")){var o=this.paper.customAttributes[n].apply(this,[].concat(m[n]));this.attrs[n]=m[n];for(var p in o)o[b](p)&&(m[p]=o[p])}w(this,m);return this},A.toFront=function(){if(this.removed)return this;this.node.parentNode.tagName.toLowerCase()==\"a\"?this.node.parentNode.parentNode.appendChild(this.node.parentNode):this.node.parentNode.appendChild(this.node);var b=this.paper;b.top!=this&&a._tofront(this,b);return this},A.toBack=function(){if(this.removed)return this;var b=this.node.parentNode;b.tagName.toLowerCase()==\"a\"?b.parentNode.insertBefore(this.node.parentNode,this.node.parentNode.parentNode.firstChild):b.firstChild!=this.node&&b.insertBefore(this.node,this.node.parentNode.firstChild),a._toback(this,this.paper);var c=this.paper;return this},A.insertAfter=function(b){if(this.removed)return this;var c=b.node||b[b.length-1].node;c.nextSibling?c.parentNode.insertBefore(this.node,c.nextSibling):c.parentNode.appendChild(this.node),a._insertafter(this,b,this.paper);return this},A.insertBefore=function(b){if(this.removed)return this;var c=b.node||b[0].node;c.parentNode.insertBefore(this.node,c),a._insertbefore(this,b,this.paper);return this},A.blur=function(b){var c=this;if(+b!==0){var d=q(\"filter\"),e=q(\"feGaussianBlur\");c.attrs.blur=b,d.id=a.createUUID(),q(e,{stdDeviation:+b||1.5}),d.appendChild(e),c.paper.defs.appendChild(d),c._blur=d,q(c.node,{filter:\"url(#\"+d.id+\")\"})}else c._blur&&(c._blur.parentNode.removeChild(c._blur),delete c._blur,delete c.attrs.blur),c.node.removeAttribute(\"filter\")},a._engine.circle=function(a,b,c,d){var e=q(\"circle\");a.canvas&&a.canvas.appendChild(e);var f=new z(e,a);f.attrs={cx:b,cy:c,r:d,fill:\"none\",stroke:\"#000\"},f.type=\"circle\",q(e,f.attrs);return f},a._engine.rect=function(a,b,c,d,e,f){var g=q(\"rect\");a.canvas&&a.canvas.appendChild(g);var h=new z(g,a);h.attrs={x:b,y:c,width:d,height:e,r:f||0,rx:f||0,ry:f||0,fill:\"none\",stroke:\"#000\"},h.type=\"rect\",q(g,h.attrs);return h},a._engine.ellipse=function(a,b,c,d,e){var f=q(\"ellipse\");a.canvas&&a.canvas.appendChild(f);var g=new z(f,a);g.attrs={cx:b,cy:c,rx:d,ry:e,fill:\"none\",stroke:\"#000\"},g.type=\"ellipse\",q(f,g.attrs);return g},a._engine.image=function(a,b,c,d,e,f){var g=q(\"image\");q(g,{x:c,y:d,width:e,height:f,preserveAspectRatio:\"none\"}),g.setAttributeNS(n,\"href\",b),a.canvas&&a.canvas.appendChild(g);var h=new z(g,a);h.attrs={x:c,y:d,width:e,height:f,src:b},h.type=\"image\";return h},a._engine.text=function(b,c,d,e){var f=q(\"text\");b.canvas&&b.canvas.appendChild(f);var g=new z(f,b);g.attrs={x:c,y:d,\"text-anchor\":\"middle\",text:e,font:a._availableAttrs.font,stroke:\"none\",fill:\"#000\"},g.type=\"text\",w(g,g.attrs);return g},a._engine.setSize=function(a,b){this.width=a||this.width,this.height=b||this.height,this.canvas.setAttribute(\"width\",this.width),this.canvas.setAttribute(\"height\",this.height),this._viewBox&&this.setViewBox.apply(this,this._viewBox);return this},a._engine.create=function(){var b=a._getContainer.apply(0,arguments),c=b&&b.container,d=b.x,e=b.y,f=b.width,g=b.height;if(!c)throw new Error(\"SVG container not found.\");var h=q(\"svg\"),i=\"overflow:hidden;\",j;d=d||0,e=e||0,f=f||512,g=g||342,q(h,{height:g,version:1.1,width:f,xmlns:\"http://www.w3.org/2000/svg\"}),c==1?(h.style.cssText=i+\"position:absolute;left:\"+d+\"px;top:\"+e+\"px\",a._g.doc.body.appendChild(h),j=1):(h.style.cssText=i+\"position:relative\",c.firstChild?c.insertBefore(h,c.firstChild):c.appendChild(h)),c=new a._Paper,c.width=f,c.height=g,c.canvas=h,c.clear(),c._left=c._top=0,j&&(c.renderfix=function(){}),c.renderfix();return c},a._engine.setViewBox=function(a,b,c,d,e){k(\"raphael.setViewBox\",this,this._viewBox,[a,b,c,d,e]);var f=g(c/this.width,d/this.height),h=this.top,i=e?\"meet\":\"xMinYMin\",j,l;a==null?(this._vbSize&&(f=1),delete this._vbSize,j=\"0 0 \"+this.width+m+this.height):(this._vbSize=f,j=a+m+b+m+c+m+d),q(this.canvas,{viewBox:j,preserveAspectRatio:i});while(f&&h)l=\"stroke-width\"in h.attrs?h.attrs[\"stroke-width\"]:1,h.attr({\"stroke-width\":l}),h._.dirty=1,h._.dirtyT=1,h=h.prev;this._viewBox=[a,b,c,d,!!e];return this},a.prototype.renderfix=function(){var a=this.canvas,b=a.style,c;try{c=a.getScreenCTM()||a.createSVGMatrix()}catch(d){c=a.createSVGMatrix()}var e=-c.e%1,f=-c.f%1;if(e||f)e&&(this._left=(this._left+e)%1,b.left=this._left+\"px\"),f&&(this._top=(this._top+f)%1,b.top=this._top+\"px\")},a.prototype.clear=function(){a.eve(\"raphael.clear\",this);var b=this.canvas;while(b.firstChild)b.removeChild(b.firstChild);this.bottom=this.top=null,(this.desc=q(\"desc\")).appendChild(a._g.doc.createTextNode(\"Created with Raphaël \"+a.version)),b.appendChild(this.desc),b.appendChild(this.defs=q(\"defs\"))},a.prototype.remove=function(){k(\"raphael.remove\",this),this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas);for(var b in this)this[b]=typeof this[b]==\"function\"?a._removedFactory(b):null};var B=a.st;for(var C in A)A[b](C)&&!B[b](C)&&(B[C]=function(a){return function(){var b=arguments;return this.forEach(function(c){c[a].apply(c,b)})}}(C))}(window.Raphael),window.Raphael.vml&&function(a){var b=\"hasOwnProperty\",c=String,d=parseFloat,e=Math,f=e.round,g=e.max,h=e.min,i=e.abs,j=\"fill\",k=/[, ]+/,l=a.eve,m=\" progid:DXImageTransform.Microsoft\",n=\" \",o=\"\",p={M:\"m\",L:\"l\",C:\"c\",Z:\"x\",m:\"t\",l:\"r\",c:\"v\",z:\"x\"},q=/([clmz]),?([^clmz]*)/gi,r=/ progid:\\S+Blur\\([^\\)]+\\)/g,s=/-?[^,\\s-]+/g,t=\"position:absolute;left:0;top:0;width:1px;height:1px\",u=21600,v={path:1,rect:1,image:1},w={circle:1,ellipse:1},x=function(b){var d=/[ahqstv]/ig,e=a._pathToAbsolute;c(b).match(d)&&(e=a._path2curve),d=/[clmz]/g;if(e==a._pathToAbsolute&&!c(b).match(d)){var g=c(b).replace(q,function(a,b,c){var d=[],e=b.toLowerCase()==\"m\",g=p[b];c.replace(s,function(a){e&&d.length==2&&(g+=d+p[b==\"m\"?\"l\":\"L\"],d=[]),d.push(f(a*u))});return g+d});return g}var h=e(b),i,j;g=[];for(var k=0,l=h.length;k<l;k++){i=h[k],j=h[k][0].toLowerCase(),j==\"z\"&&(j=\"x\");for(var m=1,r=i.length;m<r;m++)j+=f(i[m]*u)+(m!=r-1?\",\":o);g.push(j)}return g.join(n)},y=function(b,c,d){var e=a.matrix();e.rotate(-b,.5,.5);return{dx:e.x(c,d),dy:e.y(c,d)}},z=function(a,b,c,d,e,f){var g=a._,h=a.matrix,k=g.fillpos,l=a.node,m=l.style,o=1,p=\"\",q,r=u/b,s=u/c;m.visibility=\"hidden\";if(!!b&&!!c){l.coordsize=i(r)+n+i(s),m.rotation=f*(b*c<0?-1:1);if(f){var t=y(f,d,e);d=t.dx,e=t.dy}b<0&&(p+=\"x\"),c<0&&(p+=\" y\")&&(o=-1),m.flip=p,l.coordorigin=d*-r+n+e*-s;if(k||g.fillsize){var v=l.getElementsByTagName(j);v=v&&v[0],l.removeChild(v),k&&(t=y(f,h.x(k[0],k[1]),h.y(k[0],k[1])),v.position=t.dx*o+n+t.dy*o),g.fillsize&&(v.size=g.fillsize[0]*i(b)+n+g.fillsize[1]*i(c)),l.appendChild(v)}m.visibility=\"visible\"}};a.toString=function(){return\"Your browser doesn’t support SVG. Falling down to VML.\\nYou are running Raphaël \"+this.version};var A=function(a,b,d){var e=c(b).toLowerCase().split(\"-\"),f=d?\"end\":\"start\",g=e.length,h=\"classic\",i=\"medium\",j=\"medium\";while(g--)switch(e[g]){case\"block\":case\"classic\":case\"oval\":case\"diamond\":case\"open\":case\"none\":h=e[g];break;case\"wide\":case\"narrow\":j=e[g];break;case\"long\":case\"short\":i=e[g]}var k=a.node.getElementsByTagName(\"stroke\")[0];k[f+\"arrow\"]=h,k[f+\"arrowlength\"]=i,k[f+\"arrowwidth\"]=j},B=function(e,i){e.attrs=e.attrs||{};var l=e.node,m=e.attrs,p=l.style,q,r=v[e.type]&&(i.x!=m.x||i.y!=m.y||i.width!=m.width||i.height!=m.height||i.cx!=m.cx||i.cy!=m.cy||i.rx!=m.rx||i.ry!=m.ry||i.r!=m.r),s=w[e.type]&&(m.cx!=i.cx||m.cy!=i.cy||m.r!=i.r||m.rx!=i.rx||m.ry!=i.ry),t=e;for(var y in i)i[b](y)&&(m[y]=i[y]);r&&(m.path=a._getPath[e.type](e),e._.dirty=1),i.href&&(l.href=i.href),i.title&&(l.title=i.title),i.target&&(l.target=i.target),i.cursor&&(p.cursor=i.cursor),\"blur\"in i&&e.blur(i.blur);if(i.path&&e.type==\"path\"||r)l.path=x(~c(m.path).toLowerCase().indexOf(\"r\")?a._pathToAbsolute(m.path):m.path),e.type==\"image\"&&(e._.fillpos=[m.x,m.y],e._.fillsize=[m.width,m.height],z(e,1,1,0,0,0));\"transform\"in i&&e.transform(i.transform);if(s){var B=+m.cx,D=+m.cy,E=+m.rx||+m.r||0,G=+m.ry||+m.r||0;l.path=a.format(\"ar{0},{1},{2},{3},{4},{1},{4},{1}x\",f((B-E)*u),f((D-G)*u),f((B+E)*u),f((D+G)*u),f(B*u))}if(\"clip-rect\"in i){var H=c(i[\"clip-rect\"]).split(k);if(H.length==4){H[2]=+H[2]+ +H[0],H[3]=+H[3]+ +H[1];var I=l.clipRect||a._g.doc.createElement(\"div\"),J=I.style;J.clip=a.format(\"rect({1}px {2}px {3}px {0}px)\",H),l.clipRect||(J.position=\"absolute\",J.top=0,J.left=0,J.width=e.paper.width+\"px\",J.height=e.paper.height+\"px\",l.parentNode.insertBefore(I,l),I.appendChild(l),l.clipRect=I)}i[\"clip-rect\"]||l.clipRect&&(l.clipRect.style.clip=\"auto\")}if(e.textpath){var K=e.textpath.style;i.font&&(K.font=i.font),i[\"font-family\"]&&(K.fontFamily='\"'+i[\"font-family\"].split(\",\")[0].replace(/^['\"]+|['\"]+$/g,o)+'\"'),i[\"font-size\"]&&(K.fontSize=i[\"font-size\"]),i[\"font-weight\"]&&(K.fontWeight=i[\"font-weight\"]),i[\"font-style\"]&&(K.fontStyle=i[\"font-style\"])}\"arrow-start\"in i&&A(t,i[\"arrow-start\"]),\"arrow-end\"in i&&A(t,i[\"arrow-end\"],1);if(i.opacity!=null||i[\"stroke-width\"]!=null||i.fill!=null||i.src!=null||i.stroke!=null||i[\"stroke-width\"]!=null||i[\"stroke-opacity\"]!=null||i[\"fill-opacity\"]!=null||i[\"stroke-dasharray\"]!=null||i[\"stroke-miterlimit\"]!=null||i[\"stroke-linejoin\"]!=null||i[\"stroke-linecap\"]!=null){var L=l.getElementsByTagName(j),M=!1;L=L&&L[0],!L&&(M=L=F(j)),e.type==\"image\"&&i.src&&(L.src=i.src),i.fill&&(L.on=!0);if(L.on==null||i.fill==\"none\"||i.fill===null)L.on=!1;if(L.on&&i.fill){var N=c(i.fill).match(a._ISURL);if(N){L.parentNode==l&&l.removeChild(L),L.rotate=!0,L.src=N[1],L.type=\"tile\";var O=e.getBBox(1);L.position=O.x+n+O.y,e._.fillpos=[O.x,O.y],a._preload(N[1],function(){e._.fillsize=[this.offsetWidth,this.offsetHeight]})}else L.color=a.getRGB(i.fill).hex,L.src=o,L.type=\"solid\",a.getRGB(i.fill).error&&(t.type in{circle:1,ellipse:1}||c(i.fill).charAt()!=\"r\")&&C(t,i.fill,L)&&(m.fill=\"none\",m.gradient=i.fill,L.rotate=!1)}if(\"fill-opacity\"in i||\"opacity\"in i){var P=((+m[\"fill-opacity\"]+1||2)-1)*((+m.opacity+1||2)-1)*((+a.getRGB(i.fill).o+1||2)-1);P=h(g(P,0),1),L.opacity=P,L.src&&(L.color=\"none\")}l.appendChild(L);var Q=l.getElementsByTagName(\"stroke\")&&l.getElementsByTagName(\"stroke\")[0],T=!1;!Q&&(T=Q=F(\"stroke\"));if(i.stroke&&i.stroke!=\"none\"||i[\"stroke-width\"]||i[\"stroke-opacity\"]!=null||i[\"stroke-dasharray\"]||i[\"stroke-miterlimit\"]||i[\"stroke-linejoin\"]||i[\"stroke-linecap\"])Q.on=!0;(i.stroke==\"none\"||i.stroke===null||Q.on==null||i.stroke==0||i[\"stroke-width\"]==0)&&(Q.on=!1);var U=a.getRGB(i.stroke);Q.on&&i.stroke&&(Q.color=U.hex),P=((+m[\"stroke-opacity\"]+1||2)-1)*((+m.opacity+1||2)-1)*((+U.o+1||2)-1);var V=(d(i[\"stroke-width\"])||1)*.75;P=h(g(P,0),1),i[\"stroke-width\"]==null&&(V=m[\"stroke-width\"]),i[\"stroke-width\"]&&(Q.weight=V),V&&V<1&&(P*=V)&&(Q.weight=1),Q.opacity=P,i[\"stroke-linejoin\"]&&(Q.joinstyle=i[\"stroke-linejoin\"]||\"miter\"),Q.miterlimit=i[\"stroke-miterlimit\"]||8,i[\"stroke-linecap\"]&&(Q.endcap=i[\"stroke-linecap\"]==\"butt\"?\"flat\":i[\"stroke-linecap\"]==\"square\"?\"square\":\"round\");if(i[\"stroke-dasharray\"]){var W={\"-\":\"shortdash\",\".\":\"shortdot\",\"-.\":\"shortdashdot\",\"-..\":\"shortdashdotdot\",\". \":\"dot\",\"- \":\"dash\",\"--\":\"longdash\",\"- .\":\"dashdot\",\"--.\":\"longdashdot\",\"--..\":\"longdashdotdot\"};Q.dashstyle=W[b](i[\"stroke-dasharray\"])?W[i[\"stroke-dasharray\"]]:o}T&&l.appendChild(Q)}if(t.type==\"text\"){t.paper.canvas.style.display=o;var X=t.paper.span,Y=100,Z=m.font&&m.font.match(/\\d+(?:\\.\\d*)?(?=px)/);p=X.style,m.font&&(p.font=m.font),m[\"font-family\"]&&(p.fontFamily=m[\"font-family\"]),m[\"font-weight\"]&&(p.fontWeight=m[\"font-weight\"]),m[\"font-style\"]&&(p.fontStyle=m[\"font-style\"]),Z=d(m[\"font-size\"]||Z&&Z[0])||10,p.fontSize=Z*Y+\"px\",t.textpath.string&&(X.innerHTML=c(t.textpath.string).replace(/</g,\"&#60;\").replace(/&/g,\"&#38;\").replace(/\\n/g,\"<br>\"));var $=X.getBoundingClientRect();t.W=m.w=($.right-$.left)/Y,t.H=m.h=($.bottom-$.top)/Y,t.X=m.x,t.Y=m.y+t.H/2,(\"x\"in i||\"y\"in i)&&(t.path.v=a.format(\"m{0},{1}l{2},{1}\",f(m.x*u),f(m.y*u),f(m.x*u)+1));var _=[\"x\",\"y\",\"text\",\"font\",\"font-family\",\"font-weight\",\"font-style\",\"font-size\"];for(var ba=0,bb=_.length;ba<bb;ba++)if(_[ba]in i){t._.dirty=1;break}switch(m[\"text-anchor\"]){case\"start\":t.textpath.style[\"v-text-align\"]=\"left\",t.bbx=t.W/2;break;case\"end\":t.textpath.style[\"v-text-align\"]=\"right\",t.bbx=-t.W/2;break;default:t.textpath.style[\"v-text-align\"]=\"center\",t.bbx=0}t.textpath.style[\"v-text-kern\"]=!0}},C=function(b,f,g){b.attrs=b.attrs||{};var h=b.attrs,i=Math.pow,j,k,l=\"linear\",m=\".5 .5\";b.attrs.gradient=f,f=c(f).replace(a._radial_gradient,function(a,b,c){l=\"radial\",b&&c&&(b=d(b),c=d(c),i(b-.5,2)+i(c-.5,2)>.25&&(c=e.sqrt(.25-i(b-.5,2))*((c>.5)*2-1)+.5),m=b+n+c);return o}),f=f.split(/\\s*\\-\\s*/);if(l==\"linear\"){var p=f.shift();p=-d(p);if(isNaN(p))return null}var q=a._parseDots(f);if(!q)return null;b=b.shape||b.node;if(q.length){b.removeChild(g),g.on=!0,g.method=\"none\",g.color=q[0].color,g.color2=q[q.length-1].color;var r=[];for(var s=0,t=q.length;s<t;s++)q[s].offset&&r.push(q[s].offset+n+q[s].color);g.colors=r.length?r.join():\"0% \"+g.color,l==\"radial\"?(g.type=\"gradientTitle\",g.focus=\"100%\",g.focussize=\"0 0\",g.focusposition=m,g.angle=0):(g.type=\"gradient\",g.angle=(270-p)%360),b.appendChild(g)}return 1},D=function(b,c){this[0]=this.node=b,b.raphael=!0,this.id=a._oid++,b.raphaelid=this.id,this.X=0,this.Y=0,this.attrs={},this.paper=c,this.matrix=a.matrix(),this._={transform:[],sx:1,sy:1,dx:0,dy:0,deg:0,dirty:1,dirtyT:1},!c.bottom&&(c.bottom=this),this.prev=c.top,c.top&&(c.top.next=this),c.top=this,this.next=null},E=a.el;D.prototype=E,E.constructor=D,E.transform=function(b){if(b==null)return this._.transform;var d=this.paper._viewBoxShift,e=d?\"s\"+[d.scale,d.scale]+\"-1-1t\"+[d.dx,d.dy]:o,f;d&&(f=b=c(b).replace(/\\.{3}|\\u2026/g,this._.transform||o)),a._extractTransform(this,e+b);var g=this.matrix.clone(),h=this.skew,i=this.node,j,k=~c(this.attrs.fill).indexOf(\"-\"),l=!c(this.attrs.fill).indexOf(\"url(\");g.translate(-0.5,-0.5);if(l||k||this.type==\"image\"){h.matrix=\"1 0 0 1\",h.offset=\"0 0\",j=g.split();if(k&&j.noRotation||!j.isSimple){i.style.filter=g.toFilter();var m=this.getBBox(),p=this.getBBox(1),q=m.x-p.x,r=m.y-p.y;i.coordorigin=q*-u+n+r*-u,z(this,1,1,q,r,0)}else i.style.filter=o,z(this,j.scalex,j.scaley,j.dx,j.dy,j.rotate)}else i.style.filter=o,h.matrix=c(g),h.offset=g.offset();f&&(this._.transform=f);return this},E.rotate=function(a,b,e){if(this.removed)return this;if(a!=null){a=c(a).split(k),a.length-1&&(b=d(a[1]),e=d(a[2])),a=d(a[0]),e==null&&(b=e);if(b==null||e==null){var f=this.getBBox(1);b=f.x+f.width/2,e=f.y+f.height/2}this._.dirtyT=1,this.transform(this._.transform.concat([[\"r\",a,b,e]]));return this}},E.translate=function(a,b){if(this.removed)return this;a=c(a).split(k),a.length-1&&(b=d(a[1])),a=d(a[0])||0,b=+b||0,this._.bbox&&(this._.bbox.x+=a,this._.bbox.y+=b),this.transform(this._.transform.concat([[\"t\",a,b]]));return this},E.scale=function(a,b,e,f){if(this.removed)return this;a=c(a).split(k),a.length-1&&(b=d(a[1]),e=d(a[2]),f=d(a[3]),isNaN(e)&&(e=null),isNaN(f)&&(f=null)),a=d(a[0]),b==null&&(b=a),f==null&&(e=f);if(e==null||f==null)var g=this.getBBox(1);e=e==null?g.x+g.width/2:e,f=f==null?g.y+g.height/2:f,this.transform(this._.transform.concat([[\"s\",a,b,e,f]])),this._.dirtyT=1;return this},E.hide=function(){!this.removed&&(this.node.style.display=\"none\");return this},E.show=function(){!this.removed&&(this.node.style.display=o);return this},E._getBBox=function(){if(this.removed)return{};return{x:this.X+(this.bbx||0)-this.W/2,y:this.Y-this.H,width:this.W,height:this.H}},E.remove=function(){if(!this.removed&&!!this.node.parentNode){this.paper.__set__&&this.paper.__set__.exclude(this),a.eve.unbind(\"raphael.*.*.\"+this.id),a._tear(this,this.paper),this.node.parentNode.removeChild(this.node),this.shape&&this.shape.parentNode.removeChild(this.shape);for(var b in this)this[b]=typeof this[b]==\"function\"?a._removedFactory(b):null;this.removed=!0}},E.attr=function(c,d){if(this.removed)return this;if(c==null){var e={};for(var f in this.attrs)this.attrs[b](f)&&(e[f]=this.attrs[f]);e.gradient&&e.fill==\"none\"&&(e.fill=e.gradient)&&delete e.gradient,e.transform=this._.transform;return e}if(d==null&&a.is(c,\"string\")){if(c==j&&this.attrs.fill==\"none\"&&this.attrs.gradient)return this.attrs.gradient;var g=c.split(k),h={};for(var i=0,m=g.length;i<m;i++)c=g[i],c in this.attrs?h[c]=this.attrs[c]:a.is(this.paper.customAttributes[c],\"function\")?h[c]=this.paper.customAttributes[c].def:h[c]=a._availableAttrs[c];return m-1?h:h[g[0]]}if(this.attrs&&d==null&&a.is(c,\"array\")){h={};for(i=0,m=c.length;i<m;i++)h[c[i]]=this.attr(c[i]);return h}var n;d!=null&&(n={},n[c]=d),d==null&&a.is(c,\"object\")&&(n=c);for(var o in n)l(\"raphael.attr.\"+o+\".\"+this.id,this,n[o]);if(n){for(o in this.paper.customAttributes)if(this.paper.customAttributes[b](o)&&n[b](o)&&a.is(this.paper.customAttributes[o],\"function\")){var p=this.paper.customAttributes[o].apply(this,[].concat(n[o]));this.attrs[o]=n[o];for(var q in p)p[b](q)&&(n[q]=p[q])}n.text&&this.type==\"text\"&&(this.textpath.string=n.text),B(this,n)}return this},E.toFront=function(){!this.removed&&this.node.parentNode.appendChild(this.node),this.paper&&this.paper.top!=this&&a._tofront(this,this.paper);return this},E.toBack=function(){if(this.removed)return this;this.node.parentNode.firstChild!=this.node&&(this.node.parentNode.insertBefore(this.node,this.node.parentNode.firstChild),a._toback(this,this.paper));return this},E.insertAfter=function(b){if(this.removed)return this;b.constructor==a.st.constructor&&(b=b[b.length-1]),b.node.nextSibling?b.node.parentNode.insertBefore(this.node,b.node.nextSibling):b.node.parentNode.appendChild(this.node),a._insertafter(this,b,this.paper);return this},E.insertBefore=function(b){if(this.removed)return this;b.constructor==a.st.constructor&&(b=b[0]),b.node.parentNode.insertBefore(this.node,b.node),a._insertbefore(this,b,this.paper);return this},E.blur=function(b){var c=this.node.runtimeStyle,d=c.filter;d=d.replace(r,o),+b!==0?(this.attrs.blur=b,c.filter=d+n+m+\".Blur(pixelradius=\"+(+b||1.5)+\")\",c.margin=a.format(\"-{0}px 0 0 -{0}px\",f(+b||1.5))):(c.filter=d,c.margin=0,delete this.attrs.blur)},a._engine.path=function(a,b){var c=F(\"shape\");c.style.cssText=t,c.coordsize=u+n+u,c.coordorigin=b.coordorigin;var d=new D(c,b),e={fill:\"none\",stroke:\"#000\"};a&&(e.path=a),d.type=\"path\",d.path=[],d.Path=o,B(d,e),b.canvas.appendChild(c);var f=F(\"skew\");f.on=!0,c.appendChild(f),d.skew=f,d.transform(o);return d},a._engine.rect=function(b,c,d,e,f,g){var h=a._rectPath(c,d,e,f,g),i=b.path(h),j=i.attrs;i.X=j.x=c,i.Y=j.y=d,i.W=j.width=e,i.H=j.height=f,j.r=g,j.path=h,i.type=\"rect\";return i},a._engine.ellipse=function(a,b,c,d,e){var f=a.path(),g=f.attrs;f.X=b-d,f.Y=c-e,f.W=d*2,f.H=e*2,f.type=\"ellipse\",B(f,{cx:b,cy:c,rx:d,ry:e});return f},a._engine.circle=function(a,b,c,d){var e=a.path(),f=e.attrs;e.X=b-d,e.Y=c-d,e.W=e.H=d*2,e.type=\"circle\",B(e,{cx:b,cy:c,r:d});return e},a._engine.image=function(b,c,d,e,f,g){var h=a._rectPath(d,e,f,g),i=b.path(h).attr({stroke:\"none\"}),k=i.attrs,l=i.node,m=l.getElementsByTagName(j)[0];k.src=c,i.X=k.x=d,i.Y=k.y=e,i.W=k.width=f,i.H=k.height=g,k.path=h,i.type=\"image\",m.parentNode==l&&l.removeChild(m),m.rotate=!0,m.src=c,m.type=\"tile\",i._.fillpos=[d,e],i._.fillsize=[f,g],l.appendChild(m),z(i,1,1,0,0,0);return i},a._engine.text=function(b,d,e,g){var h=F(\"shape\"),i=F(\"path\"),j=F(\"textpath\");d=d||0,e=e||0,g=g||\"\",i.v=a.format(\"m{0},{1}l{2},{1}\",f(d*u),f(e*u),f(d*u)+1),i.textpathok=!0,j.string=c(g),j.on=!0,h.style.cssText=t,h.coordsize=u+n+u,h.coordorigin=\"0 0\";var k=new D(h,b),l={fill:\"#000\",stroke:\"none\",font:a._availableAttrs.font,text:g};k.shape=h,k.path=i,k.textpath=j,k.type=\"text\",k.attrs.text=c(g),k.attrs.x=d,k.attrs.y=e,k.attrs.w=1,k.attrs.h=1,B(k,l),h.appendChild(j),h.appendChild(i),b.canvas.appendChild(h);var m=F(\"skew\");m.on=!0,h.appendChild(m),k.skew=m,k.transform(o);return k},a._engine.setSize=function(b,c){var d=this.canvas.style;this.width=b,this.height=c,b==+b&&(b+=\"px\"),c==+c&&(c+=\"px\"),d.width=b,d.height=c,d.clip=\"rect(0 \"+b+\" \"+c+\" 0)\",this._viewBox&&a._engine.setViewBox.apply(this,this._viewBox);return this},a._engine.setViewBox=function(b,c,d,e,f){a.eve(\"raphael.setViewBox\",this,this._viewBox,[b,c,d,e,f]);var h=this.width,i=this.height,j=1/g(d/h,e/i),k,l;f&&(k=i/e,l=h/d,d*k<h&&(b-=(h-d*k)/2/k),e*l<i&&(c-=(i-e*l)/2/l)),this._viewBox=[b,c,d,e,!!f],this._viewBoxShift={dx:-b,dy:-c,scale:j},this.forEach(function(a){a.transform(\"...\")});return this};var F;a._engine.initWin=function(a){var b=a.document;b.createStyleSheet().addRule(\".rvml\",\"behavior:url(#default#VML)\");try{!b.namespaces.rvml&&b.namespaces.add(\"rvml\",\"urn:schemas-microsoft-com:vml\"),F=function(a){return b.createElement(\"<rvml:\"+a+' class=\"rvml\">')}}catch(c){F=function(a){return b.createElement(\"<\"+a+' xmlns=\"urn:schemas-microsoft.com:vml\" class=\"rvml\">')}}},a._engine.initWin(a._g.win),a._engine.create=function(){var b=a._getContainer.apply(0,arguments),c=b.container,d=b.height,e,f=b.width,g=b.x,h=b.y;if(!c)throw new Error(\"VML container not found.\");var i=new a._Paper,j=i.canvas=a._g.doc.createElement(\"div\"),k=j.style;g=g||0,h=h||0,f=f||512,d=d||342,i.width=f,i.height=d,f==+f&&(f+=\"px\"),d==+d&&(d+=\"px\"),i.coordsize=u*1e3+n+u*1e3,i.coordorigin=\"0 0\",i.span=a._g.doc.createElement(\"span\"),i.span.style.cssText=\"position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;\",j.appendChild(i.span),k.cssText=a.format(\"top:0;left:0;width:{0};height:{1};display:inline-block;position:relative;clip:rect(0 {0} {1} 0);overflow:hidden\",f,d),c==1?(a._g.doc.body.appendChild(j),k.left=g+\"px\",k.top=h+\"px\",k.position=\"absolute\"):c.firstChild?c.insertBefore(j,c.firstChild):c.appendChild(j),i.renderfix=function(){};return i},a.prototype.clear=function(){a.eve(\"raphael.clear\",this),this.canvas.innerHTML=o,this.span=a._g.doc.createElement(\"span\"),this.span.style.cssText=\"position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;\",this.canvas.appendChild(this.span),this.bottom=this.top=null},a.prototype.remove=function(){a.eve(\"raphael.remove\",this),this.canvas.parentNode.removeChild(this.canvas);for(var b in this)this[b]=typeof this[b]==\"function\"?a._removedFactory(b):null;return!0};var G=a.st;for(var H in E)E[b](H)&&!G[b](H)&&(G[H]=function(a){return function(){var b=arguments;return this.forEach(function(c){c[a].apply(c,b)})}}(H))}(window.Raphael)\n'''\n\nbackground_jpg = '\\xff\\xd8\\xff\\xe0\\x00\\x10JFIF\\x00\\x01\\x02\\x00\\x00d\\x00d\\x00\\x00\\xff\\xec\\x00\\x11Ducky\\x00\\x01\\x00\\x04\\x00\\x00\\x00d\\x00\\x00\\xff\\xee\\x00\\x0eAdobe\\x00d\\xc0\\x00\\x00\\x00\\x01\\xff\\xdb\\x00\\x84\\x00\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x02\\x02\\x02\\x02\\x02\\x02\\x02\\x02\\x02\\x02\\x02\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x02\\x01\\x01\\x02\\x02\\x02\\x01\\x02\\x02\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\xff\\xc0\\x00\\x11\\x08\\x03\\x00\\x00\\n\\x03\\x01\\x11\\x00\\x02\\x11\\x01\\x03\\x11\\x01\\xff\\xc4\\x00k\\x00\\x01\\x01\\x01\\x01\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x03\\x02\\x01\\x04\\t\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x02\\x03\\x06\\x07\\x10\\x01\\x00\\x02\\x01\\x04\\x01\\x05\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x12Q\\xf0\\x11a\\xa1q\\x91\\xd1\\xe1\\x02\\x13\\x81b\\x11\\x01\\x01\\x01\\x01\\x00\\x03\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x11\\x01\\x12!Qa\\x02\"\\xff\\xda\\x00\\x0c\\x03\\x01\\x00\\x02\\x11\\x03\\x11\\x00?\\x00\\xf9\\xc6\\xf7\\x0f\\x9e\\x80\\x00\\x0e\\xb5\\xc8\\x1c\\x8a\\x8e`\\x00\\x00\\x005\\xb15\\xa9\\x86\\xc4\\xd2c\\xad(\\x00\\x00\\xe8\\xb3@\\x9a\\xady\\xe9nz^\\x8a\\xf3\\xd1s\\xd1\\xd3H\\xc8\\x00\\x00\\xad</\\x86\\xae\\x14\\xf0x.6\\x8c\\x80\\x00\\n\\xd25\\x0b\\xe1\\xab\\x9e\\x8aF\\xa0\\xf0\\\\\\xf4\\xda2\\x03\\xa2\\xcd\\x02j\\xd5\\x8c-\\xd2\\xe9X\\xc1t\\xba\\xea \\x0e\\xed8\\x9fF\\xa7\\xd2\\xe1\\xb4\\xe2}\\t\\xf4\\xb8\\xa8\\xe6\\x00\\x006\\xd3\\xa0\\x00\\x00\\xa5\\'[7\\xcf\\xd5\\xf0Ru\\xb1\\xcf\\xd3\\xc2\\xaa\\xc8\\x0e\\xed+5f\\x9bI4\\x9a\\xb6\\xd1\\x88\\x0b\\xa6\\xd1\\x88\\x0b\\xae\\xa2\\x00\\xb5c\\x95\\xabt\\xacrR\\xebH\\x80)O\\x1d\\xaf\\x85\\xf0S\\xc7g\\x83\\xc2\\x88\\x805Yjb\\\\+$\\xc2\\xe2\\x83\\x00;Y\\xd6\\xe4XVu\\xb9\\x08\\xb8\\x80;\\xb4\\xaf?\\xa5\\x9am\\'?\\xa2k\\xd0\\xda\\x00m!4\\xdaBj\\xfbF .\\x9bF .\\xbaM@\\x9a-X\\xc1un\\x95\\x8c\\x17K\\xad\\x00\\x0bV\\x16\\xe9J\\xc1t\\xad \\x02\\xb4\\x82\\x85 \\xa3`\\x02\\xbf\\x9f=|\\x9dg\\xa7>\\xcf\\xcf\\x9e\\xbeN\\xb3\\xd1\\xda\\xac\\xb9\\x80\\xa55\\xa8_\\x0b\\xe0\\xa6\\xb5\\x07\\x83\\xc2\\x88\\x80)\\xf9\\xf8u\\x9f\\x9fA\\xf9\\xf8\\'\\xe7\\xd0\\xaa\\x005Ik\\xc0RO\\x02\\xcc\\x80;Y\\xc4\\xb53\\xd8Vq$\\xcfb\\xec\\x80\\x0b5\\x02h\\xbe\\xd1\\x88\\x16\\xe9\\xb4b\\x02\\xeb\\xa4\\xd4\\t\\xa3\\xd1O\\xae;\\x9ft\\xeb\\\\\\xba\\xfd\\x14\\xfa\\xe3\\xb9\\xf7:\\xd3\\xaf\\xd3H\\xc8\\n\\xd22\\xb7\\xe1\\xe0\\xa4d\\xbf\\x0f\\r\\xa0\\x03t\\x9cw\\x0e\\x9c\\xfe~\\x85\\'\\x1d\\xc1\\xcf\\xe7\\xe8\\xb0\\x00,\\xd4\\t\\xa2\\xfbF#\\xd0\\xba\\x1bF#\\xd0\\xba:\\x8a\\x02\\x94\\x9c\\xc3W\\x02\\x93\\x98.\\n2\\x005\\xce\\xa0s\\xa2\\xfbF!\\x95\\xbam\\x18\\x80\\xba\\xe8\\x00\\xd5\\'\\x1d\\xc7\\xbb_\\xca\\x14\\x9cw\\x1e\\xe7\\xf2,\\xca\\x80\\x00\\x0b\\xfe_\\xeb\\xaf\\x95\\xef\\xe34\\xfc\\xbf\\xd7_\\'\\x7f\\n\\xb3\\x9b \\x0b7\\xd6\\x817\\xd6\\x8a\\xd3\\x9e\\xbe]zB\\x9c\\xf5\\xf2t(\\xca\\x80\\x00\\rW\\xed\\x8e\\xe1\\xbb\\x88W\\xed\\x8e\\xe0\\xb8,\\xc2\\x80\\x00\\x03\\\\\\xa0r+H\\xe7_\\xc3\\xad\\nG:\\xfe\\x1dh\\xdb*\\x00\\x00\\rs\\xa8\\x1c\\xe8\\xdd\\'\\x85\\xeb\\x02\\x93\\xc1\\xd6\\n\\xb0\\xa0?\\xff\\xd9'\n\n"
  },
  {
    "path": "tickeys/kivy/modules/inspector.py",
    "content": "'''\nInspector\n=========\n\n.. versionadded:: 1.0.9\n\n.. warning::\n\n    This module is highly experimental, use it with care.\n\nThe Inspector is a tool for finding a widget in the widget tree by clicking or\ntapping on it.\nSome keyboard shortcuts are activated:\n\n    * \"Ctrl + e\": activate / deactivate the inspector view\n    * \"Escape\": cancel widget lookup first, then hide the inspector view\n\nAvailable inspector interactions:\n\n    * tap once on a widget to select it without leaving inspect mode\n    * double tap on a widget to select and leave inspect mode (then you can\n      manipulate the widget again)\n\nSome properties can be edited live. However, due to the delayed usage of\nsome properties, it might crash if you don't handle all the cases.\n\nUsage\n-----\n\nFor normal module usage, please see the :mod:`~kivy.modules` documentation.\n\nThe Inspector, however, can also be imported and used just like a normal\npython module. This has the added advantage of being able to activate and\ndeactivate the module programmatically::\n\n    from kivy.core.window import Window\n    from kivy.app import App\n    from kivy.uix.button import Button\n    from kivy.modules import inspector\n\n    class Demo(App):\n        def build(self):\n            button = Button(text=\"Test\")\n            inspector.create_inspector(Window, button)\n            return button\n\n    Demo().run()\n\nTo remove the Inspector, you can do the following::\n\n    inspector.stop(Window, button)\n\n'''\n__all__ = ('start', 'stop', 'create_inspector')\n\nimport kivy\nkivy.require('1.0.9')\n\nimport weakref\nfrom kivy.animation import Animation\nfrom kivy.logger import Logger\nfrom kivy.uix.widget import Widget\nfrom kivy.uix.button import Button\nfrom kivy.uix.label import Label\nfrom kivy.uix.togglebutton import ToggleButton\nfrom kivy.uix.textinput import TextInput\nfrom kivy.uix.image import Image\nfrom kivy.uix.treeview import TreeViewNode\nfrom kivy.uix.gridlayout import GridLayout\nfrom kivy.uix.floatlayout import FloatLayout\nfrom kivy.uix.boxlayout import BoxLayout\nfrom kivy.uix.modalview import ModalView\nfrom kivy.graphics import Color, Rectangle, PushMatrix, PopMatrix, \\\n    Translate, Rotate, Scale\nfrom kivy.properties import ObjectProperty, BooleanProperty, ListProperty, \\\n    NumericProperty, StringProperty, OptionProperty, \\\n    ReferenceListProperty, AliasProperty, VariableListProperty\nfrom kivy.graphics.texture import Texture\nfrom kivy.clock import Clock\nfrom functools import partial\nfrom itertools import chain\nfrom kivy.lang import Builder\nfrom kivy.vector import Vector\n\nBuilder.load_string('''\n<Inspector>:\n    layout: layout\n    treeview: treeview\n    content: content\n    BoxLayout:\n        orientation: 'vertical'\n        id: layout\n        size_hint_y: None\n        height: 250\n        padding: 5\n        spacing: 5\n        top: 0\n\n        canvas:\n            Color:\n                rgb: .4, .4, .4\n            Rectangle:\n                pos: self.x, self.top\n                size: self.width, 1\n            Color:\n                rgba: .185, .18, .18, .95\n            Rectangle:\n                pos: self.pos\n                size: self.size\n\n        # Top Bar\n        BoxLayout:\n            size_hint_y: None\n            height: 50\n            spacing: 5\n            Button:\n                text: 'Move to Top'\n                on_release: root.toggle_position(args[0])\n                size_hint_x: None\n                width: 120\n\n            ToggleButton:\n                text: 'Inspect'\n                on_state: root.inspect_enabled = args[1] == 'down'\n                size_hint_x: None\n                state: 'down' if root.inspect_enabled else 'normal'\n                width: 80\n\n            Button:\n                text: 'Parent'\n                on_release:\n                    root.highlight_widget(root.widget.parent) if root.widget \\\n                            else None\n                size_hint_x: None\n                width: 80\n\n            Button:\n                text: '%r' % root.widget\n                on_release: root.show_widget_info()\n\n            Button:\n                text: 'X'\n                size_hint_x: None\n                width: 50\n                on_release: root.activated = False\n\n        # Bottom Bar\n        BoxLayout:\n            ScrollView:\n                scroll_type: ['bars', 'content']\n                bar_width: 10\n                TreeView:\n                    id: treeview\n                    size_hint_y: None\n                    hide_root: True\n                    height: self.minimum_height\n\n            ScrollView:\n                id: content\n\n<TreeViewProperty>:\n    height: max(lkey.texture_size[1], ltext.texture_size[1])\n    Label:\n        id: lkey\n        text: root.key\n        text_size: (self.width, None)\n        width: 150\n        size_hint_x: None\n    Label:\n        id: ltext\n        text: [repr(getattr(root.widget, root.key, '')), root.refresh][0]\\\n                if root.widget else ''\n        text_size: (self.width, None)\n''')\n\n\nclass TreeViewProperty(BoxLayout, TreeViewNode):\n\n    widget_ref = ObjectProperty(None, allownone=True)\n\n    def _get_widget(self):\n        wr = self.widget_ref\n        if wr is None:\n            return None\n        wr = wr()\n        if wr is None:\n            self.widget_ref = None\n            return None\n        return wr\n    widget = AliasProperty(_get_widget, None, bind=('widget_ref', ))\n\n    key = ObjectProperty(None, allownone=True)\n\n    inspector = ObjectProperty(None)\n\n    refresh = BooleanProperty(False)\n\n\nclass Inspector(FloatLayout):\n\n    widget = ObjectProperty(None, allownone=True)\n\n    layout = ObjectProperty(None)\n\n    treeview = ObjectProperty(None)\n\n    inspect_enabled = BooleanProperty(False)\n\n    activated = BooleanProperty(False)\n\n    widget_info = BooleanProperty(False)\n\n    content = ObjectProperty(None)\n\n    at_bottom = BooleanProperty(True)\n\n    def __init__(self, **kwargs):\n        super(Inspector, self).__init__(**kwargs)\n        self.avoid_bring_to_top = False\n        self.win = kwargs.get('win')\n        with self.canvas.before:\n            self.gcolor = Color(1, 0, 0, .25)\n            PushMatrix()\n            self.gtranslate = Translate(0, 0, 0)\n            self.grotate = Rotate(0, 0, 0, 1)\n            self.gscale = Scale(1.)\n            self.grect = Rectangle(size=(0, 0))\n            PopMatrix()\n        Clock.schedule_interval(self.update_widget_graphics, 0)\n\n    def on_touch_down(self, touch):\n        ret = super(Inspector, self).on_touch_down(touch)\n        if (('button' not in touch.profile or touch.button == 'left')\n                and not ret and self.inspect_enabled):\n            self.highlight_at(*touch.pos)\n            if touch.is_double_tap:\n                self.inspect_enabled = False\n                self.show_widget_info()\n            ret = True\n        return ret\n\n    def on_touch_move(self, touch):\n        ret = super(Inspector, self).on_touch_move(touch)\n        if not ret and self.inspect_enabled:\n            self.highlight_at(*touch.pos)\n            ret = True\n        return ret\n\n    def on_touch_up(self, touch):\n        ret = super(Inspector, self).on_touch_up(touch)\n        if not ret and self.inspect_enabled:\n            ret = True\n        return ret\n\n    def on_window_children(self, win, children):\n        if self.avoid_bring_to_top:\n            return\n        self.avoid_bring_to_top = True\n        win.remove_widget(self)\n        win.add_widget(self)\n        self.avoid_bring_to_top = False\n\n    def highlight_at(self, x, y):\n        widget = None\n        # reverse the loop - look at children on top first and\n        # modalviews before others\n        win_children = self.win.children\n        children = chain(\n            (c for c in reversed(win_children) if isinstance(c, ModalView)),\n            (c for c in reversed(win_children) if not isinstance(c, ModalView))\n        )\n        for child in children:\n            if child is self:\n                continue\n            widget = self.pick(child, x, y)\n            if widget:\n                break\n        self.highlight_widget(widget)\n\n    def highlight_widget(self, widget, info=True, *largs):\n        # no widget to highlight, reduce rectangle to 0, 0\n        self.widget = widget\n        if not widget:\n            self.grect.size = 0, 0\n        if self.widget_info and info:\n            self.show_widget_info()\n\n    def update_widget_graphics(self, *l):\n        if not self.activated:\n            return\n        if self.widget is None:\n            self.grect.size = 0, 0\n            return\n        gr = self.grect\n        widget = self.widget\n\n        # determine rotation\n        a = Vector(1, 0)\n        if widget is self.win:\n            b = Vector(widget.to_window(0, 0))\n            c = Vector(widget.to_window(1, 0))\n        else:\n            b = Vector(widget.to_window(*widget.to_parent(0, 0)))\n            c = Vector(widget.to_window(*widget.to_parent(1, 0))) - b\n        angle = -a.angle(c)\n\n        # determine scale\n        scale = c.length()\n\n        # apply transform\n        gr.size = widget.size\n        if widget is self.win:\n            self.gtranslate.xy = Vector(widget.to_window(0, 0))\n        else:\n            self.gtranslate.xy = Vector(widget.to_window(*widget.pos))\n        self.grotate.angle = angle\n        # fix warning about scale property deprecation\n        self.gscale.xyz = (scale,) * 3\n\n    def toggle_position(self, button):\n        to_bottom = button.text == 'Move to Bottom'\n\n        if to_bottom:\n            button.text = 'Move to Top'\n            if self.widget_info:\n                Animation(top=250, t='out_quad', d=.3).start(self.layout)\n            else:\n                Animation(top=60, t='out_quad', d=.3).start(self.layout)\n\n            bottom_bar = self.layout.children[1]\n            self.layout.remove_widget(bottom_bar)\n            self.layout.add_widget(bottom_bar)\n        else:\n            button.text = 'Move to Bottom'\n            if self.widget_info:\n                Animation(top=self.height, t='out_quad', d=.3).start(\n                    self.layout)\n            else:\n                Animation(y=self.height - 60, t='out_quad', d=.3).start(\n                    self.layout)\n\n            bottom_bar = self.layout.children[1]\n            self.layout.remove_widget(bottom_bar)\n            self.layout.add_widget(bottom_bar)\n        self.at_bottom = to_bottom\n\n    def pick(self, widget, x, y):\n        ret = None\n        # try to filter widgets that are not visible (invalid inspect target)\n        if (hasattr(widget, 'visible') and not widget.visible):\n            return ret\n        if widget.collide_point(x, y):\n            ret = widget\n            x2, y2 = widget.to_local(x, y)\n            # reverse the loop - look at children on top first\n            for child in reversed(widget.children):\n                ret = self.pick(child, x2, y2) or ret\n        return ret\n\n    def on_activated(self, instance, activated):\n        if not activated:\n            self.grect.size = 0, 0\n            if self.at_bottom:\n                anim = Animation(top=0, t='out_quad', d=.3)\n            else:\n                anim = Animation(y=self.height, t='out_quad', d=.3)\n            anim.bind(on_complete=self.animation_close)\n            anim.start(self.layout)\n            self.widget = None\n            self.widget_info = False\n        else:\n            self.win.add_widget(self)\n            Logger.info('Inspector: inspector activated')\n            if self.at_bottom:\n                Animation(top=60, t='out_quad', d=.3).start(self.layout)\n            else:\n                Animation(y=self.height - 60, t='out_quad', d=.3).start(\n                    self.layout)\n\n    def animation_close(self, instance, value):\n        if self.activated is False:\n            self.inspect_enabled = False\n            self.win.remove_widget(self)\n            self.content.clear_widgets()\n            treeview = self.treeview\n            for node in list(treeview.iterate_all_nodes())[:]:\n                node.widget_ref = None\n                treeview.remove_node(node)\n            Logger.info('Inspector: inspector deactivated')\n\n    def show_widget_info(self):\n        self.content.clear_widgets()\n        widget = self.widget\n        treeview = self.treeview\n        for node in list(treeview.iterate_all_nodes())[:]:\n            node.widget_ref = None\n            treeview.remove_node(node)\n        if not widget:\n            if self.at_bottom:\n                Animation(top=60, t='out_quad', d=.3).start(self.layout)\n            else:\n                Animation(y=self.height - 60, t='out_quad', d=.3).start(\n                    self.layout)\n            self.widget_info = False\n            return\n        self.widget_info = True\n        if self.at_bottom:\n            Animation(top=250, t='out_quad', d=.3).start(self.layout)\n        else:\n            Animation(top=self.height, t='out_quad', d=.3).start(self.layout)\n        for node in list(treeview.iterate_all_nodes())[:]:\n            treeview.remove_node(node)\n\n        keys = list(widget.properties().keys())\n        keys.sort()\n        node = None\n        wk_widget = weakref.ref(widget)\n        for key in keys:\n            text = '%s' % key\n            node = TreeViewProperty(text=text, key=key, widget_ref=wk_widget)\n            node.bind(is_selected=self.show_property)\n            try:\n                widget.bind(**{key: partial(\n                    self.update_node_content, weakref.ref(node))})\n            except:\n                pass\n            treeview.add_node(node)\n\n    def update_node_content(self, node, *l):\n        node = node()\n        if node is None:\n            return\n        node.refresh = True\n        node.refresh = False\n\n    def keyboard_shortcut(self, win, scancode, *largs):\n        modifiers = largs[-1]\n        if scancode == 101 and modifiers == ['ctrl']:\n            self.activated = not self.activated\n            if self.activated:\n                self.inspect_enabled = True\n            return True\n        elif scancode == 27:\n            if self.inspect_enabled:\n                self.inspect_enabled = False\n                return True\n            if self.activated:\n                self.activated = False\n                return True\n\n    def show_property(self, instance, value, key=None, index=-1, *l):\n        # normal call: (tree node, focus, )\n        # nested call: (widget, prop value, prop key, index in dict/list)\n        if value is False:\n            return\n\n        content = None\n        if key is None:\n            # normal call\n            nested = False\n            widget = instance.widget\n            key = instance.key\n            prop = widget.property(key)\n            value = getattr(widget, key)\n        else:\n            # nested call, we might edit subvalue\n            nested = True\n            widget = instance\n            prop = None\n\n        dtype = None\n\n        if isinstance(prop, AliasProperty) or nested:\n            # trying to resolve type dynamicly\n            if type(value) in (str, str):\n                dtype = 'string'\n            elif type(value) in (int, float):\n                dtype = 'numeric'\n            elif type(value) in (tuple, list):\n                dtype = 'list'\n\n        if isinstance(prop, NumericProperty) or dtype == 'numeric':\n            content = TextInput(text=str(value) or '', multiline=False)\n            content.bind(text=partial(\n                self.save_property_numeric, widget, key, index))\n        elif isinstance(prop, StringProperty) or dtype == 'string':\n            content = TextInput(text=value or '', multiline=True)\n            content.bind(text=partial(\n                self.save_property_text, widget, key, index))\n        elif (isinstance(prop, ListProperty) or\n              isinstance(prop, ReferenceListProperty) or\n              isinstance(prop, VariableListProperty) or\n              dtype == 'list'):\n            content = GridLayout(cols=1, size_hint_y=None)\n            content.bind(minimum_height=content.setter('height'))\n            for i, item in enumerate(value):\n                button = Button(text=repr(item), size_hint_y=None, height=44)\n                if isinstance(item, Widget):\n                    button.bind(on_release=partial(self.highlight_widget, item,\n                                                   False))\n                else:\n                    button.bind(on_release=partial(self.show_property, widget,\n                                                   item, key, i))\n                content.add_widget(button)\n        elif isinstance(prop, OptionProperty):\n            content = GridLayout(cols=1, size_hint_y=None)\n            content.bind(minimum_height=content.setter('height'))\n            for option in prop.options:\n                button = ToggleButton(\n                    text=option,\n                    state='down' if option == value else 'normal',\n                    group=repr(content.uid), size_hint_y=None,\n                    height=44)\n                button.bind(on_press=partial(\n                    self.save_property_option, widget, key))\n                content.add_widget(button)\n        elif isinstance(prop, ObjectProperty):\n            if isinstance(value, Widget):\n                content = Button(text=repr(value))\n                content.bind(on_release=partial(self.highlight_widget, value))\n            elif isinstance(value, Texture):\n                content = Image(texture=value)\n            else:\n                content = Label(text=repr(value))\n\n        elif isinstance(prop, BooleanProperty):\n            state = 'down' if value else 'normal'\n            content = ToggleButton(text=key, state=state)\n            content.bind(on_release=partial(self.save_property_boolean, widget,\n                                            key, index))\n\n        self.content.clear_widgets()\n        if content:\n            self.content.add_widget(content)\n\n    def save_property_numeric(self, widget, key, index, instance, value):\n        try:\n            if index >= 0:\n                getattr(widget, key)[index] = float(instance.text)\n            else:\n                setattr(widget, key, float(instance.text))\n        except:\n            pass\n\n    def save_property_text(self, widget, key, index, instance, value):\n        try:\n            if index >= 0:\n                getattr(widget, key)[index] = instance.text\n            else:\n                setattr(widget, key, instance.text)\n        except:\n            pass\n\n    def save_property_boolean(self, widget, key, index, instance, ):\n        try:\n            value = instance.state == 'down'\n            if index >= 0:\n                getattr(widget, key)[index] = value\n            else:\n                setattr(widget, key, value)\n        except:\n            pass\n\n    def save_property_option(self, widget, key, instance, *l):\n        try:\n            setattr(widget, key, instance.text)\n        except:\n            pass\n\n\ndef create_inspector(win, ctx, *l):\n    '''Create an Inspector instance attached to the *ctx* and bound to the\n    Windows :meth:`~kivy.core.window.WindowBase.on_keyboard` event for capturing\n    the keyboard shortcut.\n\n        :Parameters:\n            `win`: A :class:`Window <kivy.core.window.WindowBase>`\n                The application Window to bind to.\n            `ctx`: A :class:`~kivy.uix.widget.Widget` or subclass\n                The Widget to be inspected.\n\n    '''\n    # Dunno why, but if we are creating inspector within the start(), no lang\n    # rules are applied.\n    ctx.inspector = Inspector(win=win)\n    win.bind(children=ctx.inspector.on_window_children,\n             on_keyboard=ctx.inspector.keyboard_shortcut)\n\n\ndef start(win, ctx):\n    Clock.schedule_once(partial(create_inspector, win, ctx))\n\n\ndef stop(win, ctx):\n    '''Stop and unload any active Inspectors for the given *ctx*.'''\n    if hasattr(ctx, 'inspector'):\n        win.unbind(children=ctx.inspector.on_window_children,\n                   on_keyboard=ctx.inspector.keyboard_shortcut)\n        win.remove_widget(ctx.inspector)\n        del ctx.inspector\n"
  },
  {
    "path": "tickeys/kivy/modules/keybinding.py",
    "content": "'''Keybinding\n==========\n\nThis module forces the mapping of some keys to functions:\n\n* F11: Rotate the Window through 0, 90, 180 and 270 degrees\n* Shift + F11: Switches between portrait and landscape on desktops\n* F12: Take a screenshot\n\nNote: this does't work if the application requests the keyboard beforehand.\n\nUsage\n-----\n\nFor normal module usage, please see the :mod:`~kivy.modules` documentation.\n\nThe Keybinding module, however, can also be imported and used just\nlike a normal python module. This has the added advantage of being\nable to activate and deactivate the module programmatically::\n\n    from kivy.app import App\n    from kivy.uix.button import Button\n    from kivy.modules import keybinding\n    from kivy.core.window import Window\n\n    class Demo(App):\n\n        def build(self):\n            button = Button(text=\"Hello\")\n            keybinding.start(Window, button)\n            return button\n\n    Demo().run()\n\nTo remove the Keybinding, you can do the following::\n\n    Keybinding.stop(Window, button)\n\n'''\n\nfrom kivy.utils import platform\n\n__all__ = ('start', 'stop')\n\n\ndef _on_keyboard_handler(instance, key, scancode, codepoint, modifiers):\n    if key == 293 and modifiers == []:  # F12\n        instance.screenshot()\n    elif key == 292 and modifiers == []:  # F11\n        instance.rotation += 90\n    elif key == 292 and modifiers == ['shift']:  # Shift + F11\n        if platform in ('win', 'linux', 'macosx'):\n            instance.rotation = 0\n            w, h = instance.size\n            w, h = h, w\n            instance.size = (w, h)\n\n\ndef start(win, ctx):\n    win.bind(on_keyboard=_on_keyboard_handler)\n\n\ndef stop(win, ctx):\n    win.unbind(on_keyboard=_on_keyboard_handler)\n"
  },
  {
    "path": "tickeys/kivy/modules/monitor.py",
    "content": "'''\nMonitor module\n==============\n\nThe Monitor module is a toolbar that shows the activity of your current\napplication :\n\n* FPS\n* Graph of input events\n\nUsage\n-----\n\nFor normal module usage, please see the :mod:`~kivy.modules` documentation.\n\n'''\n\n__all__ = ('start', 'stop')\n\nfrom kivy.uix.label import Label\nfrom kivy.graphics import Rectangle, Color\nfrom kivy.clock import Clock\nfrom functools import partial\n\n_statsinput = 0\n_maxinput = -1\n\n\ndef update_fps(ctx, *largs):\n    ctx.label.text = 'FPS: %f' % Clock.get_fps()\n    ctx.rectangle.texture = ctx.label.texture\n    ctx.rectangle.size = ctx.label.texture_size\n\n\ndef update_stats(ctx, *largs):\n    global _statsinput\n    ctx.stats = ctx.stats[1:] + [_statsinput]\n    _statsinput = 0\n    m = max(1., _maxinput)\n    for index, x in enumerate(ctx.stats):\n        ctx.statsr[index].size = (4, ctx.stats[index] / m * 20)\n\n\nclass StatsInput(object):\n\n    def process(self, events):\n        global _statsinput, _maxinput\n        _statsinput += len(events)\n        if _statsinput > _maxinput:\n            _maxinput = float(_statsinput)\n        return events\n\n\ndef start(win, ctx):\n    # late import to avoid breaking module loading\n    from kivy.input.postproc import kivy_postproc_modules\n    kivy_postproc_modules['fps'] = StatsInput()\n    global _ctx\n    ctx.label = Label(text='FPS: 0.0')\n    ctx.inputstats = 0\n    ctx.stats = []\n    ctx.statsr = []\n    with win.canvas.after:\n        ctx.color = Color(1, 0, 0, .5)\n        ctx.rectangle = Rectangle(pos=(0, win.height - 25),\n                                  size=(win.width, 25))\n        ctx.color = Color(1, 1, 1)\n        ctx.rectangle = Rectangle(pos=(5, win.height - 20))\n        ctx.color = Color(1, 1, 1, .5)\n        for x in range(64):\n            ctx.stats.append(0)\n            ctx.statsr.append(\n                Rectangle(pos=(win.width - 64 * 4 + x * 4, win.height - 25),\n                          size=(4, 0)))\n    Clock.schedule_interval(partial(update_fps, ctx), .5)\n    Clock.schedule_interval(partial(update_stats, ctx), 1 / 60.)\n\n\ndef stop(win, ctx):\n    win.canvas.remove(ctx.label)\n"
  },
  {
    "path": "tickeys/kivy/modules/recorder.py",
    "content": "'''\nRecorder module\n===============\n\n.. versionadded:: 1.1.0\n\nCreate an instance of :class:`~kivy.input.recorder.Recorder`, attach to the\nclass, and bind some keys to record / play sequences:\n\n    - F6: play the last record in a loop\n    - F7: read the latest recording\n    - F8: record input events\n\nConfiguration\n-------------\n\n:Parameters:\n    `attrs`: str, defaults to\n    :attr:`~kivy.input.recorder.Recorder.record_attrs` value.\n\n        Attributes to record from the motion event\n\n    `profile_mask`: str, defaults to\n    :attr:`~kivy.input.recorder.Recorder.record_profile_mask` value.\n\n        Mask for motion event profile. Used to filter which profile will appear\n        in the fake motion event when replayed.\n\n    `filename`: str, defaults to 'recorder.kvi'\n\n        Name of the file to record / play with\n\nUsage\n-----\n\nFor normal module usage, please see the :mod:`~kivy.modules` documentation.\n\n'''\n\n__all__ = ('start', 'stop')\n\nfrom kivy.logger import Logger\nfrom functools import partial\n\n\ndef replay(recorder, *args):\n    if recorder.play:\n        return\n    else:\n        recorder.play = True\n\n\ndef on_recorder_key(recorder, window, key, *largs):\n    if key == 289:  # F8\n        if recorder.play:\n            Logger.error('Recorder: Cannot start recording while playing.')\n            return\n        recorder.record = not recorder.record\n    elif key == 288:  # F7\n        if recorder.record:\n            Logger.error('Recorder: Cannot start playing while recording.')\n            return\n        recorder.play = not recorder.play\n    elif key == 287:  # F6\n        if recorder.play:\n            recorder.unbind(play=replay)\n        else:\n            recorder.bind(play=replay)\n            recorder.play = True\n\n\ndef start(win, ctx):\n    keys = {}\n\n    # attributes\n    value = ctx.config.get('attrs', None)\n    if value is not None:\n        keys['record_attrs'] = value.split(':')\n\n    # profile mask\n    value = ctx.config.get('profile_mask', None)\n    if value is not None:\n        keys['record_profile_mask'] = value.split(':')\n\n    # filename\n    value = ctx.config.get('filename', None)\n    if value is not None:\n        keys['filename'] = value\n\n    from kivy.input.recorder import Recorder\n    ctx.recorder = Recorder(window=win, **keys)\n    win.bind(on_key_down=partial(on_recorder_key, ctx.recorder))\n\n\ndef stop(win, ctx):\n    if hasattr(ctx, 'recorder'):\n        ctx.recorder.release()\n"
  },
  {
    "path": "tickeys/kivy/modules/screen.py",
    "content": "'''Screen\n======\n\nThis module changes some environement and configuration variables\nto match the density / dpi / screensize of a specific device.\n\nTo see a list of the available screenid's, just run::\n\n    python main.py -m screen\n\nTo simulate a medium-density screen such as the Motolora Droid 2::\n\n    python main.py -m screen:droid2\n\nTo simulate a high-density screen such as HTC One X, in portrait::\n\n    python main.py -m screen:onex,portrait\n\nTo simulate the iPad 2 screen::\n\n    python main.py -m screen:ipad\n\nIf the generated window is too large, you can specify a scale::\n\n    python main.py -m screen:note2,portrait,scale=.75\n\nNote that to display your contents correctly on a scaled window you\nmust consistently use units 'dp' and 'sp' throughout your app. See\n:mod:`~kiv.metrics` for more details.\n\n'''\n\nimport sys\nfrom os import environ\nfrom kivy.config import Config\nfrom kivy.logger import Logger\n\n# taken from http://en.wikipedia.org/wiki/List_of_displays_by_pixel_density\ndevices = {\n    # device: (name, width, height, dpi, density)\n    'onex': ('HTC One X', 1280, 720, 312, 2),\n    'one': ('HTC One', 1920, 1080, 468, 3),\n    'onesv': ('HTC One SV', 800, 480, 216, 1.5),\n    's3': ('Galaxy SIII', 1280, 720, 306, 2),\n    'note2': ('Galaxy Note II', 1280, 720, 267, 2),\n    'droid2': ('Motolora Droid 2', 854, 480, 240, 1.5),\n    'xoom': ('Motolora Xoom', 1280, 800, 149, 1),\n    'ipad': ('iPad (1 and 2)', 1024, 768, 132, 1),\n    'ipad3': ('iPad 3', 2048, 1536, 264, 2),\n    'iphone4': ('iPhone 4', 960, 640, 326, 2),\n    'iphone5': ('iPhone 5', 1136, 640, 326, 2),\n    'xperiae': ('Xperia E', 480, 320, 166, 1),\n    'nexus4': ('Nexus 4', 1280, 768, 320, 2),\n    'nexus7': ('Nexus 7 (2012 version)', 1280, 800, 216, 1.325),\n    'nexus7.2': ('Nexus 7 (2013 version)', 1920, 1200, 323, 2),\n}\n\n\ndef start(win, ctx):\n    pass\n\n\ndef stop(win, ctx):\n    pass\n\n\ndef apply_device(device, scale, orientation):\n    name, width, height, dpi, density = devices[device]\n    if orientation == 'portrait':\n        width, height = height, width\n    Logger.info('Screen: Apply screen settings for {0}'.format(name))\n    Logger.info('Screen: size={0}x{1} dpi={2} density={3} '\n                'orientation={4}'.format(width, height, dpi, density,\n                                         orientation))\n    try:\n        scale = float(scale)\n    except:\n        scale = 1\n    environ['KIVY_METRICS_DENSITY'] = str(density * scale)\n    environ['KIVY_DPI'] = str(dpi * scale)\n    Config.set('graphics', 'width', str(int(width * scale)))\n    # simulate with the android bar\n    # FIXME should be configurable\n    Config.set('graphics', 'height', str(int(height * scale - 25 * density)))\n    Config.set('graphics', 'fullscreen', '0')\n    Config.set('graphics', 'show_mousecursor', '1')\n\n\ndef usage(device=None):\n    if device:\n        Logger.error('Screen: The specified device ({0}) is unknown.',\n                     device)\n    print('\\nModule usage: python main.py -m screen:deviceid[,orientation]\\n')\n    print('Available devices:\\n')\n    print('{0:12} {1:<22} {2:<8} {3:<8} {4:<5} {5:<8}'.format(\n        'Device ID', 'Name', 'Width', 'Height', 'DPI', 'Density'))\n    for device, info in devices.items():\n        print('{0:12} {1:<22} {2:<8} {3:<8} {4:<5} {5:<8}'.format(\n            device, *info))\n    print('\\n')\n    print('Simulate a medium-density screen such as Motolora Droid 2:\\n')\n    print('    python main.py -m screen:droid2\\n')\n    print('Simulate a high-density screen such as HTC One X, in portrait:\\n')\n    print('    python main.py -m screen:onex,portrait\\n')\n    print('Simulate the iPad 2 screen\\n')\n    print('    python main.py -m screen:ipad\\n')\n    print('If the generated window is too large, you can specify a scale:\\n')\n    print('    python main.py -m screen:note2,portrait,scale=.75\\n')\n    sys.exit(1)\n\n\ndef configure(ctx):\n    scale = ctx.pop('scale', None)\n    orientation = 'landscape'\n    ctx.pop('landscape', None)\n    if ctx.pop('portrait', None):\n        orientation = 'portrait'\n    if not ctx:\n        return usage(None)\n    device = list(ctx.keys())[0]\n    if device not in devices:\n        return usage('')\n    apply_device(device, scale, orientation)\n\nif __name__ == \"__main__\":\n    for n in devices.values():\n        assert n[1] > n[2]\n"
  },
  {
    "path": "tickeys/kivy/modules/touchring.py",
    "content": "'''\nTouchring\n=========\n\nShows rings around every touch on the surface / screen. You can use this module\nto check that you don't have any calibration issues with touches.\n\nConfiguration\n-------------\n\n:Parameters:\n    `image`: str, defaults to '<kivy>/data/images/ring.png'\n        Filename of the image to use.\n    `scale`: float, defaults to 1.\n        Scale of the image.\n    `alpha`: float, defaults to 1.\n        Opacity of the image.\n    `show_cursor`: boolean, defaults to False\n        .. versionadded:: 1.8.0\n    `cursor_image`: str, defaults to\n        'atlas://data/images/defaulttheme/slider_cursor' Image used to\n        represent the cursor if displayed\n        .. versionadded:: 1.8.0\n    `cursor_size`: tuple, defaults to (None, None)\n        Apparent size of the mouse cursor, if displayed, default value\n        will keep its real size.\n        .. versionadded:: 1.8.0\n    `cursor_offset`: tuple, defaults to (None, None)\n        Offset of the texture image. The default value will align the\n        top-left corner of the image to the mouse pos.\n        .. versionadded:: 1.8.0\n\nExample\n-------\n\nIn your configuration (`~/.kivy/config.ini`), you can add something like\nthis::\n\n    [modules]\n    touchring = image=mypointer.png,scale=.3,alpha=.7\n\n'''\n\n__all__ = ('start', 'stop')\n\nfrom kivy.core.image import Image\nfrom kivy.graphics import Color, Rectangle\n\npointer_image = None\npointer_scale = 1.0\npointer_alpha = 0.7\ncursor_image = ''\ncursor_offset = (0, 0)\ncursor_size = (None, None)\n\n\ndef _touch_down(win, touch):\n    ud = touch.ud\n    touch.scale_for_screen(win.width, win.height)\n    with win.canvas.after:\n        ud['tr.color'] = Color(1, 1, 1, pointer_alpha)\n        iw, ih = pointer_image.size\n        ud['tr.rect'] = Rectangle(\n            pos=(\n                touch.x - (pointer_image.width / 2. * pointer_scale),\n                touch.y - (pointer_image.height / 2. * pointer_scale)),\n            size=(iw * pointer_scale, ih * pointer_scale),\n            texture=pointer_image.texture)\n\n    if not ud.get('tr.grab', False):\n        ud['tr.grab'] = True\n        touch.grab(win)\n\n\ndef _touch_move(win, touch):\n    ud = touch.ud\n    ud['tr.rect'].pos = (\n        touch.x - (pointer_image.width / 2. * pointer_scale),\n        touch.y - (pointer_image.height / 2. * pointer_scale))\n\n\ndef _touch_up(win, touch):\n    if touch.grab_current is win:\n        ud = touch.ud\n        win.canvas.after.remove(ud['tr.color'])\n        win.canvas.after.remove(ud['tr.rect'])\n\n        if ud.get('tr.grab') is True:\n            touch.ungrab(win)\n            ud['tr.grab'] = False\n\n\ndef _mouse_move(win, pos, *args):\n    global cursor_size\n    if hasattr(win, '_cursor'):\n        c = win._cursor\n    else:\n        with win.canvas.after:\n            img = Image(cursor_image)\n            Color(1, 1, 1, 1, mode='rgba')\n            size = (\n                cursor_size[0] or img.texture.size[0],\n                cursor_size[1] or img.texture.size[1]\n            )\n            print(size)\n            win._cursor = c = Rectangle(texture=img.texture,\n                                        size=size)\n\n    c.pos = pos[0] + cursor_offset[0], pos[1] - c.size[1] + cursor_offset[1]\n\n\ndef start(win, ctx):\n    # XXX use ctx !\n    global pointer_image, pointer_scale, pointer_alpha, cursor_size,\\\n        cursor_image, cursor_offset\n    pointer_fn = ctx.config.get('image',\n                                'atlas://data/images/defaulttheme/ring')\n    pointer_scale = float(ctx.config.get('scale', 1.0))\n    pointer_alpha = float(ctx.config.get('alpha', 1.0))\n    pointer_image = Image(pointer_fn)\n    cursor_image = ctx.config.get(\n        'cursor_image',\n        'atlas://data/images/defaulttheme/slider_cursor')\n    cursor_size = ctx.config.get('cursor_size', (None, None))\n    if isinstance(cursor_size, str):\n        cursor_size = [int(x) for x in cursor_size.split('x')]\n\n    cursor_offset = ctx.config.get('cursor_offset', (0, 0))\n    if isinstance(cursor_offset, str):\n        cursor_offset = [int(x) for x in cursor_offset.split('x')]\n\n    win.bind(on_touch_down=_touch_down,\n             on_touch_move=_touch_move,\n             on_touch_up=_touch_up)\n\n    if ctx.config.get('show_cursor', False):\n        print('adding binding for mouse move')\n        win.bind(mouse_pos=_mouse_move)\n\n\ndef stop(win, ctx):\n    win.unbind(on_touch_down=_touch_down,\n               on_touch_move=_touch_move,\n               on_touch_up=_touch_up,\n               on_mouse_pos=_mouse_move)\n"
  },
  {
    "path": "tickeys/kivy/modules/webdebugger.py",
    "content": "# -*- coding: utf-8 -*-\n'''\nWeb Debugger\n============\n\n.. versionadded:: 1.2.0\n\n.. warning::\n\n    This module is highly experimental, use it with care.\n\nThis module will start a webserver and run in the background. You can\nsee how your application evolves during runtime, examine the internal\ncache etc.\n\nRun with::\n\n    python main.py -m webdebugger\n\nThen open your webbrowser on http://localhost:5000/\n\n'''\n\n__all__ = ('start', 'stop')\n\nimport os\nif 'KIVY_DOC' not in os.environ:\n    from kivy.modules._webdebugger import start, stop\nelse:\n    start = stop = lambda *x: True\n"
  },
  {
    "path": "tickeys/kivy/multistroke.py",
    "content": "'''\nMultistroke gesture recognizer\n==============================\n\n.. versionadded::\n    1.9.0\n\n.. warning::\n\n    This is experimental and subject to change as long as this warning notice\n    is present.\n\nSee :file:`kivy/examples/demo/multistroke/main.py` for a complete application\nexample.\n\nConceptual Overview\n-------------------\n\nThis module implements the Protractor gesture recognition algorithm.\n\n:class:`Recognizer` is the search/database API similar to\n:class:`~kivy.gesture.GestureDatabase`. It maintains a list of\n:class:`MultistrokeGesture` objects and allows you to search for a\nuser-input gestures among them.\n\n:class:`ProgressTracker` tracks the progress of a :meth:`Recognizer.recognize`\ncall. It can be used to interact with the running recognizer task, for example\nforcing it to stop half-way, or analyzing results as they arrive.\n\n:class:`MultistrokeGesture` represents a gesture in the gesture database\n(:attr:`Recognizer.db`). It is a container for :class:`UnistrokeTemplate`\nobjects, and implements the heap permute algorithm to automatically generate\nall possible stroke orders (if desired).\n\n:class:`UnistrokeTemplate` represents a single stroke path. It's typically\ninstantiated automatically by :class:`MultistrokeGesture`, but sometimes you\nmay need to create them manually.\n\n:class:`Candidate` represents a user-input gesture that is used to search\nthe gesture database for matches. It is normally instantiated automatically\nby calling :meth:`Recognizer.recognize`.\n\nUsage examples\n--------------\n\nSee :file:`kivy/examples/demo/multistroke/main.py` for a complete application\nexample.\n\nYou can bind to events on :class:`Recognizer` to track the state of all\ncalls to :meth:`Recognizer.recognize`. The callback function will receive an\ninstance of :class:`ProgressTracker` that can be used to analyze and control\nvarious aspects of the recognition process ::\n\n    from kivy.vector import Vector\n    from kivy.multistroke import Recognizer\n\n    gdb = Recognizer()\n\n    def search_start(gdb, pt):\n        print(\"A search is starting with %d tasks\" % (pt.tasks))\n\n    def search_stop(gdb, pt):\n        # This will call max() on the result dictonary, so it's best to store\n        # it instead of calling it 3 times consecutively\n        best = pt.best\n        print(\"Search ended (%s). Best is %s (score %f, distance %f)\" % (\n            pt.status, best['name'], best['score'], best['dist'] ))\n\n    # Bind your callbacks to track all matching operations\n    gdb.bind(on_search_start=search_start)\n    gdb.bind(on_search_complete=search_stop)\n\n    # The format below is referred to as `strokes`, a list of stroke paths.\n    # Note that each path shown here consists of two points, ie a straight\n    # line; if you plot them it looks like a T, hence the name.\n    gdb.add_gesture('T', [\n        [Vector(30, 7), Vector(103, 7)],\n        [Vector(66, 7), Vector(66, 87)]])\n\n    # Now you can search for the 'T' gesture using similar data (user input).\n    # This will trigger both of the callbacks bound above.\n    gdb.recognize([\n        [Vector(45, 8), Vector(110, 12)],\n        [Vector(88, 9), Vector(85, 95)]])\n\nOn the next :class:`~kivy.clock.Clock` tick, the matching process starts\n(and, in this case, completes).\n\nTo track individual calls to :meth:`Recognizer.recognize`, use the return\nvalue (also a :class:`ProgressTracker` instance) ::\n\n    # Same as above, but keep track of progress using returned value\n    progress = gdb.recognize([\n        [Vector(45, 8), Vector(110, 12)],\n        [Vector(88, 9), Vector(85, 95)]])\n\n    progress.bind(on_progress=my_other_callback)\n    print(progress.progress) # = 0\n\n    # [ assuming a kivy.clock.Clock.tick() here ]\n\n    print(result.progress) # = 1\n\nAlgorithm details\n-----------------\n\nFor more information about the matching algorithm, see:\n\n\"Protractor: A fast and accurate gesture recognizer\" by Yang Li\n  http://yangl.org/pdf/protractor-chi2010.pdf\n\n\"$N-Protractor\" by Lisa Anthony and Jacob O. Wobbrock\n  http://depts.washington.edu/aimgroup/proj/dollar/ndollar-protractor.pdf\n\nSome of the code is derived from the JavaScript implementation here:\n  http://depts.washington.edu/aimgroup/proj/dollar/ndollar.html\n'''\n\n__all__ = ('Recognizer', 'ProgressTracker', 'MultistrokeGesture',\n           'UnistrokeTemplate', 'Candidate')\n\nimport pickle\nimport base64\nimport zlib\nfrom re import match as re_match\nfrom collections import deque\nfrom math import sqrt, pi, radians, acos, atan, atan2, pow, floor\nfrom math import sin as math_sin, cos as math_cos\nfrom kivy.vector import Vector\nfrom kivy.clock import Clock\nfrom kivy.event import EventDispatcher\nfrom kivy.properties import ListProperty\nfrom kivy.compat import PY2\nfrom io import BytesIO\n\nif not PY2:\n    xrange = range\n\n# Default number of gesture matches per frame\n# FIXME: relevant number\nDEFAULT_GPF = 10\n\n# Algorithm data\nSQUARESIZE = 250.0\nONEDTHRESHOLD = 0.25\nORIGIN = Vector(0, 0)\n\n\nclass MultistrokeError(Exception):\n    pass\n\n\n# -----------------------------------------------------------------------------\n# Recognizer\n# -----------------------------------------------------------------------------\n\nclass Recognizer(EventDispatcher):\n    ''':class:`Recognizer` provides a gesture database with matching\n    facilities.\n\n    :Events:\n        `on_search_start`\n            Fired when a new search is started using this Recognizer.\n\n        `on_search_complete`\n            Fired when a running search ends, for whatever reason.\n            (use :data:`ProgressTracker.status` to find out)\n\n    :Properties:\n        `db`\n            A :class:`ListProperty` that contains the available\n            :class:`MultistrokeGesture` objects.\n\n            :attr:`db` is a\n            :class:`~kivy.properties.ListProperty` and defaults to []\n    '''\n\n    db = ListProperty([])\n\n    def __init__(self, **kwargs):\n        super(Recognizer, self).__init__(**kwargs)\n        self.register_event_type('on_search_start')\n        self.register_event_type('on_search_complete')\n\n    def filter(self, **kwargs):\n        ''':meth:`filter` returns a subset of objects in :attr:`self.db`,\n        according to given criteria. This is used by many other methods of\n        the :class:`Recognizer`; the arguments below can for example be\n        used when calling :meth:`Recognizer.recognize` or\n        :meth:`Recognizer.export_gesture`. You normally don't need to call\n        this directly.\n\n        :Arguments:\n\n            `name`\n                Limits the returned list to gestures where\n                :attr:`MultistrokeGesture.name` matches given regular\n                expression(s). If re.match(name, MultistrokeGesture.name)\n                tests true, the gesture is included in the returned list.\n                Can be a string or an array of strings ::\n\n                    gdb = Recognizer()\n\n                    # Will match all names that start with a captial N\n                    # (ie Next, New, N, Nebraska etc, but not \"n\" or \"next\")\n                    gdb.filter(name='N')\n\n                    # exactly 'N'\n                    gdb.filter(name='N$')\n\n                    # Nebraska, teletubbies, France, fraggle, N, n, etc\n                    gdb.filter(name=['[Nn]', '(?i)T', '(?i)F'])\n\n            `priority`\n                Limits the returned list to gestures with certain\n                :attr:`MultistrokeGesture.priority` values. If specified as an\n                integer, only gestures with a lower priority are returned. If\n                specified as a list (min/max) ::\n\n                    # Max priority 50\n                    gdb.filter(priority=50)\n\n                    # Max priority 50 (same result as above)\n                    gdb.filter(priority=[0, 50])\n\n                    # Min priority 50, max 100\n                    gdb.filter(priority=[50, 100])\n\n                When this option is used, :attr:`Recognizer.db` is automatically\n                sorted according to priority, incurring extra cost. You can use\n                `force_priority_sort` to override this behavior if your gestures\n                are already sorted according to priority.\n\n            `orientation_sensitive`\n                Limits the returned list to gestures that are\n                orientation sensitive (True), gestures that are not orientation\n                sensitive (False) or None (ignore template sensitivity, this is\n                the default).\n\n            `numstrokes`\n                Limits the returned list to gestures that have the specified\n                number of strokes (in :attr:`MultistrokeGesture.strokes`).\n                Can be a single integer or a list of integers.\n\n            `numpoints`\n                Limits the returned list to gestures that have specific\n                :attr:`MultistrokeGesture.numpoints` values. This is provided\n                for flexibility, do not use it unless you understand what it\n                does. Can be a single integer or a list of integers.\n\n            `force_priority_sort`\n                Can be used to override the default sort behavior. Normally\n                :class:`MultistrokeGesture` objects are returned in priority\n                order if the `priority` option is used. Setting this to True\n                will return gestures sorted in priority order, False will\n                return in the order gestures were added. None means decide\n                automatically (the default).\n\n                .. Note ::\n                    For improved performance, you can load your gesture\n                    database in priority order and set this to False when\n                    calling :meth:`Recognizer.recognize`\n\n            `db`\n                Can be set if you want to filter a different list of objects\n                than :attr:`Recognizer.db`. You probably don't want to do this;\n                it is used internally by :meth:`import_gesture`.\n        '''\n        have_filters = False\n\n        kwargs_get = kwargs.get\n\n        name = kwargs_get('name', None)\n        if name is not None:\n            have_filters = True\n            if not isinstance(name, list):\n                name = [name]\n\n        priority = kwargs_get('priority', None)\n        min_p, max_p = None, None\n        if priority is not None:\n            have_filters = True\n            if isinstance(priority, list):\n                min_p, max_p = priority\n            elif isinstance(priority, int):\n                min_p, max_p = None, priority\n\n        numstrokes = kwargs_get('numstrokes', None)\n        if numstrokes is not None:\n            have_filters = True\n            if not isinstance(numstrokes, list):\n                numstrokes = [numstrokes]\n\n        numpoints = kwargs_get('numpoints', None)\n        if numpoints is not None:\n            have_filters = True\n            if not isinstance(numpoints, list):\n                numpoints = [numpoints]\n\n        orientation_sens = kwargs_get('orientation_sensitive', None)\n        if orientation_sens is not None:\n            have_filters = True\n\n        # Prepare a correctly sorted tasklist\n        force_priority_sort = kwargs.get('force_priority_sort', None)\n        force_sort_on = force_priority_sort and True\n        force_sort_off = (force_priority_sort is False) and True\n\n        db = kwargs.get('db', None) or self.db\n        if (force_sort_on or priority) and not force_sort_off:\n            tasklist = sorted(db, key=lambda n: n.priority)\n        else:\n            tasklist = db\n\n        # Now test each gesture in the database against filter criteria\n        out = deque()\n        if not have_filters:\n            out.extend(tasklist)\n            return out\n\n        out_append = out.append\n        for gesture in tasklist:\n\n            if (orientation_sens is not None and\n                    orientation_sens != gesture.orientation_sens):\n                continue\n\n            if numpoints and gesture.numpoints not in numpoints:\n                continue\n\n            if numstrokes and len(gesture.strokes) not in numstrokes:\n                continue\n\n            if min_p is not None and gesture.priority < min_p:\n                continue\n\n            if max_p is not None and gesture.priority > max_p:\n                return out\n\n            if name:\n                for f in name:\n                    if re_match(f, gesture.name):\n                        out_append(gesture)\n                        break\n            else:\n                out_append(gesture)\n\n        return out\n\n    def add_gesture(self, name, strokes, **kwargs):\n        '''Add a new gesture to the database. This will instantiate a new\n        :class:`MultistrokeGesture` with `strokes` and append it to self.db.\n\n        .. Note ::\n            If you already have instantiated a :class:`MultistrokeGesture`\n            object and wish to add it, append it to :attr:`Recognizer.db`\n            manually.\n        '''\n        if not strokes:\n            return False\n        self.db.append(MultistrokeGesture(name=name, strokes=strokes, **kwargs))\n        return True\n\n    def parse_gesture(self, data):\n        '''Parse data formatted by export_gesture(). Returns a list of\n        :class:`MultistrokeGesture` objects. This is used internally by\n        :meth:`import_gesture`, you normally don't need to call this\n        directly.'''\n        io = BytesIO(zlib.decompress(base64.b64decode(data)))\n\n        p = pickle.Unpickler(io)\n        multistrokes = []\n        ms_append = multistrokes.append\n        for multistroke in p.load():\n            strokes = multistroke['strokes']\n            multistroke['strokes'] = [[Vector(\n                x, y) for x, y in line] for line in strokes]\n            ms_append(MultistrokeGesture(**multistroke))\n        return multistrokes\n\n    # FIXME: use a try block, maybe shelve or something\n    def export_gesture(self, filename=None, **kwargs):\n        '''Export a list of :class:`MultistrokeGesture` objects. Outputs a\n        base64-encoded string that can be decoded to a Python list with\n        the :meth:`parse_gesture` function or imported directly to\n        :attr:`self.db` using :meth:`Recognizer.import_gesture`. If\n        `filename` is specified, the output is written to disk, otherwise\n        returned.\n\n        This method accepts optional :meth:`Recognizer.filter` arguments.\n        '''\n        io = BytesIO()\n        p = pickle.Pickler(io, protocol=0)\n        multistrokes = []\n        defaults = {'priority': 100, 'numpoints': 16, 'stroke_sens': True,\n                    'orientation_sens': False, 'angle_similarity': 30.0}\n        dkeys = defaults.keys()\n\n        for multistroke in self.filter(**kwargs):\n            m = dict(defaults)\n            m = {'name': multistroke.name}\n            for attr in dkeys:\n                m[attr] = getattr(multistroke, attr)\n            m['strokes'] = tuple([(p.x, p.y) for p in line]\n                                 for line in multistroke.strokes)\n            multistrokes.append(m)\n        p.dump(multistrokes)\n\n        if filename:\n            f = open(filename, 'wb')\n            f.write(base64.b64encode(zlib.compress(io.getvalue(), 9)))\n            f.close()\n        else:\n            return base64.b64encode(zlib.compress(io.getvalue(), 9))\n\n    # FIXME: match them all with protractor, and don't load exacts? or\n    # just compare the data or something; seems better to do this on import\n    # than on every subsequent call to recognize(). And fix it in general,\n    # too.\n    def import_gesture(self, data=None, filename=None, **kwargs):\n        '''Import a list of gestures as formatted by :meth:`export_gesture`.\n        One of `data` or `filename` must be specified.\n\n        This method accepts optional :meth:`Recognizer.filter` arguments,\n        if none are specified then all gestures in specified data are\n        imported.'''\n        if filename is not None:\n            with open(filename, \"rb\") as infile:\n                data = infile.read()\n        elif data is None:\n            raise MultistrokeError('import_gesture needs data= or filename=')\n\n        new = self.filter(db=self.parse_gesture(data), **kwargs)\n        if new:\n            self.db.extend(new)\n\n    def transfer_gesture(self, tgt, **kwargs):\n        '''Transfers :class:`MultistrokeGesture` objects from\n        :attr:`Recognizer.db` to another :class:`Recognizer` instance `tgt`.\n\n        This method accepts optional :meth:`Recognizer.filter` arguments.\n        '''\n        if hasattr(tgt, 'db') and isinstance(tgt.db, list):\n            send = self.filter(**kwargs)\n            if send:\n                tgt.db.append(None)\n                tgt.db[-1:] = send\n                return True\n\n    def prepare_templates(self, **kwargs):\n        '''This method is used to prepare :class:`UnistrokeTemplate` objects\n        within the gestures in self.db. This is useful if you want to minimize\n        punishment of lazy resampling by preparing all vectors in advance. If\n        you do this before a call to :meth:`Recognizer.export_gesture`, you\n        will have the vectors computed when you load the data later.\n\n        This method accepts optional :meth:`Recognizer.filter` arguments.\n\n        `force_numpoints`, if specified, will prepare all templates to the\n        given number of points (instead of each template's preferred n; ie\n        :data:`UnistrokeTemplate.numpoints`). You normally don't want to\n        do this.'''\n        for gesture in self.filter(**kwargs):\n            for tpl in gesture:\n                n = kwargs.get('force_numpoints', tpl.numpoints)\n                tpl.prepare(n)\n\n    def recognize(self, strokes, goodscore=None, timeout=0, delay=0, **kwargs):\n        '''Search for gestures matching `strokes`. Returns a\n        :class:`ProgressTracker` instance.\n\n        This method accepts optional :meth:`Recognizer.filter` arguments.\n\n        :Arguments:\n\n            `strokes`\n                A list of stroke paths (list of lists of\n                :class:`~kivy.vector.Vector` objects) that will be matched\n                against gestures in the database. Can also be a\n                :class:`Candidate` instance.\n\n                .. Warning ::\n\n                    If you manually supply a :class:`Candidate` that has a\n                    skip-flag, make sure that the correct filter arguments\n                    are set. Otherwise the system will attempt to load vectors\n                    that have not been computed. For example, if you set\n                    `skip_bounded` and do not set `orientation_sensitive` to\n                    False, it will raise an exception if an\n                    orientation_sensitive :class:`UnistrokeTemplate`\n                    is encountered.\n\n            `goodscore`\n                If this is set (between 0.0 - 1.0) and a gesture score is\n                equal to or higher than the specified value, the search is\n                immediately halted and the on_search_complete event is\n                fired (+ the on_complete event of the associated\n                :class:`ProgressTracker` instance). Default is None (disabled).\n\n            `timeout`\n                Specifies a timeout (in seconds) for when the search is\n                aborted and the results returned. This option applies only\n                when `max_gpf` is not 0. Default value is 0, meaning all\n                gestures in the database will be tested, no matter how long\n                it takes.\n\n            `max_gpf`\n                Specifies the maximum number of :class:`MultistrokeGesture`\n                objects that can be processed per frame. When exceeded, will\n                cause the search to halt and resume work in the next frame.\n                Setting to 0 will complete the search immediately (and block\n                the UI).\n\n                .. Warning ::\n\n                    This does not limit the number of\n                    :class:`UnistrokeTemplate` objects matched! If a single\n                    gesture has a million templates, they will all be\n                    processed in a single frame with max_gpf=1!\n\n            `delay`\n                Sets an optional delay between each run of the recognizer\n                loop. Normally, a run is scheduled for the next frame until\n                the tasklist is exhausted. If you set this, there will be an\n                additional delay between each run (specified in seconds).\n                Default is 0, resume in the next frame.\n\n            `force_numpoints`\n                forces all templates (and candidate) to be prepared to a\n                certain number of points. This can be useful for example if\n                you are evaluating templates for optimal n (do not use this\n                unless you understand what it does).\n        '''\n        GPF = kwargs.get('max_gpf', DEFAULT_GPF)\n\n        # Obtain a list of MultistrokeGesture objects matching filter arguments\n        tasklist = self.filter(**kwargs)\n\n        # Initialize the candidate and result objects\n        cand = self._candidate(strokes)\n        result = ProgressTracker(cand, len(tasklist))\n\n        # This is done to inform caller if they bind to on_complete and there\n        # is nothing to do; perhaps should just return None?\n        if not tasklist:\n            result.status = 'complete'\n            self.dispatch('on_search_complete', result)\n\n            def result_hack(dt):\n                result.dispatch('on_complete')\n            Clock.schedule_once(result_hack)\n            return result\n\n        # This callback is scheduled once per frame until completed\n        def _recognize_tick(dt):\n            start_gc = result._completed\n            stop_now = False\n\n            while not stop_now and (tasklist and not result._break_flag) and \\\n                    (not GPF or (result._completed - start_gc < GPF)):\n\n                if (timeout and\n                        Clock.get_time() - result._start_time >= timeout):\n                    result.status = 'timeout'\n                    stop_now = True\n                    break\n\n                # Get the best distance and number of matching operations done\n                gesture = tasklist.popleft()\n                tpl, d, res, mos = gesture.match_candidate(\n                    cand, **kwargs)\n\n                if tpl is not None:\n                    score = result._add_result(gesture, d, tpl, res)\n                    if goodscore is not None and score >= goodscore:\n                        result.status = 'goodscore'\n                        stop_now = True\n\n                result._match_ops += mos\n                result._completed += 1\n                result.dispatch('on_progress')\n\n            # The loop has ended. Prepare to dispatch 'complete'\n            def _dispatch():\n                result.dispatch('on_complete')\n                self.dispatch('on_search_complete', result)\n                return False\n\n            # Dispatch or reschedule another run\n            if not tasklist:\n                result.status = 'complete'\n                return _dispatch()\n            elif result._break_flag:\n                result.status = 'stop'\n                return _dispatch()\n            elif stop_now:\n                return _dispatch()\n            else:\n                Clock.schedule_once(_recognize_tick, delay)\n                return True\n        # End _recognize_tick()\n\n        self.dispatch('on_search_start', result)\n        if not GPF:\n            _recognize_tick(0)\n        else:\n            Clock.schedule_once(_recognize_tick, 0)\n\n        return result\n\n    def _candidate(self, strokes, **kwargs):\n        # recognize() helper function, do not use directly. Set up a\n        # Candidate object from arguments. Either use a specified object\n        # or make a new one from strokes and apply safe skip_* settings to\n        # use less resources.\n        if isinstance(strokes, Candidate):\n            return strokes\n\n        if (not isinstance(strokes, list) or not len(strokes) or not\n                isinstance(strokes[0], list)):\n            raise MultistrokeError('recognize() needs strokes= '\n                                   'list or Candidate')\n\n        cand = Candidate(strokes)\n        o_filter = kwargs.get('orientation_sensitive', None)\n        if o_filter is False:\n            cand.skip_bounded = True\n        elif o_filter is True:\n            cand.skip_invariant = True\n\n        return cand\n\n    # Default event handlers\n    def on_search_start(self, result):\n        pass\n\n    def on_search_complete(self, result):\n        pass\n\n\n# -----------------------------------------------------------------------------\n# ProgressTracker\n# -----------------------------------------------------------------------------\n\nclass ProgressTracker(EventDispatcher):\n    '''Represents an ongoing (or completed) search operation. Instantiated and\n    returned by the :meth:`Recognizer.recognize` method when it is called. The\n    `results` attribute is a dictionary that is  updated as the recognition\n    operation progresses.\n\n    .. Note ::\n        You do not need to instantiate this class.\n\n    :Arguments:\n        `candidate`\n            :class:`Candidate` object to be evaluated\n        `tasks`\n            Total number of gestures in tasklist (to test against)\n\n    :Events:\n        `on_progress`\n            Fired for every gesture that is processed\n        `on_result`\n            Fired when a new result is added, and it is the first match\n            for the `name` so far, or a consecutive match with better score.\n        `on_complete`\n            Fired when the search is completed, for whatever reason.\n            (use `ProgressTracker.status` to find out)\n\n    :Attributes:\n        `results`\n            A dictionary of all results (so far). The key is the name of the\n            gesture (ie :attr:`UnistrokeTemplate.name` usually inherited from\n            :class:`MultistrokeGesture`). Each item in the dictionary is a\n            dict with the following entries:\n\n                `name`\n                    Name of the matched template (redundant)\n                `score`\n                    Computed score from 1.0 (perfect match) to 0.0\n                `dist`\n                    Cosine distance from candidate to template (low=closer)\n                `gesture`\n                    The :class:`MultistrokeGesture` object that was matched\n                `best_template`\n                    Index of the best matching template (in\n                    :attr:`MultistrokeGesture.templates`)\n                `template_results`\n                    List of distances for all templates. The list index\n                    corresponds to a :class:`UnistrokeTemplate` index in\n                    gesture.templates.\n\n        `status`\n            `search`\n                Currently working\n            `stop`\n                Was stopped by the user (:meth:`stop` called)\n            `timeout`\n                A timeout occured (specified as `timeout=` to recognize())\n            `goodscore`\n                The search was stopped early because a gesture with a high\n                enough score was found (specified as `goodscore=` to\n                recognize())\n            `complete`\n                The search is complete (all gestures matching filters were\n                tested)\n    '''\n    def __init__(self, candidate, tasks, **kwargs):\n        self.status = 'search'\n        self.candidate = candidate\n        self.results = {}\n        self.tasks = tasks\n        self._start_time = Clock.get_time()\n        self._match_ops = 0\n        self._completed = 0\n        self._break_flag = False\n\n        # fired by recognize()\n        self.register_event_type('on_complete')\n        self.register_event_type('on_progress')\n\n        # fired locally\n        self.register_event_type('on_result')\n        super(ProgressTracker, self).__init__(**kwargs)\n\n    @property\n    def progress(self):\n        '''Returns the progress as a float, 0 is 0% done, 1 is 100%. This\n        is a Python property.'''\n        if not self.tasks:\n            return 1\n        return self._completed / float(self.tasks)\n\n    @property\n    def best(self):\n        '''Return the best match found by recognize() so far. It returns a\n        dictionary with three keys, 'name', 'dist' and 'score' representing\n        the template's name, distance (from candidate path) and the\n        computed score value. This is a Python property.'''\n        results = self.results  # to avoid too many self. lookups\n        if not results:\n            return {'name': None, 'dist': None, 'score': 0}\n        b = max(results, key=lambda r: results[r]['score'])\n        return {\n            'name': results[b]['name'],\n            'dist': results[b]['dist'],\n            'score': results[b]['score']\n        }\n\n    def stop(self):\n        '''Raises a stop flag that is checked by the search process. It will\n        be stopped on the next clock tick (if it is still running).'''\n        self._break_flag = True\n\n    def _add_result(self, gesture, dist, tpl, res):\n        # Add a result; used internally by the recognize() function\n        if tpl <= len(res):\n            n = gesture.templates[tpl].name\n        else:\n            return 0.\n\n        if n not in self.results or dist < self.results[n]['dist']:\n            self.results[n] = {\n                'name': n,\n                'dist': dist,\n                'gesture': gesture,\n                'best_template': tpl,\n                'template_results': res\n            }\n\n            if not dist:\n                self.results[n]['score'] = 1.0\n            else:\n                self.results[n]['score'] = 1.0 - (dist / pi)\n\n            self.dispatch('on_result', self.results[n])\n            return self.results[n]['score']\n        else:\n            return 0.\n\n    def on_complete(self):\n        pass\n\n    def on_progress(self):\n        pass\n\n    def on_result(self, result):\n        pass\n\n\n# -----------------------------------------------------------------------------\n# MultistrokeGesture\n# -----------------------------------------------------------------------------\n\nclass MultistrokeGesture(object):\n    ''':class:`MultistrokeGesture` represents a gesture. It maintains a set of\n    `strokes` and generates unistroke (ie :class:`UnistrokeTemplate`)\n    permutations that are used for evaluating candidates against this gesture\n    later.\n\n    :Arguments:\n        `name`\n            Identifies the name of the gesture - it is returned to you in the\n            results of a :meth:`Recognizer.recognize` search. You can have any\n            number of MultistrokeGesture objects with the same name; many\n            definitions of one gesture. The same name is given to all the\n            generated unistroke permutations. Required, no default.\n        `strokes`\n            A list of paths that represents the gesture. A path is a list of\n            Vector objects::\n\n                gesture = MultistrokeGesture('my_gesture', strokes=[\n                  [Vector(x1, y1), Vector(x2, y2), ...... ], # stroke 1\n                  [Vector(), Vector(), Vector(), Vector() ]  # stroke 2\n                  #, [stroke 3], [stroke 4], ...\n                ])\n\n            For template matching purposes, all the strokes are combined to a\n            single list (unistroke). You should still specify the strokes\n            individually, and set `stroke_sensitive` True (whenever possible).\n\n            Once you do this, unistroke permutations are immediately generated\n            and stored in `self.templates` for later, unless you set the\n            `permute` flag to False.\n        `priority`\n            Determines when :func:`Recognizer.recognize` will attempt to match\n            this template, lower priorities are evaluated first (only if\n            a priority `filter` is used). You should use lower priority on\n            gestures that are more likely to match. For example, set user\n            templates at lower number than generic templates. Default is 100.\n        `numpoints`\n            Determines the number of points this gesture should be resampled to\n            (for matching purposes). The default is 16.\n        `stroke_sensitive`\n            Determines if the number of strokes (paths) in this gesture is\n            required to be the same in the candidate (user input) gesture\n            during matching. If this is False, candidates will always be\n            evaluated, disregarding the number of strokes. Default is True.\n        `orientation_sensitive`\n            Determines if this gesture is orientation sensitive. If True,\n            aligns the indicative orientation with the one of eight base\n            orientations that requires least rotation. Default is True.\n        `angle_similarity`\n            This is used by the :func:`Recognizer.recognize` function when a\n            candidate is evaluated against this gesture. If the angles between\n            them are too far off, the template is considered a non-match.\n            Default is 30.0 (degrees)\n        `permute`\n            If False, do not use Heap Permute algorithm to generate different\n            stroke orders when instantiated. If you set this to False, a\n            single UnistrokeTemplate built from `strokes` is used.\n    '''\n    def __init__(self, name, strokes=None, **kwargs):\n        self.name = name\n        self.priority = kwargs.get('priority', 100)\n        self.numpoints = kwargs.get('numpoints', 16)\n        self.stroke_sens = kwargs.get('stroke_sensitive', True)\n        self.orientation_sens = kwargs.get('orientation_sensitive', True)\n        self.angle_similarity = kwargs.get('angle_similarity', 30.0)\n        self.strokes = []\n\n        if strokes is not None:\n            self.strokes = strokes\n            if kwargs.get('permute', True):\n                self.permute()\n            else:\n                self.templates = [UnistrokeTemplate(name,\n                                  points=[i for sub in strokes for i in sub],\n                                  numpoints=self.numpoints,\n                                  orientation_sensitive=self.orientation_sens)]\n\n    def angle_similarity_threshold(self):\n        return radians(self.angle_similarity)\n\n    def add_stroke(self, stroke, permute=False):\n        '''Add a stroke to the self.strokes list. If `permute` is True, the\n        :meth:`permute` method is called to generate new unistroke templates'''\n        self.strokes.append(stroke)\n        if permute:\n            self.permute()\n\n    def get_distance(self, cand, tpl, numpoints=None):\n        '''Compute the distance from this Candiate to a UnistrokeTemplate.\n        Returns the Cosine distance between the stroke paths.\n\n        `numpoints` will prepare both the UnistrokeTemplate and Candidate path\n        to n points (when neccessary), you probably don't want to do this.\n        '''\n        n = numpoints\n        if n is None or n < 2:\n            n = self.numpoints\n\n        # optimal_cosine_distance() inlined here for performance\n        v1 = tpl.get_vector(n)\n        v2 = cand.get_protractor_vector(n, tpl.orientation_sens)\n\n        a = 0.0\n        b = 0.0\n\n        for i in xrange(0, len(v1), 2):\n            a += (v1[i] * v2[i]) + (v1[i + 1] * v2[i + 1])\n            b += (v1[i] * v2[i + 1]) - (v1[i + 1] * v2[i])\n\n        angle = atan(b / a)\n\n        # If you put the below directly into math.acos(), you will get a domain\n        # error when a=1.0 and angle=0.0 (ie math_cos(angle)=1.0). It seems to\n        # be because float representation of 1.0*1.0 is >1.0 (ie 1.00000...001)\n        # and this is problematic for math.acos(). If you try math.acos(1.0*1.0)\n        # in interpreter it does not happen, only with exact match at runtime\n        result = a * math_cos(angle) + b * math_sin(angle)\n\n        # FIXME: I'm sure there is a better way to do it but..\n        if result >= 1:\n            result = 1\n        elif result <= -1:  # has not happened to me, but I leave it here.\n            result = -1\n        return acos(result)\n\n    def match_candidate(self, cand, **kwargs):\n        '''Match a given candidate against this MultistrokeGesture object. Will\n        test against all templates and report results as a list of four\n        items:\n\n            `index 0`\n                Best matching template's index (in self.templates)\n            `index 1`\n                Computed distance from the template to the candidate path\n            `index 2`\n                List of distances for all templates. The list index\n                corresponds to a :class:`UnistrokeTemplate` index in\n                self.templates.\n            `index 3`\n                Counter for the number of performed matching operations, ie\n                templates matched against the candidate\n        '''\n        best_d = float('infinity')\n        best_tpl = None\n        mos = 0\n        out = []\n\n        if (self.stroke_sens and len(self.strokes) != len(cand.strokes)):\n            return (best_tpl, best_d, out, mos)\n\n        skip_bounded = cand.skip_bounded\n        skip_invariant = cand.skip_invariant\n        get_distance = self.get_distance\n        ang_sim_threshold = self.angle_similarity_threshold()\n\n        for idx, tpl in enumerate(self.templates):\n            # Handle a theoretical case where a MultistrokeGesture is composed\n            # manually and the orientation_sensitive flag is True, and contains\n            # a UnistrokeTemplate that has orientation_sensitive=False (or vice\n            # versa). This would cause KeyError - requesing nonexistant vector.\n            if tpl.orientation_sens:\n                if skip_bounded:\n                    continue\n            elif skip_invariant:\n                continue\n\n            # Count as a match operation now, since the call to get_\n            # angle_similarity below will force vector calculation,\n            # even if it doesn't make it to get_distance\n            mos += 1\n\n            # Note: With this implementation, we always resample the candidate\n            # to *any* encountered UnistrokeTemplate numpoints here, the filter\n            # is only applied to MultistrokeGesture. See theoretical case\n            # above; should not matter normally.\n            n = kwargs.get('force_numpoints', tpl.numpoints)\n\n            # Skip if candidate/gesture angles are too far off\n            ang_sim = cand.get_angle_similarity(tpl, numpoints=n)\n            if ang_sim > ang_sim_threshold:\n                continue\n\n            # Get the distance between cand/tpl paths\n            d = get_distance(cand, tpl, numpoints=n)\n            out.append(d)\n\n            if d < best_d:\n                best_d = d\n                best_tpl = idx\n\n        return (best_tpl, best_d, out, mos)\n\n    def permute(self):\n        '''Generate all possible unistroke permutations from self.strokes and\n        save the resulting list of UnistrokeTemplate objects in self.templates.\n\n        Quote from http://faculty.washington.edu/wobbrock/pubs/gi-10.2.pdf ::\n\n            We use Heap Permute [16] (p. 179) to generate all stroke orders\n            in a multistroke gesture. Then, to generate stroke directions for\n            each order, we treat each component stroke as a dichotomous\n            [0,1] variable. There are 2^N combinations for N strokes, so we\n            convert the decimal values 0 to 2^N-1, inclusive, to binary\n            representations and regard each bit as indicating forward (0) or\n            reverse (1). This algorithm is often used to generate truth tables\n            in propositional logic.\n\n        See section 4.1: \"$N Algorithm\" of the linked paper for details.\n\n        .. Warning ::\n\n            Using heap permute for gestures with more than 3 strokes\n            can result in very large number of templates (a 9-stroke\n            gesture = 38 million templates). If you are dealing with\n            these types of gestures, you should manually compose\n            all the desired stroke orders.\n        '''\n        # Seed with index of each stroke\n        self._order = [i for i in xrange(0, len(self.strokes))]\n\n        # Prepare ._orders\n        self._orders = []\n        self._heap_permute(len(self.strokes))\n        del self._order\n\n        # Generate unistroke permutations\n        self.templates = [UnistrokeTemplate(\n            self.name,\n            points=permutation,\n            numpoints=self.numpoints,\n            orientation_sensitive=self.orientation_sens\n        ) for permutation in self._make_unistrokes()]\n        del self._orders\n\n    def _heap_permute(self, n):\n        # Heap Permute algorithm\n        self_order = self._order\n        if n == 1:\n            self._orders.append(self_order[:])\n        else:\n            i = 0\n            for i in xrange(0, n):\n                self._heap_permute(n - 1)\n                if n % 2 == 1:\n                    tmp = self_order[0]\n                    self_order[0] = self_order[n - 1]\n                    self_order[n - 1] = tmp\n                else:\n                    tmp = self_order[i]\n                    self_order[i] = self_order[n - 1]\n                    self_order[n - 1] = tmp\n\n    def _make_unistrokes(self):\n        # Create unistroke permutations from self.strokes\n        unistrokes = []\n        unistrokes_append = unistrokes.append\n        self_strokes = self.strokes\n        for r in self._orders:\n            b = 0\n            while b < pow(2, len(r)):  # use b's bits for directions\n                unistroke = []\n                unistroke_append = unistroke.append\n                for i in xrange(0, len(r)):\n                    pts = self_strokes[r[i]][:]\n                    if (b >> i) & 1 == 1:  # is b's bit at index i 1?\n                        pts.reverse()\n                    unistroke_append(None)\n                    unistroke[-1:] = pts\n\n                unistrokes_append(unistroke)\n                b += 1\n        return unistrokes\n\n\n# -----------------------------------------------------------------------------\n# UnistrokeTemplate\n# -----------------------------------------------------------------------------\n\nclass UnistrokeTemplate(object):\n    '''Represents a (uni)stroke path as a list of Vectors. Normally, this class\n    is instantiated by MultistrokeGesture and not by the programmer directly.\n    However, it is possible to manually compose UnistrokeTemplate objects.\n\n    :Arguments:\n        `name`\n            Identifies the name of the gesture. This is normally inherited from\n            the parent MultistrokeGesture object when a template is generated.\n        `points`\n            A list of points that represents a unistroke path. This is normally\n            one of the possible stroke order permutations from a\n            MultistrokeGesture.\n        `numpoints`\n            The number of points this template should (ideally) be resampled to\n            before the matching process. The default is 16, but you can use a\n            template-specific settings if that improves results.\n        `orientation_sensitive`\n            Determines if this template is orientation sensitive (True) or\n            fully rotation invariant (False). The default is True.\n\n    .. Note::\n        You will get an exception if you set a skip-flag and then attempt to\n        retrieve those vectorsa.\n    '''\n    def __init__(self, name, points=None, **kwargs):\n        self.name = name\n        self.numpoints = kwargs.get('numpoints', 16)\n        self.orientation_sens = kwargs.get('orientation_sensitive', True)\n\n        self.db = {}\n        self.points = []\n\n        if points is not None:\n            self.points = points\n\n    def add_point(self, p):\n        '''Add a point to the unistroke/path. This invalidates all previously\n        computed vectors.'''\n        self.points.append(p)\n        # All previously computed data is now void.\n        self.db = {}\n\n    # Used to lazily prepare the template\n    def _get_db_key(self, key, numpoints=None):\n        n = numpoints and numpoints or self.numpoints\n        if n not in self.db:\n            self.prepare(n)\n        return self.db[n][key]\n\n    def get_start_unit_vector(self, numpoints=None):\n        return self._get_db_key('startvector', numpoints)\n\n    def get_vector(self, numpoints=None):\n        return self._get_db_key('vector', numpoints)\n\n    def get_points(self, numpoints=None):\n        return self._get_db_key('points', numpoints)\n\n    def prepare(self, numpoints=None):\n        '''This function prepares the UnistrokeTemplate for matching given a\n        target number of points (for resample). 16 is optimal.'''\n\n        if not self.points:\n            raise MultistrokeError('prepare() called without self.points')\n\n        # How many points are we resampling to?\n        n = numpoints or self.numpoints\n        if not n or n < 2:\n            raise MultistrokeError('prepare() called with invalid numpoints')\n\n        p = resample(self.points, n)\n        radians = indicative_angle(p)\n        p = rotate_by(p, -radians)\n        p = scale_dim(p, SQUARESIZE, ONEDTHRESHOLD)\n\n        if self.orientation_sens:\n            p = rotate_by(p, +radians)  # restore\n\n        p = translate_to(p, ORIGIN)\n\n        # Now store it using the number of points in the resampled path as the\n        # dict key. On the next call to get_*, it will be returned instead of\n        # recomputed. Implicitly, you must reset self.db or call prepare() for\n        # all the keys once you manipulate self.points.\n        self.db[n] = {\n            # Compute STARTANGLEINDEX as n/8:\n            'startvector': start_unit_vector(p, (n / 8)),\n            'vector': vectorize(p, self.orientation_sens)\n        }\n\n\n# -----------------------------------------------------------------------------\n# Candidate\n# -----------------------------------------------------------------------------\n\nclass Candidate(object):\n    '''Represents a set of unistroke paths of user input, ie data to be matched\n    against a :class:`UnistrokeTemplate` object using the Protractor algorithm.\n    By default, data is precomputed to match both rotation bounded and fully\n    invariant :class:`UnistrokeTemplate` objects.\n\n    :Arguments:\n        `strokes`\n            See :data:`MultistrokeGesture.strokes` for format example. The\n            Candidate strokes are simply combined to a unistroke in the order\n            given. The idea is that this will match one of the unistroke\n            permutations in `MultistrokeGesture.templates`.\n        `numpoints`\n            The Candidate's default N; this is only for a fallback, it is not\n            normally used since n is driven by the UnistrokeTemplate we are\n            being compared to.\n        `skip_bounded`\n            If True, do not generate/store rotation bounded vectors\n        `skip_invariant`\n            If True, do not generate/store rotation invariant vectors\n\n    Note that you WILL get errors if you set a skip-flag and then attempt to\n    retrieve the data.'''\n    def __init__(self, strokes=None, numpoints=16, **kwargs):\n        self.skip_invariant = kwargs.get('skip_invariant', False)\n        self.skip_bounded = kwargs.get('skip_bounded', False)\n\n        self.numpoints = numpoints\n        self.db = {}\n        self.strokes = []\n\n        if not strokes is None:\n            self.strokes = strokes\n\n    def add_stroke(self, stroke):\n        '''Add a stroke to the candidate; this will invalidate all\n        previously computed vectors'''\n        self.points.append(stroke)\n        self.db = {}\n\n    # Used to lazily prepare the candidate\n    def _get_db_key(self, key, numpoints, orientation_sens):\n        n = numpoints and numpoints or self.numpoints\n        if n not in self.db:\n            self.prepare(n)\n\n        prefix = orientation_sens and 'bound_' or 'inv_'\n        return self.db[n][prefix + key]\n\n    def get_start_unit_vector(self, numpoints, orientation_sens):\n        '''(Internal use only) Get the start vector for this Candidate,\n        with the path resampled to `numpoints` points. This is the first\n        step in the matching process. It is compared to a\n        UnistrokeTemplate object's start vector to determine angle\n        similarity.'''\n        return self._get_db_key('startvector', numpoints, orientation_sens)\n\n    def get_protractor_vector(self, numpoints, orientation_sens):\n        '''(Internal use only) Return vector for comparing to a\n        UnistrokeTemplate with Protractor'''\n        return self._get_db_key('vector', numpoints, orientation_sens)\n\n    def get_angle_similarity(self, tpl, **kwargs):\n        '''(Internal use only) Compute the angle similarity between this\n        Candidate and a UnistrokeTemplate object. Returns a number that\n        represents the angle similarity (lower is more similar).'''\n        n = kwargs.get('numpoints', self.numpoints)\n\n        # angle_between_unit_vectors() inlined here for performance\n        v1x, v1y = self.get_start_unit_vector(n, tpl.orientation_sens)\n        v2x, v2y = tpl.get_start_unit_vector(n)\n\n        n = (v1x * v2x + v1y * v2y)\n        # FIXME: Domain error on float representation of 1.0 (exact match)\n        # (see comments in MultistrokeGesture.get_distance())\n        if n >= 1:\n            return 0.0\n        if n <= -1:\n            return pi\n        return acos(n)\n\n    def prepare(self, numpoints=None):\n        '''Prepare the Candidate vectors. self.strokes is combined to a single\n        unistroke (connected end-to-end), resampled to :attr:`numpoints` points,\n        and then the vectors are calculated and stored in self.db (for use by\n        `get_distance` and `get_angle_similarity`)'''\n        n = numpoints and numpoints or self.numpoints\n\n        # Inlined combine_strokes() for performance\n        points = [i for sub in self.strokes for i in sub]\n        points = resample(points, n)\n        radians = indicative_angle(points)\n        points = rotate_by(points, -radians)\n        points = scale_dim(points, SQUARESIZE, ONEDTHRESHOLD)\n\n        # Compute STARTANGLEINDEX as n / 8\n        angidx = n / 8\n        cand = {}\n\n        # full rotation invariance\n        if not self.skip_invariant:\n            inv_points = translate_to(points, ORIGIN)\n            cand['inv_startvector'] = start_unit_vector(inv_points, angidx)\n            cand['inv_vector'] = vectorize(inv_points, False)\n\n        # rotation bounded invariance\n        if not self.skip_bounded:\n            bound_points = rotate_by(points, +radians)  # restore\n            bound_points = translate_to(bound_points, ORIGIN)\n            cand['bound_startvector'] = start_unit_vector(bound_points, angidx)\n            cand['bound_vector'] = vectorize(bound_points, True)\n\n        self.db[n] = cand\n\n\n# -----------------------------------------------------------------------------\n# Helper functions from this point on. This is all directly related to the\n# recognition algorithm, and is almost 100% transcription from the JavaScript\n# -----------------------------------------------------------------------------\ndef resample(points, n):\n    # Resample a path to `n` points\n    if not len(points) or not n or n < 2:\n        raise MultistrokeError('resample() called with invalid arguments')\n\n    interval = path_length(points) / (n - 1)\n    D = 0.0\n    i = 1\n    newpoints = [points[0]]\n    workpoints = points[:]\n    newpoints_len = 1\n    workpoints_len = len(points)\n\n    new_append = newpoints.append\n    work_insert = workpoints.insert\n    while i < len(workpoints):\n        p1 = workpoints[i - 1]\n        p2 = workpoints[i]\n        d = distance(p1, p2)\n\n        if D + d >= interval:\n            qx = p1[0] + ((interval - D) / d) * (p2[0] - p1[0])\n            qy = p1[1] + ((interval - D) / d) * (p2[1] - p1[1])\n            q = Vector(qx, qy)\n            new_append(q)\n            work_insert(i, q)  # q is the next i\n            newpoints_len += 1\n            workpoints_len += 1\n            D = 0.0\n        else:\n            D += d\n\n        i += 1\n\n    # rounding error; insert the last point\n    if newpoints_len < n:\n        new_append(points[-1])\n\n    return newpoints\n\n\ndef indicative_angle(points):\n    cx, cy = centroid(points)\n    return atan2(cy - points[0][1], cx - points[0][0])\n\n\ndef rotate_by(points, radians):\n    # Rotate points around centroid\n    cx, cy = centroid(points)\n    cos = math_cos(radians)\n    sin = math_sin(radians)\n    newpoints = []\n    newpoints_append = newpoints.append\n\n    for i in xrange(0, len(points)):\n        qx = (points[i][0] - cx) * cos - (points[i][1] - cy) * sin + cx\n        qy = (points[i][0] - cx) * sin + (points[i][1] - cy) * cos + cy\n        newpoints_append(Vector(qx, qy))\n\n    return newpoints\n\n\ndef scale_dim(points, size, oneDratio):\n    bbox_x, bbox_y, bbox_w, bbox_h = bounding_box(points)\n\n    if bbox_h == 0 or bbox_w == 0:\n        raise MultistrokeError('scale_dim() called with invalid points')\n\n    # 1D or 2D gesture test\n    uniformly = min(bbox_w / bbox_h, bbox_h / bbox_w) <= oneDratio\n\n    if uniformly:\n        qx_size = size / max(bbox_w, bbox_h)\n        qy_size = size / max(bbox_w, bbox_h)\n    else:\n        qx_size = size / bbox_w\n        qy_size = size / bbox_h\n\n    newpoints = []\n    newpoints_append = newpoints.append\n\n    for p in points:\n        qx = p[0] * qx_size\n        qy = p[1] * qy_size\n        newpoints_append(Vector(qx, qy))\n\n    return newpoints\n\n\ndef translate_to(points, pt):\n    # Translate points around centroid\n    cx, cy = centroid(points)\n    ptx, pty = pt\n    newpoints = []\n    for p in points:\n        qx = p[0] + ptx - cx\n        qy = p[1] + pty - cy\n        newpoints.append(Vector(qx, qy))\n    return newpoints\n\n\ndef vectorize(points, use_bounded_rotation_invariance):\n    # Helper function for the Protractor algorithm\n    cos = 1.0\n    sin = 0.0\n\n    if use_bounded_rotation_invariance:\n        ang = atan2(points[0][1], points[0][0])\n        bo = (pi / 4.) * floor((ang + pi / 8.) / (pi / 4.))\n        cos = math_cos(bo - ang)\n        sin = math_sin(bo - ang)\n\n    sum = 0.0\n    vector = []\n    vector_len = 0\n    vector_append = vector.append\n\n    for px, py in points:\n        newx = px * cos - py * sin\n        newy = py * cos + px * sin\n        vector_append(newx)\n        vector_append(newy)\n        vector_len += 2\n        sum += newx ** 2 + newy ** 2\n\n    magnitude = sqrt(sum)\n    for i in xrange(0, vector_len):\n        vector[i] /= magnitude\n\n    return vector\n\n\ndef centroid(points):\n    x = 0.0\n    y = 0.0\n    points_len = len(points)\n\n    for i in xrange(0, points_len):\n        x += points[i][0]\n        y += points[i][1]\n\n    x /= points_len\n    y /= points_len\n\n    return Vector(x, y)\n\n\ndef bounding_box(points):\n    minx = float('infinity')\n    miny = float('infinity')\n    maxx = float('-infinity')\n    maxy = float('-infinity')\n\n    for px, py in points:\n        if px < minx:\n            minx = px\n        if px > maxx:\n            maxx = px\n        if py < miny:\n            miny = py\n        if py > maxy:\n            maxy = py\n\n    return (minx, miny, maxx - minx, maxy - miny)\n\n\ndef path_length(points):\n    d = 0.0\n    for i in xrange(1, len(points)):\n        d += distance(points[i - 1], points[i])\n    return d\n\n\ndef distance(p1, p2):\n    dx = p2[0] - p1[0]\n    dy = p2[1] - p1[1]\n    return sqrt(dx ** 2 + dy ** 2)\n\n\ndef start_unit_vector(points, index):\n    i = int(index)\n    vx, vy = points[i][0] - points[0][0], points[i][1] - points[0][1]\n    length = sqrt(vx ** 2 + vy ** 2)\n    return Vector(vx / length, vy / length)\n"
  },
  {
    "path": "tickeys/kivy/network/__init__.py",
    "content": "'''\nNetwork support\n===============\n\nKivy currently supports basic, asynchronous network requests.\nPlease refer to :class:`kivy.network.urlrequest.UrlRequest`.\n'''\n"
  },
  {
    "path": "tickeys/kivy/network/urlrequest.py",
    "content": "'''\nUrl Request\n===========\n\n.. versionadded:: 1.0.8\n\nYou can use the :class:`UrlRequest` to make asynchronous requests on the\nweb and get the result when the request is completed. The spirit is the\nsame as the XHR object in Javascript.\n\nThe content is also decoded if the Content-Type is\napplication/json and the result automatically passed through json.loads.\n\n\nThe syntax to create a request::\n\n    from kivy.network.urlrequest import UrlRequest\n    req = UrlRequest(url, on_success, on_redirect, on_failure, on_error,\n                     on_progress, req_body, req_headers, chunk_size,\n                     timeout, method, decode, debug, file_path)\n\n\nOnly the first argument is mandatory: the rest are optional.\nBy default, a \"GET\" request will be sent. If the :attr:`UrlRequest.req_body` is\nnot None, a \"POST\" request will be sent. It's up to you to adjust\n:attr:`UrlRequest.req_headers` to suit your requirements and the response\nto the request will be accessible as the parameter called \"result\" on\nthe callback function of the on_success event.\n\n\nExample of fetching weather in Paris::\n\n    def got_weather(req, results):\n        for key, value in results['weather'][0].items():\n            print(key, ': ', value)\n\n    req = UrlRequest(\n        'http://api.openweathermap.org/data/2.5/weather?q=Paris,fr',\n        got_weather)\n\nExample of Posting data (adapted from httplib example)::\n\n    import urllib\n\n    def bug_posted(req, result):\n        print('Our bug is posted !')\n        print(result)\n\n    params = urllib.urlencode({'@number': 12524, '@type': 'issue',\n        '@action': 'show'})\n    headers = {'Content-type': 'application/x-www-form-urlencoded',\n              'Accept': 'text/plain'}\n    req = UrlRequest('bugs.python.org', on_success=bug_posted, req_body=params,\n            req_headers=headers)\n\nIf you want a synchronous request, you can call the wait() method.\n\n'''\n\nfrom collections import deque\nfrom threading import Thread\nfrom json import loads\nfrom time import sleep\nfrom kivy.compat import PY2\n\nif PY2:\n    from httplib import HTTPConnection\n    from urlparse import urlparse\nelse:\n    from http.client import HTTPConnection\n    from urllib.parse import urlparse\n\ntry:\n    HTTPSConnection = None\n    if PY2:\n        from httplib import HTTPSConnection\n    else:\n        from http.client import HTTPSConnection\nexcept ImportError:\n    # depending the platform, if openssl support wasn't compiled before python,\n    # this class is not available.\n    pass\n\nfrom kivy.clock import Clock\nfrom kivy.weakmethod import WeakMethod\nfrom kivy.logger import Logger\n\n\n# list to save UrlRequest and prevent GC on un-referenced objects\ng_requests = []\n\n\nclass UrlRequest(Thread):\n    '''A UrlRequest. See module documentation for usage.\n\n    .. versionchanged:: 1.5.1\n        Add `debug` parameter\n\n    .. versionchanged:: 1.0.10\n        Add `method` parameter\n\n    :Parameters:\n        `url`: str\n            Complete url string to call.\n        `on_success`: callback(request, result)\n            Callback function to call when the result has been fetched.\n        `on_redirect`: callback(request, result)\n            Callback function to call if the server returns a Redirect.\n        `on_failure`: callback(request, result)\n            Callback function to call if the server returns a Client or\n            Server Error.\n        `on_error`: callback(request, error)\n            Callback function to call if an error occurs.\n        `on_progress`: callback(request, current_size, total_size)\n            Callback function that will be called to report progression of the\n            download. `total_size` might be -1 if no Content-Length has been\n            reported in the http response.\n            This callback will be called after each `chunk_size` is read.\n        `req_body`: str, defaults to None\n            Data to sent in the request. If it's not None, a POST will be done\n            instead of a GET.\n        `req_headers`: dict, defaults to None\n            Custom headers to add to the request.\n        `chunk_size`: int, defaults to 8192\n            Size of each chunk to read, used only when `on_progress` callback\n            has been set. If you decrease it too much, a lot of on_progress\n            callbacks will be fired and will slow down your download. If you\n            want to have the maximum download speed, increase the chunk_size\n            or don't use ``on_progress``.\n        `timeout`: int, defaults to None\n            If set, blocking operations will timeout after this many seconds.\n        `method`: str, defaults to 'GET' (or 'POST' if ``body`` is specified)\n            The HTTP method to use.\n        `decode`: bool, defaults to True\n            If False, skip decoding of the response.\n        `debug`: bool, defaults to False\n            If True, it will use the Logger.debug to print information\n            about url access/progression/errors.\n        `file_path`: str, defaults to None\n            If set, the result of the UrlRequest will be written to this path\n            instead of in memory.\n\n    .. versionchanged:: 1.8.0\n\n        Parameter `decode` added.\n        Parameter `file_path` added.\n        Parameter `on_redirect` added.\n        Parameter `on_failure` added.\n\n    '''\n\n    def __init__(self, url, on_success=None, on_redirect=None,\n                 on_failure=None, on_error=None, on_progress=None,\n                 req_body=None, req_headers=None, chunk_size=8192,\n                 timeout=None, method=None, decode=True, debug=False,\n                 file_path=None):\n        super(UrlRequest, self).__init__()\n        self._queue = deque()\n        self._trigger_result = Clock.create_trigger(self._dispatch_result, 0)\n        self.daemon = True\n        self.on_success = WeakMethod(on_success) if on_success else None\n        self.on_redirect = WeakMethod(on_redirect) if on_redirect else None\n        self.on_failure = WeakMethod(on_failure) if on_failure else None\n        self.on_error = WeakMethod(on_error) if on_error else None\n        self.on_progress = WeakMethod(on_progress) if on_progress else None\n        self.decode = decode\n        self.file_path = file_path\n        self._debug = debug\n        self._result = None\n        self._error = None\n        self._is_finished = False\n        self._resp_status = None\n        self._resp_headers = None\n        self._resp_length = -1\n        self._chunk_size = chunk_size\n        self._timeout = timeout\n        self._method = method\n\n        #: Url of the request\n        self.url = url\n\n        #: Request body passed in __init__\n        self.req_body = req_body\n\n        #: Request headers passed in __init__\n        self.req_headers = req_headers\n\n        # save our request to prevent GC\n        g_requests.append(self)\n\n        self.start()\n\n    def run(self):\n        q = self._queue.appendleft\n        url = self.url\n        req_body = self.req_body\n        req_headers = self.req_headers\n\n        try:\n            result, resp = self._fetch_url(url, req_body, req_headers, q)\n            if self.decode:\n                result = self.decode_result(result, resp)\n        except Exception as e:\n            q(('error', None, e))\n        else:\n            q(('success', resp, result))\n\n        # using trigger can result in a missed on_success event\n        self._trigger_result()\n\n        # clean ourself when the queue is empty\n        while len(self._queue):\n            sleep(.1)\n            self._trigger_result()\n\n        # ok, authorize the GC to clean us.\n        if self in g_requests:\n            g_requests.remove(self)\n\n    def _fetch_url(self, url, body, headers, q):\n        # Parse and fetch the current url\n        trigger = self._trigger_result\n        chunk_size = self._chunk_size\n        report_progress = self.on_progress is not None\n        timeout = self._timeout\n        file_path = self.file_path\n\n        if self._debug:\n            Logger.debug('UrlRequest: {0} Fetch url <{1}>'.format(\n                id(self), url))\n            Logger.debug('UrlRequest: {0} - body: {1}'.format(\n                id(self), body))\n            Logger.debug('UrlRequest: {0} - headers: {1}'.format(\n                id(self), headers))\n\n        # parse url\n        parse = urlparse(url)\n\n        # translate scheme to connection class\n        cls = self.get_connection_for_scheme(parse.scheme)\n\n        # correctly determine host/port\n        port = None\n        host = parse.netloc.split(':')\n        if len(host) > 1:\n            port = int(host[1])\n        host = host[0]\n\n        # create connection instance\n        args = {}\n        if timeout is not None:\n            args['timeout'] = timeout\n        req = cls(host, port, **args)\n\n        # reconstruct path to pass on the request\n        path = parse.path\n        if parse.params:\n            path += ';' + parse.params\n        if parse.query:\n            path += '?' + parse.query\n        if parse.fragment:\n            path += '#' + parse.fragment\n\n        # send request\n        method = self._method\n        if method is None:\n            method = 'GET' if body is None else 'POST'\n        req.request(method, path, body, headers or {})\n\n        # read header\n        resp = req.getresponse()\n\n        # read content\n        if report_progress or file_path is not None:\n            try:\n                total_size = int(resp.getheader('content-length'))\n            except:\n                total_size = -1\n\n            # before starting the download, send a fake progress to permit the\n            # user to initialize his ui\n            if report_progress:\n                q(('progress', resp, (0, total_size)))\n\n            def get_chunks(fd=None):\n                bytes_so_far = 0\n                result = b''\n                while 1:\n                    chunk = resp.read(chunk_size)\n                    if not chunk:\n                        break\n\n                    if fd:\n                        fd.write(chunk)\n                    else:\n                        result += chunk\n\n                    bytes_so_far += len(chunk)\n                    # report progress to user\n                    if report_progress:\n                        q(('progress', resp, (bytes_so_far, total_size)))\n                        trigger()\n                return bytes_so_far, result\n\n            if file_path is not None:\n                with open(file_path, 'wb') as fd:\n                    bytes_so_far, result = get_chunks(fd)\n            else:\n                bytes_so_far, result = get_chunks()\n\n            # ensure that restults are dispatched for the last chunk,\n            # avoid trigger\n            if report_progress:\n                q(('progress', resp, (bytes_so_far, total_size)))\n                trigger()\n        else:\n            result = resp.read()\n            try:\n                if isinstance(result, bytes):\n                    result = result.decode('utf-8')\n            except UnicodeDecodeError:\n                # if it's an image? decoding would not work\n                pass\n        req.close()\n\n        # return everything\n        return result, resp\n\n    def get_connection_for_scheme(self, scheme):\n        '''Return the Connection class for a particular scheme.\n        This is an internal function that can be expanded to support custom\n        schemes.\n\n        Actual supported schemes: http, https.\n        '''\n        if scheme == 'http':\n            return HTTPConnection\n        elif scheme == 'https' and HTTPSConnection is not None:\n            return HTTPSConnection\n        else:\n            raise Exception('No class for scheme %s' % scheme)\n\n    def decode_result(self, result, resp):\n        '''Decode the result fetched from url according to his Content-Type.\n        Currently supports only application/json.\n        '''\n        # Entry to decode url from the content type.\n        # For example, if the content type is a json, it will be automatically\n        # decoded.\n        content_type = resp.getheader('Content-Type', None)\n        if content_type is not None:\n            ct = content_type.split(';')[0]\n            if ct == 'application/json':\n                try:\n                    return loads(result)\n                except:\n                    return result\n        return result\n\n    def _dispatch_result(self, dt):\n        while True:\n            # Read the result pushed on the queue, and dispatch to the client\n            try:\n                result, resp, data = self._queue.pop()\n            except IndexError:\n                return\n            if resp:\n                # XXX usage of dict can be dangerous if multiple headers\n                # are set even if it's invalid. But it look like it's ok\n                # ?  http://stackoverflow.com/questions/2454494/..\n                # ..urllib2-multiple-set-cookie-headers-in-response\n                self._resp_headers = dict(resp.getheaders())\n                self._resp_status = resp.status\n            if result == 'success':\n                status_class = resp.status // 100\n\n                if status_class in (1, 2):\n                    if self._debug:\n                        Logger.debug('UrlRequest: {0} Download finished with'\n                                     ' {1} datalen'.format(id(self),\n                                                           len(data)))\n                    self._is_finished = True\n                    self._result = data\n                    if self.on_success:\n                        func = self.on_success()\n                        if func:\n                            func(self, data)\n\n                elif status_class == 3:\n                    if self._debug:\n                        Logger.debug('UrlRequest: {} Download '\n                                     'redirected'.format(id(self)))\n                    self._is_finished = True\n                    self._result = data\n                    if self.on_redirect:\n                        func = self.on_redirect()\n                        if func:\n                            func(self, data)\n\n                elif status_class in (4, 5):\n                    if self._debug:\n                        Logger.debug('UrlRequest: {} Download failed with '\n                                     'http error {}'.format(id(self),\n                                                            resp.status))\n                    self._is_finished = True\n                    self._result = data\n                    if self.on_failure:\n                        func = self.on_failure()\n                        if func:\n                            func(self, data)\n\n            elif result == 'error':\n                if self._debug:\n                    Logger.debug('UrlRequest: {0} Download error '\n                                 '<{1}>'.format(id(self), data))\n                self._is_finished = True\n                self._error = data\n                if self.on_error:\n                    func = self.on_error()\n                    if func:\n                        func(self, data)\n\n            elif result == 'progress':\n                if self._debug:\n                    Logger.debug('UrlRequest: {0} Download progress '\n                                 '{1}'.format(id(self), data))\n                if self.on_progress:\n                    func = self.on_progress()\n                    if func:\n                        func(self, data[0], data[1])\n\n            else:\n                assert(0)\n\n    @property\n    def is_finished(self):\n        '''Return True if the request has finished, whether it's a\n        success or a failure.\n        '''\n        return self._is_finished\n\n    @property\n    def result(self):\n        '''Return the result of the request.\n        This value is not determined until the request is finished.\n        '''\n        return self._result\n\n    @property\n    def resp_headers(self):\n        '''If the request has been completed, return a dictionary containing\n        the headers of the response. Otherwise, it will return None.\n        '''\n        return self._resp_headers\n\n    @property\n    def resp_status(self):\n        '''Return the status code of the response if the request is complete,\n        otherwise return None.\n        '''\n        return self._resp_status\n\n    @property\n    def error(self):\n        '''Return the error of the request.\n        This value is not determined until the request is completed.\n        '''\n        return self._error\n\n    @property\n    def chunk_size(self):\n        '''Return the size of a chunk, used only in \"progress\" mode (when\n        on_progress callback is set.)\n        '''\n        return self._chunk_size\n\n    def wait(self, delay=0.5):\n        '''Wait for the request to finish (until :attr:`resp_status` is not\n        None)\n\n        .. note::\n            This method is intended to be used in the main thread, and the\n            callback will be dispatched from the same thread\n            from which you're calling.\n\n        .. versionadded:: 1.1.0\n        '''\n        while self.resp_status is None:\n            self._dispatch_result(delay)\n            sleep(delay)\n\n\nif __name__ == '__main__':\n\n    from pprint import pprint\n\n    def on_success(req, result):\n        pprint('Got the result:')\n        pprint(result)\n\n    def on_error(req, error):\n        pprint('Got an error:')\n        pprint(error)\n\n    req = UrlRequest('http://en.wikipedia.org/w/api.php?format'\n        '=json&action=query&titles=Kivy&prop=revisions&rvprop=content',\n        on_success, on_error)\n    while not req.is_finished:\n        sleep(1)\n        Clock.tick()\n\n    print('result =', req.result)\n    print('error =', req.error)\n"
  },
  {
    "path": "tickeys/kivy/parser.py",
    "content": "'''\nParser utilities\n================\n\nHelper functions used for CSS parsing.\n'''\n\n__all__ = ('parse_color', 'parse_int', 'parse_float',\n           'parse_string', 'parse_bool', 'parse_int2',\n           'parse_float4', 'parse_filename')\n\nimport re\nfrom kivy.logger import Logger\nfrom kivy.resources import resource_find\n\n\nclass ColorException(Exception):\n    pass\n\n\ndef parse_filename(filename):\n    '''Parse a filename and search for it using `resource_find()`.\n    If found, the resource path is returned, otherwise return the unmodified\n    filename (as specified by the caller).'''\n    filename = parse_string(filename)\n    result = resource_find(filename)\n    if result is None:\n        Logger.error('Resource: unable to find <%s>' % filename)\n    return result or filename\n\n\ndef color_error(text):\n    # show warning and return a sane value\n    Logger.warning(text)\n    return (0, 0, 0, 1)\n\n\ndef parse_color(text):\n    '''Parse a string to a kivy color. Supported formats:\n\n        * rgb(r, g, b)\n        * rgba(r, g, b, a)\n        * aaa\n        * rrggbb\n\n    For hexadecimal values, you case also use:\n\n        * #aaa\n        * #rrggbb\n    '''\n    value = [1, 1, 1, 1]\n    if text.startswith('rgb'):\n        res = re.match('rgba?\\((.*)\\)', text)\n        if res:\n            try:\n                # default r/g/b values to 1 if greater than 255 else x/255\n                value = [1 if int(x) > 255. else (int(x) / 255.)\n                         for x in re.split(',\\ ?', res.groups()[0])]\n                if len(value) < 3:\n                    #in case of invalid input like rgb()/rgb(r)/rgb(r, g)\n                    raise ValueError\n            except ValueError:\n                return color_error('ColorParser: Invalid color for %r' % text)\n            except AttributeError:\n                return color_error('ColorParser: Invalid color for %r' % text)\n        else:\n            return color_error('ColorParser: Invalid color for %r' % text)\n        if len(value) == 3:\n            value.append(1.)\n    elif len(text):\n        res = text\n        if text[0] == '#':\n            res = text[1:]\n        lres = len(res)\n        if lres == 3 or lres == 4:\n            res = ''.join([x + x for x in res])\n        elif lres != 6 and lres != 8:\n            #raise ColorException('Invalid color format for %r' % text)\n            return color_error(\n                'ColorParser: Invalid color format for %r' % text)\n        try:\n            value = [int(res[i:i + 2], 16) / 255.\n                     for i in range(0, len(res), 2)]\n        except ValueError:\n            return color_error('ColorParser: Invalid color for %r' % text)\n        if lres == 6:\n            value.append(1.)\n    return value\n\n\ndef parse_bool(text):\n    '''Parse a string to a boolean, ignoring case. \"true\"/\"1\" is True,\n    \"false\"/\"0\" is False. Anything else throws an exception.'''\n    if text.lower() in ('true', '1'):\n        return True\n    elif text.lower() in ('false', '0'):\n        return False\n    raise Exception('Invalid boolean: %s' % text)\n\n\ndef parse_string(text):\n    '''Parse a string to a string (removing single and double quotes)'''\n    if len(text) >= 2 and text[0] in ('\"', \"'\") and text[-1] in ('\"', \"'\"):\n        text = text[1:-1]\n    return text.strip()\n\n\ndef parse_int2(text):\n    '''Parse a string to a list of exactly 2 integers.\n\n        >>> print(parse_int2(\"12 54\"))\n        12, 54\n\n    '''\n    texts = [x for x in text.split(' ') if x.strip() != '']\n    value = list(map(parse_int, texts))\n    if len(value) < 1:\n        raise Exception('Invalid int2 format: %s' % text)\n    elif len(value) == 1:\n        return [value[0], value[0]]\n    elif len(value) > 2:\n        raise Exception('Too many values in %s: %s' % (text, str(value)))\n    return value\n\n\ndef parse_float4(text):\n    '''Parse a string to a list of exactly 4 floats.\n\n        >>> parse_float4('54 87. 35 0')\n        54, 87., 35, 0\n\n    '''\n    texts = [x for x in text.split(' ') if x.strip() != '']\n    value = list(map(parse_float, texts))\n    if len(value) < 1:\n        raise Exception('Invalid float4 format: %s' % text)\n    elif len(value) == 1:\n        return [value[0] for x in range(4)]\n    elif len(value) == 2:\n        return [value[0], value[1], value[0], value[1]]\n    elif len(value) == 3:\n        # ambigous case!\n        return [value[0], value[1], value[0], value[2]]\n    elif len(value) > 4:\n        raise Exception('Too many values in %s' % text)\n    return value\n\n\nparse_int = int\nparse_float = float\n"
  },
  {
    "path": "tickeys/kivy/properties.pxd",
    "content": "from kivy._event cimport EventDispatcher, EventObservers\n\ncdef class PropertyStorage:\n    cdef object value\n    cdef EventObservers observers\n    cdef object numeric_fmt\n    cdef long bnum_min\n    cdef long bnum_max\n    cdef float bnum_f_min\n    cdef float bnum_f_max\n    cdef int bnum_use_min\n    cdef int bnum_use_max\n    cdef list options\n    cdef tuple properties\n    cdef int stop_event\n    cdef object getter\n    cdef object setter\n    cdef int alias_initial\n\ncdef class Property:\n    cdef str _name\n    cdef int allownone\n    cdef int force_dispatch\n    cdef object errorvalue\n    cdef object errorhandler\n    cdef int errorvalue_set\n    cdef public object defaultvalue\n    cdef init_storage(self, EventDispatcher obj, PropertyStorage storage)\n    cpdef link(self, EventDispatcher obj, str name)\n    cpdef link_deps(self, EventDispatcher obj, str name)\n    cpdef bind(self, EventDispatcher obj, observer)\n    cpdef fast_bind(self, EventDispatcher obj, observer, tuple largs=*, dict kwargs=*)\n    cpdef unbind(self, EventDispatcher obj, observer)\n    cpdef fast_unbind(self, EventDispatcher obj, observer, tuple largs=*, dict kwargs=*)\n    cpdef unbind_uid(self, EventDispatcher obj, object uid)\n    cdef compare_value(self, a, b)\n    cpdef set(self, EventDispatcher obj, value)\n    cpdef get(self, EventDispatcher obj)\n    cdef check(self, EventDispatcher obj, x)\n    cdef convert(self, EventDispatcher obj, x)\n    cpdef dispatch(self, EventDispatcher obj)\n\ncdef class NumericProperty(Property):\n    cdef float parse_str(self, EventDispatcher obj, value)\n    cdef float parse_list(self, EventDispatcher obj, value, ext)\n\ncdef class StringProperty(Property):\n    pass\n\ncdef class ListProperty(Property):\n    pass\n\ncdef class DictProperty(Property):\n    cdef public int rebind\n\ncdef class ObjectProperty(Property):\n    cdef object baseclass\n    cdef public int rebind\n\ncdef class BooleanProperty(Property):\n    pass\n\ncdef class BoundedNumericProperty(Property):\n    cdef int use_min\n    cdef int use_max\n    cdef long min\n    cdef long max\n    cdef float f_min\n    cdef float f_max\n\ncdef class OptionProperty(Property):\n    cdef list options\n\ncdef class ReferenceListProperty(Property):\n    cdef list properties\n    cpdef trigger_change(self, EventDispatcher obj, value)\n    cpdef setitem(self, EventDispatcher obj, key, value)\n\ncdef class AliasProperty(Property):\n    cdef object getter\n    cdef object setter\n    cdef list bind_objects\n    cdef int use_cache\n    cdef public int rebind\n    cpdef trigger_change(self, EventDispatcher obj, value)\n\ncdef class VariableListProperty(Property):\n    cdef public int length\n    cdef _convert_numeric(self, EventDispatcher obj, x)\n    cdef float parse_str(self, EventDispatcher obj, value)\n    cdef float parse_list(self, EventDispatcher obj, value, ext)\n\ncdef class ConfigParserProperty(Property):\n    cdef object config\n    cdef object section\n    cdef object key\n    cdef object val_type\n    cdef object verify\n    cdef object obj\n    cdef object last_value  # last string config value\n    cdef object config_name\n    cpdef _edit_setting(self, section, key, value)\n    cdef inline object _parse_str(self, object value)\n"
  },
  {
    "path": "tickeys/kivy/resources.py",
    "content": "'''\nResources management\n====================\n\nResource management can be a pain if you have multiple paths and projects. Kivy\noffers 2 functions for searching for specific resources across a list of\npaths.\n'''\n\n__all__ = ('resource_find', 'resource_add_path', 'resource_remove_path')\n\nfrom os.path import join, dirname, exists\nfrom kivy import kivy_data_dir\nfrom kivy.utils import platform\nfrom kivy.logger import Logger\nimport sys\nimport kivy\n\nresource_paths = ['.', dirname(sys.argv[0])]\nif platform == 'ios':\n    resource_paths += [join(dirname(sys.argv[0]), 'YourApp')]\nresource_paths += [dirname(kivy.__file__), join(kivy_data_dir, '..')]\n\n\ndef resource_find(filename):\n    '''Search for a resource in the list of paths.\n    Use resource_add_path to add a custom path to the search.\n    '''\n    if not filename:\n        return None\n    if filename[:8] == 'atlas://':\n        return filename\n    if exists(filename):\n        return filename\n    for path in reversed(resource_paths):\n        output = join(path, filename)\n        if exists(output):\n            return output\n    return None\n\n\ndef resource_add_path(path):\n    '''Add a custom path to search in.\n    '''\n    if path in resource_paths:\n        return\n    Logger.debug('Resource: add <%s> in path list' % path)\n    resource_paths.append(path)\n\n\ndef resource_remove_path(path):\n    '''Remove a search path.\n\n    .. versionadded:: 1.0.8\n    '''\n    if path not in resource_paths:\n        return\n    Logger.debug('Resource: remove <%s> from path list' % path)\n    resource_paths.remove(path)\n"
  },
  {
    "path": "tickeys/kivy/setupconfig.py",
    "content": "# Autogenerated file for Kivy configuration\nPY3 = 0\nCYTHON_MIN = '0.20'\nCYTHON_MAX = '0.23'\nCYTHON_BAD = ''\nUSE_RPI = 0\nUSE_OPENGL_ES2 = 1\nUSE_OPENGL_DEBUG = 0\nUSE_GLEW = 0\nUSE_SDL2 = 1\nUSE_IOS = 0\nUSE_MESAGL = 0\nUSE_X11 = 0\nUSE_GSTREAMER = 1\nUSE_AVFOUNDATION = 0\nUSE_OSX_FRAMEWORKS = 0\nDEBUG = False\n"
  },
  {
    "path": "tickeys/kivy/storage/__init__.py",
    "content": "'''\nStorage\n=======\n\n.. versionadded:: 1.7.0\n\n.. warning::\n\n    This module is still experimental, and the API is subject to change in a\n    future version.\n\nUsage\n-----\n\nThe idea behind the Storage module is to be able to load/store any number of\nkey/value pairs via an indexed key. The default model is abstract so you\ncannot use it directly. We provide some implementations such as:\n\n- :class:`kivy.storage.dictstore.DictStore`: use a python dict as a store\n- :class:`kivy.storage.jsonstore.JsonStore`: use a JSON file as a store\n- :class:`kivy.storage.redistore.RedisStore`: use a `Redis <http://redis.io>`_\n  database with `redis-py <https://github.com/andymccurdy/redis-py>`_\n\n\n\nExamples\n--------\n\nFor example, let's use a JsonStore::\n\n    from kivy.storage.jsonstore import JsonStore\n\n    store = JsonStore('hello.json')\n\n    # put some values\n    store.put('tito', name='Mathieu', org='kivy')\n    store.put('tshirtman', name='Gabriel', age=27)\n\n    # using the same index key erases all previously added key/value pairs\n    store.put('tito', name='Mathieu', age=30)\n\n    # get a value using a index key and key\n    print('tito is', store.get('tito')['age'])\n\n    # or guess the key/entry for a part of the key\n    for item in store.find(name='Gabriel'):\n        print('tshirtmans index key is', item[0])\n        print('his key value pairs are', str(item[1]))\n\nBecause the data is persistant, you can check later to see if the key exists::\n\n    from kivy.storage.jsonstore import JsonStore\n\n    store = JsonStore('hello.json')\n    if store.exists('tito'):\n        print('tite exists:', store.get('tito'))\n        store.delete('tito')\n\n\nSynchronous / Asynchronous API\n------------------------------\n\nAll the standard methods (:meth:`~AbstractStore.get`,\n:meth:`~AbstractStore.put` , :meth:`~AbstractStore.exists`,\n:meth:`~AbstractStore.delete`, :meth:`~AbstractStore.find`) have an\nasynchronous version.\n\nFor example, the *get* method has a `callback` parameter. If set, the\n`callback` will be used to return the result to the user when available:\nthe request will be asynchronous. If the `callback` is None, then the\nrequest will be synchronous and the result will be returned directly.\n\n\nWithout callback (Synchronous API)::\n\n    entry = mystore.get('tito')\n    print('tito =', entry)\n\nWith callback (Asynchronous API)::\n\n    def my_callback(store, key, entry):\n        print('the key', key, 'have', entry)\n    mystore.get('plop', callback=my_callback)\n\n\nThe callback signature is (for almost all methods) `callback(store, key,\nresult)`::\n\n#. `store` is the `Store` instance currently used.\n#. `key` is the key to search for.\n#. `entry` is the result of the lookup for the `key`.\n\n\nSynchronous container type\n--------------------------\n\nThe storage API emulates the container type for the synchronous API::\n\n    store = JsonStore('hello.json')\n\n    # original: store.get('tito')\n    store['tito']\n\n    # original: store.put('tito', name='Mathieu')\n    store['tito'] = {'name': 'Mathieu'}\n\n    # original: store.delete('tito')\n    del store['tito']\n\n    # original: store.count()\n    len(store)\n\n    # original: store.exists('tito')\n    'tito' in store\n\n    # original: for key in store.keys()\n    for key in store:\n        pass\n\n'''\n\nfrom kivy.clock import Clock\nfrom kivy.event import EventDispatcher\nfrom functools import partial\n\n\nclass AbstractStore(EventDispatcher):\n    '''Abstract class used to implement a Store\n    '''\n\n    def __init__(self, **kwargs):\n        super(AbstractStore, self).__init__(**kwargs)\n        self.store_load()\n\n    def exists(self, key):\n        '''Check if a key exists in the store.\n        '''\n        return self.store_exists(key)\n\n    def async_exists(self, callback, key):\n        '''Asynchronous version of :meth:`exists`.\n\n        :Callback arguments:\n            `store`: :class:`AbstractStore` instance\n                Store instance\n            `key`: string\n                Name of the key to search for\n            `result`: boo\n                Result of the query, None if any error\n        '''\n        self._schedule(self.store_exists_async,\n                       key=key, callback=callback)\n\n    def get(self, key):\n        '''Get the key/value pairs stored at `key`. If the key is not found, a\n        `KeyError` exception will be thrown.\n        '''\n        return self.store_get(key)\n\n    def async_get(self, callback, key):\n        '''Asynchronous version of :meth:`get`.\n\n        :Callback arguments:\n            `store`: :class:`AbstractStore` instance\n                Store instance\n            `key`: string\n                Name of the key to search for\n            `result`: dict\n                Result of the query, None if any error\n        '''\n        self._schedule(self.store_get_async, key=key, callback=callback)\n\n    def put(self, key, **values):\n        '''Put new key/value pairs (given in *values*) into the storage. Any\n        existing key/value pairs will be removed.\n        '''\n        need_sync = self.store_put(key, values)\n        if need_sync:\n            self.store_sync()\n        return need_sync\n\n    def async_put(self, callback, key, **values):\n        '''Asynchronous version of :meth:`put`.\n\n        :Callback arguments:\n            `store`: :class:`AbstractStore` instance\n                Store instance\n            `key`: string\n                Name of the key to search for\n            `result`: bool\n                Indicate True if the storage has been updated, or False if\n                nothing has been done (no changes). None if any error.\n        '''\n        self._schedule(self.store_put_async,\n                       key=key, value=values, callback=callback)\n\n    def delete(self, key):\n        '''Delete a key from the storage. If the key is not found, a `KeyError`\n        exception will be thrown.'''\n        need_sync = self.store_delete(key)\n        if need_sync:\n            self.store_sync()\n        return need_sync\n\n    def async_delete(self, callback, key):\n        '''Asynchronous version of :meth:`delete`.\n\n        :Callback arguments:\n            `store`: :class:`AbstractStore` instance\n                Store instance\n            `key`: string\n                Name of the key to search for\n            `result`: bool\n                Indicate True if the storage has been updated, or False if\n                nothing has been done (no changes). None if any error.\n        '''\n        self._schedule(self.store_delete_async, key=key,\n                       callback=callback)\n\n    def find(self, **filters):\n        '''Return all the entries matching the filters. The entries are\n        returned through a generator as a list of (key, entry) pairs\n        where *entry* is a dict of key/value pairs ::\n\n            for key, entry in store.find(name='Mathieu'):\n                print('key:', key, ', entry:', entry)\n\n        Because it's a generator, you cannot directly use it as a list. You can\n        do::\n\n            # get all the (key, entry) availables\n            entries = list(store.find(name='Mathieu'))\n            # get only the entry from (key, entry)\n            entries = list((x[1] for x in store.find(name='Mathieu')))\n        '''\n        return self.store_find(filters)\n\n    def async_find(self, callback, **filters):\n        '''Asynchronous version of :meth:`find`.\n\n        The callback will be called for each entry in the result.\n\n        :Callback arguments:\n            `store`: :class:`AbstractStore` instance\n                Store instance\n            `key`: string\n                Name of the key to search for, or None if we reach the end of\n                the results\n            `result`: bool\n                Indicate True if the storage has been updated, or False if\n                nothing has been done (no changes). None if any error.\n        '''\n        self._schedule(self.store_find_async,\n                       callback=callback, filters=filters)\n\n    def keys(self):\n        '''Return a list of all the keys in the storage.\n        '''\n        return self.store_keys()\n\n    def async_keys(self, callback):\n        '''Asynchronously return all the keys in the storage.\n        '''\n        self._schedule(self.store_keys_async, callback=callback)\n\n    def count(self):\n        '''Return the number of entries in the storage.\n        '''\n        return self.store_count()\n\n    def async_count(self, callback):\n        '''Asynchronously return the number of entries in the storage.\n        '''\n        self._schedule(self.store_count_async, callback=callback)\n\n    def clear(self):\n        '''Wipe the whole storage.\n        '''\n        return self.store_clear()\n\n    def async_clear(self, callback):\n        '''Asynchronous version of :meth:`clear`.\n        '''\n        self._schedule(self.store_clear_async, callback=callback)\n\n    #\n    # Operators\n    #\n\n    def __setitem__(self, key, values):\n        if not isinstance(values, dict):\n            raise Exception('Only dict are accepted for the store[key] = dict')\n        self.put(key, **values)\n\n    def __getitem__(self, key):\n        return self.get(key)\n\n    def __delitem__(self, key):\n        return self.keys()\n\n    def __contains__(self, key):\n        return self.exists(key)\n\n    def __len__(self):\n        return self.count()\n\n    def __iter__(self):\n        for key in self.keys():\n            yield key\n\n    #\n    # Used for implementation\n    #\n\n    def store_load(self):\n        pass\n\n    def store_sync(self):\n        pass\n\n    def store_get(self, key):\n        raise NotImplemented()\n\n    def store_put(self, key, value):\n        raise NotImplemented()\n\n    def store_exists(self, key):\n        raise NotImplemented()\n\n    def store_delete(self, key):\n        raise NotImplemented()\n\n    def store_find(self, filters):\n        return []\n\n    def store_keys(self):\n        return []\n\n    def store_count(self):\n        return len(self.store_keys())\n\n    def store_clear(self):\n        for key in self.store_keys():\n            self.store_delete(key)\n\n    def store_get_async(self, key, callback):\n        try:\n            value = self.store_get(key)\n            callback(self, key, value)\n        except KeyError:\n            callback(self, key, None)\n\n    def store_put_async(self, key, value, callback):\n        try:\n            value = self.store_put(key, value)\n            callback(self, key, value)\n        except:\n            callback(self, key, None)\n\n    def store_exists_async(self, key, callback):\n        try:\n            value = self.store_exists(key)\n            callback(self, key, value)\n        except:\n            callback(self, key, None)\n\n    def store_delete_async(self, key, callback):\n        try:\n            value = self.store_delete(key)\n            callback(self, key, value)\n        except:\n            callback(self, key, None)\n\n    def store_find_async(self, filters, callback):\n        for key, entry in self.store_find(filters):\n            callback(self, filters, key, entry)\n        callback(self, filters, None, None)\n\n    def store_count_async(self, callback):\n        try:\n            value = self.store_count()\n            callback(self, value)\n        except:\n            callback(self, 0)\n\n    def store_keys_async(self, callback):\n        try:\n            keys = self.store_keys()\n            callback(self, keys)\n        except:\n            callback(self, [])\n\n    def store_clear_async(self, callback):\n        self.store_clear()\n        callback(self)\n\n    #\n    # Privates\n    #\n\n    def _schedule(self, cb, **kwargs):\n        # XXX not entirely sure about the best value (0 or -1).\n        Clock.schedule_once(partial(cb, **kwargs), 0)\n"
  },
  {
    "path": "tickeys/kivy/storage/dictstore.py",
    "content": "'''\nDictionary store\n=================\n\nUse a Python dictionary as a store.\n'''\n\n__all__ = ('DictStore', )\n\ntry:\n    import cPickle as pickle\nexcept ImportError:\n    import pickle\n\nfrom os.path import exists\nfrom kivy.compat import iteritems\nfrom kivy.storage import AbstractStore\n\n\nclass DictStore(AbstractStore):\n    '''Store implementation using a pickled `dict`.\n    See the :mod:`kivy.storage` module documentation for more information.\n    '''\n    def __init__(self, filename, data=None, **kwargs):\n        if isinstance(filename, dict):\n            # backward compatibility, first argument was a dict.\n            self.filename = None\n            self._data = filename\n        else:\n            self.filename = filename\n            self._data = data or {}\n        self._is_changed = True\n        super(DictStore, self).__init__(**kwargs)\n\n    def store_load(self):\n        if self.filename is None:\n            return\n        if not exists(self.filename):\n            return\n        with open(self.filename, 'rb') as fd:\n            data = fd.read()\n            if data:\n                self._data = pickle.loads(data)\n\n    def store_sync(self):\n        if self.filename is None:\n            return\n        if not self._is_changed:\n            return\n\n        with open(self.filename, 'wb') as fd:\n            pickle.dump(self._data, fd)\n\n        self._is_changed = False\n\n    def store_exists(self, key):\n        return key in self._data\n\n    def store_get(self, key):\n        return self._data[key]\n\n    def store_put(self, key, value):\n        self._data[key] = value\n        self._is_changed = True\n        return True\n\n    def store_delete(self, key):\n        del self._data[key]\n        self._is_changed = True\n        return True\n\n    def store_find(self, filters):\n        for key, values in iteritems(self._data):\n            found = True\n            for fkey, fvalue in iteritems(filters):\n                if fkey not in values:\n                    found = False\n                    break\n                if values[fkey] != fvalue:\n                    found = False\n                    break\n            if found:\n                yield key, values\n\n    def store_count(self):\n        return len(self._data)\n\n    def store_keys(self):\n        return self._data.keys()\n"
  },
  {
    "path": "tickeys/kivy/storage/jsonstore.py",
    "content": "'''\nJSON store\n==========\n\nCan be used to save/load key-value pairs from a json file.\n'''\n\n__all__ = ('JsonStore', )\n\n\nfrom os.path import exists\nfrom kivy.compat import iteritems\nfrom kivy.storage import AbstractStore\nfrom json import loads, dump\n\n\nclass JsonStore(AbstractStore):\n    '''Store implementation using a json file for storing the keys-value pairs.\n    See the :mod:`kivy.storage` module documentation for more information.\n    '''\n    def __init__(self, filename, **kwargs):\n        self.filename = filename\n        self._data = {}\n        self._is_changed = True\n        super(JsonStore, self).__init__(**kwargs)\n\n    def store_load(self):\n        if not exists(self.filename):\n            return\n        with open(self.filename) as fd:\n            data = fd.read()\n            if len(data) == 0:\n                return\n            self._data = loads(data)\n\n    def store_sync(self):\n        if self._is_changed is False:\n            return\n        with open(self.filename, 'w') as fd:\n            dump(self._data, fd)\n        self._is_changed = False\n\n    def store_exists(self, key):\n        return key in self._data\n\n    def store_get(self, key):\n        return self._data[key]\n\n    def store_put(self, key, value):\n        self._data[key] = value\n        self._is_changed = True\n        return True\n\n    def store_delete(self, key):\n        del self._data[key]\n        self._is_changed = True\n        return True\n\n    def store_find(self, filters):\n        for key, values in iteritems(self._data):\n            found = True\n            for fkey, fvalue in iteritems(filters):\n                if fkey not in values:\n                    found = False\n                    break\n                if values[fkey] != fvalue:\n                    found = False\n                    break\n            if found:\n                yield key, values\n\n    def store_count(self):\n        return len(self._data)\n\n    def store_keys(self):\n        return self._data.keys()\n"
  },
  {
    "path": "tickeys/kivy/storage/redisstore.py",
    "content": "'''\nRedis Store\n===========\n\nStore implementation using Redis. You must have redis-py installed.\n\nUsage example::\n\n    from kivy.storage.redisstore import RedisStore\n\n    params = dict(host='localhost', port=6379, db=14)\n    store = RedisStore(params)\n\nAll the key-value pairs will be stored with a prefix 'store' by default.\nYou can instanciate the storage with another prefix like this::\n\n\n    from kivy.storage.redisstore import RedisStore\n\n    params = dict(host='localhost', port=6379, db=14)\n    store = RedisStore(params, prefix='mystore2')\n\nThe params dictionary will be passed to the redis.StrictRedis class.\n\nSee `redis-py <https://github.com/andymccurdy/redis-py>`_.\n'''\n\n__all__ = ('RedisStore', )\n\nimport os\nfrom json import loads, dumps\nfrom kivy.properties import StringProperty\nfrom kivy.storage import AbstractStore\n\n# don't import redis during the documentation generation\nif 'KIVY_DOC' not in os.environ:\n    import redis\n\n\nclass RedisStore(AbstractStore):\n    '''Store implementation using a Redis database.\n    See the :mod:`kivy.storage` module documentation for more informations.\n    '''\n\n    prefix = StringProperty('store')\n\n    def __init__(self, redis_params, **kwargs):\n        self.redis_params = redis_params\n        self.r = None\n        super(RedisStore, self).__init__(**kwargs)\n\n    def store_load(self):\n        self.r = redis.StrictRedis(**self.redis_params)\n\n    def store_sync(self):\n        pass\n\n    def store_exists(self, key):\n        key = self.prefix + '.d.' + key\n        value = self.r.exists(key)\n        return value\n\n    def store_get(self, key):\n        key = self.prefix + '.d.' + key\n        if not self.r.exists(key):\n            raise KeyError(key)\n        result = self.r.hgetall(key)\n        for k in result.keys():\n            result[k] = loads(result[k])\n        return result\n\n    def store_put(self, key, values):\n        key = self.prefix + '.d.' + key\n        pipe = self.r.pipeline()\n        pipe.delete(key)\n        for k, v in values.iteritems():\n            pipe.hset(key, k, dumps(v))\n        pipe.execute()\n        return True\n\n    def store_delete(self, key):\n        key = self.prefix + '.d.' + key\n        if not self.r.exists(key):\n            raise KeyError(key)\n        return self.r.delete(key)\n\n    def store_keys(self):\n        l = len(self.prefix + '.d.')\n        return [x[l:] for x in self.r.keys(self.prefix + '.d.*')]\n\n    def store_find(self, filters):\n        fkeys = filters.keys()\n        fvalues = filters.values()\n        for key in self.store_keys():\n            skey = self.prefix + '.d.' + key\n            svalues = self.r.hmget(skey, fkeys)\n            if None in svalues:\n                continue\n            svalues = [loads(x) for x in svalues]\n            if fvalues != svalues:\n                continue\n            yield key, self.r.hgetall(skey)\n"
  },
  {
    "path": "tickeys/kivy/support.py",
    "content": "'''\nSupport\n=======\n\nActivate other frameworks/toolkits inside the kivy event loop.\n\n'''\n\n__all__ = ('install_gobject_iteration', 'install_twisted_reactor',\n           'uninstall_twisted_reactor', 'install_android')\n\n\ndef install_gobject_iteration():\n    '''Import and install gobject context iteration inside our event loop.\n    This is used as soon as gobject is used (like gstreamer).\n    '''\n\n    from kivy.clock import Clock\n\n    try:\n        from gi.repository import GObject as gobject\n    except ImportError:\n        import gobject\n\n    if hasattr(gobject, '_gobject_already_installed'):\n        # already installed, don't do it twice.\n        return\n\n    gobject._gobject_already_installed = True\n\n    # get gobject mainloop / context\n    loop = gobject.MainLoop()\n    gobject.threads_init()\n    context = loop.get_context()\n\n    # schedule the iteration each frame\n    def _gobject_iteration(*largs):\n        # XXX we need to loop over context here, otherwise, we might have a lag\n        loop = 0\n        while context.pending() and loop < 10:\n            context.iteration(False)\n            loop += 1\n    Clock.schedule_interval(_gobject_iteration, 0)\n\n\n# -----------------------------------------------------------------------------\n# Android support\n# -----------------------------------------------------------------------------\n\ng_android_redraw_count = 0\n\n\ndef _android_ask_redraw(*largs):\n    # after wakeup, we need to redraw more than once, otherwise we get a\n    # black screen\n    global g_android_redraw_count\n    from kivy.core.window import Window\n    Window.canvas.ask_update()\n    g_android_redraw_count -= 1\n    if g_android_redraw_count < 0:\n        return False\n\n\ndef install_android():\n    '''Install hooks for the android platform.\n\n    * Automatically sleep when the device is paused.\n    * Automatically kill the application when the return key is pressed.\n    '''\n    try:\n        import android\n    except ImportError:\n        print('Android lib is missing, cannot install android hooks')\n        return\n\n    from kivy.clock import Clock\n    from kivy.logger import Logger\n    import pygame\n\n    Logger.info('Support: Android install hooks')\n\n    # Init the library\n    android.init()\n    android.map_key(android.KEYCODE_MENU, pygame.K_MENU)\n    android.map_key(android.KEYCODE_BACK, pygame.K_ESCAPE)\n\n    # Check if android should be paused or not.\n    # If pause is requested, just leave the app.\n    def android_check_pause(*largs):\n        # do nothing until android asks for it.\n        if not android.check_pause():\n            return\n\n        from kivy.app import App\n        from kivy.base import stopTouchApp\n        from kivy.logger import Logger\n        from kivy.core.window import Window\n        global g_android_redraw_count\n\n        # try to get the current running application\n        Logger.info('Android: Must go into sleep mode, check the app')\n        app = App.get_running_app()\n\n        # no running application, stop our loop.\n        if app is None:\n            Logger.info('Android: No app running, stop everything.')\n            stopTouchApp()\n            return\n\n        # try to go to pause mode\n        if app.dispatch('on_pause'):\n            Logger.info('Android: App paused, now wait for resume.')\n\n            # app goes in pause mode, wait.\n            android.wait_for_resume()\n\n            # is it a stop or resume ?\n            if android.check_stop():\n                # app must stop\n                Logger.info('Android: Android wants to close our app.')\n                stopTouchApp()\n            else:\n                # app resuming now !\n                Logger.info('Android: Android has resumed, resume the app.')\n                app.dispatch('on_resume')\n                Window.canvas.ask_update()\n                g_android_redraw_count = 25  # 5 frames/seconds for 5 seconds\n                Clock.unschedule(_android_ask_redraw)\n                Clock.schedule_interval(_android_ask_redraw, 1 / 5)\n                Logger.info('Android: App resume completed.')\n\n        # app doesn't support pause mode, just stop it.\n        else:\n            Logger.info('Android: App doesn\\'t support pause mode, stop.')\n            stopTouchApp()\n\n    Clock.schedule_interval(android_check_pause, 0)\n\n\n_twisted_reactor_stopper = None\n_twisted_reactor_work = None\n\n\ndef install_twisted_reactor(**kwargs):\n    '''Installs a threaded twisted reactor, which will schedule one\n    reactor iteration before the next frame only when twisted needs\n    to do some work.\n\n    Any arguments or keyword arguments passed to this function will be\n    passed on the the threadedselect reactors interleave function. These\n    are the arguments one would usually pass to twisted's reactor.startRunning.\n\n    Unlike the default twisted reactor, the installed reactor will not handle\n    any signals unless you set the 'installSignalHandlers' keyword argument\n    to 1 explicitly. This is done to allow kivy to handle the signals as\n    usual unless you specifically want the twisted reactor to handle the\n    signals (e.g. SIGINT).\n\n    .. note::\n        Twisted is not included in iOS build by default. To use it on iOS,\n        put the twisted distribution (and zope.interface dependency) in your\n        application directory.\n    '''\n    import twisted\n\n    # prevent installing more than once\n    if hasattr(twisted, '_kivy_twisted_reactor_installed'):\n        return\n    twisted._kivy_twisted_reactor_installed = True\n\n    # don't let twisted handle signals, unless specifically requested\n    kwargs.setdefault('installSignalHandlers', 0)\n\n    # install threaded-select reactor, to use with own event loop\n    from twisted.internet import _threadedselect\n    _threadedselect.install()\n\n    # now we can import twisted reactor as usual\n    from twisted.internet import reactor\n    from twisted.internet.error import ReactorNotRunning\n\n    from collections import deque\n    from kivy.base import EventLoop\n    from kivy.logger import Logger\n    from kivy.clock import Clock\n\n    # will hold callbacks to twisted callbacks\n    q = deque()\n\n    # twisted will call the wake function when it needs to do work\n    def reactor_wake(twisted_loop_next):\n        '''Wakeup the twisted reactor to start processing the task queue\n        '''\n\n        Logger.trace(\"Support: twisted wakeup call to schedule task\")\n        q.append(twisted_loop_next)\n\n    # called every frame, to process the reactors work in main thread\n    def reactor_work(*args):\n        '''Process the twisted reactor task queue\n        '''\n        Logger.trace(\"Support: processing twisted task queue\")\n        while len(q):\n            q.popleft()()\n    global _twisted_reactor_work\n    _twisted_reactor_work = reactor_work\n\n    # start the reactor, by telling twisted how to wake, and process\n    def reactor_start(*args):\n        '''Start the twisted reactor main loop\n        '''\n        Logger.info(\"Support: Starting twisted reactor\")\n        reactor.interleave(reactor_wake, **kwargs)\n        Clock.schedule_interval(reactor_work, 0)\n\n    # make sure twisted reactor is shutdown if eventloop exists\n    def reactor_stop(*args):\n        '''Shutdown the twisted reactor main loop\n        '''\n        if reactor.threadpool:\n            Logger.info(\"Support: Stooping twisted threads\")\n            reactor.threadpool.stop()\n        Logger.info(\"Support: Shutting down twisted reactor\")\n        reactor._mainLoopShutdown()\n        try:\n            reactor.stop()\n        except ReactorNotRunning:\n            pass\n\n        import sys\n        sys.modules.pop('twisted.internet.reactor', None)\n\n    global _twisted_reactor_stopper\n    _twisted_reactor_stopper = reactor_stop\n\n    # start and stop the reactor along with kivy EventLoop\n    Clock.schedule_once(reactor_start, 0)\n    EventLoop.bind(on_stop=reactor_stop)\n\n\ndef uninstall_twisted_reactor():\n    '''Uninstalls the Kivy's threaded Twisted Reactor. No more Twisted\n    tasks will run after this got called. Use this to clean the\n    `twisted.internet.reactor` .\n\n    .. versionadded:: 1.9.0\n    '''\n\n    import twisted\n\n    # prevent uninstalling more than once\n    if not hasattr(twisted, '_kivy_twisted_reactor_installed'):\n        return\n\n    from kivy.base import EventLoop\n\n    global _twisted_reactor_stopper\n    _twisted_reactor_stopper()\n    EventLoop.unbind(on_stop=_twisted_reactor_stopper)\n\n    del twisted._kivy_twisted_reactor_installed\n"
  },
  {
    "path": "tickeys/kivy/tools/__init__.py",
    "content": ""
  },
  {
    "path": "tickeys/kivy/tools/benchmark.py",
    "content": "'''\nBenchmark\n=========\n\n'''\n\nfrom __future__ import print_function\n\nbenchmark_version = '1'\n\nimport os\nimport sys\nimport json\nimport kivy\nimport gc\nfrom time import clock, time, ctime\nfrom random import randint\n\nfrom kivy.uix.label import Label\nfrom kivy.uix.button import Button\nfrom kivy.uix.widget import Widget\nfrom kivy.graphics import RenderContext\nfrom kivy.input.motionevent import MotionEvent\nfrom kivy.cache import Cache\nfrom kivy.clock import Clock\nfrom kivy.compat import PY2\n\nif not PY2:\n    xrange = range\n\nclockfn = time\nif sys.platform == 'win32':\n    clockfn = clock\n\n\nclass FakeMotionEvent(MotionEvent):\n    pass\n\n\nclass bench_widget_creation:\n    '''Widget: creation (10000 Widget)'''\n\n    def run(self):\n        o = []\n        for x in range(10000):\n            o.append(Widget())\n\n\nclass bench_widget_creation_with_root:\n    '''Widget: creation (10000 Widget + 1 root)'''\n\n    def run(self):\n        o = Widget()\n        for x in range(10000):\n            o.add_widget(Widget())\n\n\nclass bench_widget_draw:\n    '''Widget: empty drawing (10000 Widget + 1 root)'''\n\n    def __init__(self):\n        self.ctx = RenderContext()\n        self.root = root = Widget()\n        for x in range(10000):\n            root.add_widget(Widget())\n        self.ctx.add(self.root.canvas)\n\n    def run(self):\n        self.ctx.draw()\n\n\nclass bench_widget_dispatch:\n    '''Widget: event dispatch (1000 on_update in 10*1000 Widget)'''\n\n    def __init__(self):\n        root = Widget()\n        for x in range(10):\n            parent = Widget()\n            for y in range(1000):\n                parent.add_widget(Widget())\n            root.add_widget(parent)\n        self.root = root\n\n    def run(self):\n        touch = FakeMotionEvent('fake', 1, [])\n        self.root.dispatch('on_touch_down', touch)\n        self.root.dispatch('on_touch_move', touch)\n        self.root.dispatch('on_touch_up', touch)\n\n\nclass bench_label_creation:\n    '''Core: label creation (10000 * 10 a-z)'''\n\n    def __init__(self):\n        labels = []\n        for x in range(10000):\n            label = [chr(randint(ord('a'), ord('z'))) for x in range(10)]\n            labels.append(''.join(label))\n        self.labels = labels\n\n    def run(self):\n        o = []\n        for x in self.labels:\n            o.append(Label(text=x))\n\n\nclass bench_button_creation:\n    '''Core: button creation (10000 * 10 a-z)'''\n\n    def __init__(self):\n        labels = []\n        for x in xrange(10000):\n            button = map(lambda x: chr(randint(ord('a'), ord('z'))), xrange(10))\n            labels.append(''.join(button))\n        self.labels = labels\n\n    def run(self):\n        o = []\n        for x in self.labels:\n            o.append(Button(text=x))\n\n\nclass bench_label_creation_with_tick:\n    '''Core: label creation (10000 * 10 a-z), with Clock.tick'''\n\n    def __init__(self):\n        labels = []\n        for x in range(10000):\n            label = [chr(randint(ord('a'), ord('z'))) for x in range(10)]\n            labels.append(''.join(label))\n        self.labels = labels\n\n    def run(self):\n        o = []\n        for x in self.labels:\n            o.append(Label(text=x))\n        # tick for texture creation\n        Clock.tick()\n\n\nclass bench_button_creation_with_tick:\n    '''Core: button creation (10000 * 10 a-z), with Clock.tick'''\n\n    def __init__(self):\n        labels = []\n        for x in xrange(10000):\n            button = map(lambda x: chr(randint(ord('a'), ord('z'))), xrange(10))\n            labels.append(''.join(button))\n        self.labels = labels\n\n    def run(self):\n        o = []\n        for x in self.labels:\n            o.append(Button(text=x))\n        # tick for texture creation\n        Clock.tick()\n\n\nif __name__ == '__main__':\n\n    report = []\n    report_newline = True\n\n    def log(s, newline=True):\n        global report_newline\n        if not report_newline:\n            report[-1] = '%s %s' % (report[-1], s)\n        else:\n            report.append(s)\n        if newline:\n            print(s)\n            report_newline = True\n        else:\n            print(s, end=' ')\n            report_newline = False\n        sys.stdout.flush()\n\n    clock_total = 0\n    benchs = list(globals().keys())\n    benchs.sort()\n    benchs = [globals()[x] for x in benchs if x.startswith('bench_')]\n\n    log('')\n    log('=' * 70)\n    log('Kivy Benchmark v%s' % benchmark_version)\n    log('=' * 70)\n    log('')\n    log('System informations')\n    log('-------------------')\n\n    log('OS platform     : %s' % sys.platform)\n    log('Python EXE      : %s' % sys.executable)\n    log('Python Version  : %s' % sys.version)\n    log('Python API      : %s' % sys.api_version)\n    log('Kivy Version    : %s' % kivy.__version__)\n    log('Install path    : %s' % os.path.dirname(kivy.__file__))\n    log('Install date    : %s' % ctime(os.path.getctime(kivy.__file__)))\n\n    log('')\n    log('OpenGL informations')\n    log('-------------------')\n\n    from kivy.core.gl import glGetString, GL_VENDOR, GL_RENDERER, GL_VERSION\n    log('GL Vendor: %s' % glGetString(GL_VENDOR))\n    log('GL Renderer: %s' % glGetString(GL_RENDERER))\n    log('GL Version: %s' % glGetString(GL_VERSION))\n    log('')\n\n    log('Benchmark')\n    log('---------')\n\n    for x in benchs:\n        # clean cache to prevent weird case\n        for cat in Cache._categories:\n            Cache.remove(cat)\n\n        # force gc before next test\n        gc.collect()\n\n        log('%2d/%-2d %-60s' % (benchs.index(x) + 1,\n            len(benchs), x.__doc__), False)\n        try:\n            sys.stderr.write('.')\n            test = x()\n        except Exception as e:\n            log('failed %s' % str(e))\n            import traceback\n            traceback.print_exc()\n            continue\n\n        clock_start = clockfn()\n\n        try:\n            sys.stderr.write('.')\n            test.run()\n            clock_end = clockfn() - clock_start\n            log('%.6f' % clock_end)\n        except Exception as e:\n            log('failed %s' % str(e))\n            continue\n\n        clock_total += clock_end\n\n    log('')\n    log('Result: %.6f' % clock_total)\n    log('')\n\ntry:\n    reply = input(\n        'Do you want to send benchmark to gist.github.com (Y/n) : ')\nexcept EOFError:\n    sys.exit(0)\n\nif reply.lower().strip() in ('', 'y'):\n    print('Please wait while sending the benchmark...')\n\n    try:\n        import requests\n    except ImportError:\n        print(\"`requests` module not found, no benchmark posted.\")\n        sys.exit(1)\n\n    payload = {\n        'public': True, 'files': {\n            'benchmark.txt': {\n                'content': '\\n'.join(report)}}}\n\n    r = requests.post('https://api.github.com/gists', data=json.dumps(payload))\n\n    print()\n    print()\n    print('REPORT posted at {0}'.format(r.json['html_url']))\n    print()\n    print()\nelse:\n    print('No benchmark posted.')\n"
  },
  {
    "path": "tickeys/kivy/tools/extensions/__init__.py",
    "content": ""
  },
  {
    "path": "tickeys/kivy/tools/extensions/make-kivyext.py",
    "content": "#!/usr/bin/env python\n\"\"\"\n    make-kivyext\n    ~~~~~~~~~~~~~\n\n    Little helper script that helps creating new Kivy extensions.\n    To use it, just run it::\n\n        python make-kivyext.py\n\n    :copyright: (c) 2011: Adjusted by the Kivy Authors,\n                    2010: Courtesy of Armin Ronacher\n                          (Originally developed for flask.pocoo.org)\n    :license: BSD, see LICENSE for more details.\n\"\"\"\n\nimport re\nimport os\nimport sys\nimport getpass\nfrom datetime import datetime\nfrom urllib.parse import quote\n\n\n_sep_re = re.compile(r'[\\s.,;_-]+')\n\n\nFILE_HEADER_TEMPLATE = '''\\\n# -*- coding: utf-8 -*-\n\"\"\"\n    %(module)s\n    %(moduledecor)s\n\n    Please describe your extension here...\n\n    :copyright: (c) %(year)s by %(name)s.\n\"\"\"\n'''\n\nSETUP_PY_TEMPLATE = '''\\\n\"\"\"\n%(name)s\n%(namedecor)s\n\nTo create a Kivy *.kex extension file for this extension, run this file like\nso::\n\n    python setup.py create_package\n\nThat will turn your current Kivy extension development folder into a *.kex Kivy\nextension file that you can just drop in one of the extensions/ directories\nsupported by Kivy.\n\"\"\"\nfrom distutils.core import setup\nfrom distutils.cmd import Command\n\nimport %(extname)s\nlong_desc = %(extname)s.__doc__\n\n\nimport os\nfrom os.path import join\nfrom shutil import copy\nfrom subprocess import call\nimport sys\n\n\nclass PackageBuild(Command):\n    description = 'Create Extension Package'\n    user_options = []\n\n    def run(self):\n        # Call this file and make a distributable .zip file that has our desired\n        # folder structure\n        call([sys.executable, 'setup.py', 'install', '--root', 'output/',\n            '--install-lib', '/', '--install-platlib', '/', '--install-data',\n            '/%(extname)s/data', 'bdist', '--formats=zip'])\n        files = os.listdir('dist')\n        if not os.path.isdir('kexfiles'):\n            os.mkdir('kexfiles')\n        for file in files:\n            # Simply copy & replace...\n            copy(join('dist', file), join('kexfiles', file[:-3] + \"kex\"))\n        print('The extension files are now available in kexfiles/')\n\n    def initialize_options(self):\n        pass\n\n    def finalize_options(self):\n        pass\n\n\ncmdclass = {'create_package': PackageBuild}\n\n\nsetup(\n    name='%(name)s',\n    version='0.1',\n    url='<enter URL here>',\n    license='<specify license here>',\n    author='%(author)s',\n    author_email='%(email)s',\n    description='<enter short description here>',\n    long_description=long_desc,\n    packages=['%(extname)s'],\n    cmdclass=cmdclass,\n    classifiers=[\n        # Add your own classifiers here\n        'Development Status :: 4 - Beta',\n        'Intended Audience :: Developers',\n        'Operating System :: OS Independent',\n        'Programming Language :: Python',\n        'Topic :: Software Development :: Libraries :: Python Modules'\n    ]\n)\n'''\n\n\ndef prompt(name, default=None):\n    prompt = name + (default and ' [%s]' % default or '')\n    prompt += name.endswith('?') and ' ' or ': '\n    while True:\n        rv = input(prompt)\n        if rv:\n            return rv\n        if default is not None:\n            return default\n\n\ndef prompt_bool(name, default=False):\n    while True:\n        rv = prompt(name + '?', default and 'Y' or 'N')\n        if not rv:\n            return default\n        if rv.lower() in ('y', 'yes', '1', 'on', 'true', 't'):\n            return True\n        elif rv.lower() in ('n', 'no', '0', 'off', 'false', 'f'):\n            return False\n\n\ndef prompt_choices(name, choices):\n    while True:\n        rv = prompt(name + '? - (%s)' % ', '.join(choices), choices[0])\n        rv = rv.lower()\n        if not rv:\n            return choices[0]\n        if rv in choices:\n            if rv == 'none':\n                return None\n            else:\n                return rv\n\n\ndef guess_package(name):\n    \"\"\"Guess the package name\"\"\"\n    words = [x.lower() for x in _sep_re.split(name)]\n    return '_'.join(words) or None\n\n\nclass Extension(object):\n\n    def __init__(self, name, shortname, author, email, output_folder):\n        self.name = name\n        self.shortname = shortname\n        self.author = author\n        self.email = email\n        self.output_folder = output_folder\n\n    def make_folder(self):\n        root = os.path.join(self.output_folder, self.shortname)\n        os.makedirs(root)\n        os.mkdir(os.path.join(root, 'data'))\n\n    def create_files(self):\n        decor = '~' * len(self.shortname)\n        with open(os.path.join(self.output_folder, self.shortname,\n                               '__init__.py'), 'w') as f:\n            f.write(FILE_HEADER_TEMPLATE % dict(\n                module=self.shortname,\n                moduledecor=decor,\n                year=datetime.utcnow().year,\n                name=self.author,\n            ))\n        with open(os.path.join(self.output_folder, 'setup.py'), 'w') as f:\n            f.write(SETUP_PY_TEMPLATE % dict(\n                name=self.name,\n                namedecor='~' * len(self.name),\n                urlname=quote(self.name),\n                author=self.author,\n                extname=self.shortname,\n                email=self.email,\n            ))\n\n\ndef main():\n    if len(sys.argv) not in (1, 2):\n        print('usage: make-kivyext.py [output-folder]')\n        return\n    msg = 'Welcome to the Kivy Extension Creator Wizard'\n    print(msg)\n    print('~' * len(msg))\n\n    name = prompt('Extension Name (human readable)')\n    shortname = prompt('Extension Name (for filesystem)', guess_package(name))\n    author = prompt('Author', default=getpass.getuser())\n    email = prompt('EMail', default='')\n\n    output_folder = len(sys.argv) == 2 and sys.argv[1] or shortname + '-dev'\n    while 1:\n        folder = prompt('Output folder', default=output_folder)\n        if os.path.isfile(folder):\n            print('Error: output folder is a file')\n        elif os.path.isdir(folder) and os.listdir(folder):\n            if prompt_bool('Warning: output folder is not empty. Continue'):\n                break\n        else:\n            break\n    output_folder = os.path.abspath(folder)\n\n    ext = Extension(name, shortname, author, email, output_folder)\n    ext.make_folder()\n    ext.create_files()\n    msg = '''\n    Congratulations!\n    Your initial Kivy extension code skeleton has been created in:\n        %(output_folder)s\n    The next step is to look at the files that have been created and to\n    populate the placeholder values. Obviously you will also need to add the\n    actual extension code.\n    ''' % dict(output_folder=output_folder)\n    print(msg)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "tickeys/kivy/tools/generate-icons.py",
    "content": "#!/usr/bin/env python\n'''\nIcon generator\n==============\n\nThis tool will help you to generate all the icons wanted for Google Play Store,\nApp Store, Amazon store.\n'''\n\nimport sys\nfrom PIL import Image\nfrom os.path import exists, join, realpath, basename, dirname\nfrom os import makedirs\nfrom argparse import ArgumentParser\n\n\nclass Converter(object):\n\n    converters = {\n        'appstore': {\n            'directory_name': 'ios',\n            'sizes': [\n                ('App store high resolution', '{}-appstore-1024.png', 1024),\n                ('App store normal resolution', '{}-appstore-512.png', 512),\n                # iOS 7\n                ('iPhone (iOS 7)', '{}-60.png', 120),\n                ('iPhone @2 (iOS 7)', '{}-60@2x.png', 120),\n                ('iPad (iOS 7)', '{}-76.png', 76),\n                ('iPad @2 (iOS 7)', '{}-60@2x.png', 152),\n                # iOS 6.1 and earlier\n                ('iPhone (iOS >= 6.1)', '{}-57.png', 57),\n                ('iPhone @2 (iOS >= 6.1)', '{}-57@2x.png', 114),\n                ('iPad (iOS >= 6.1)', '{}-72.png', 72),\n                ('iPad @2 (iOS >= 6.1)', '{}-72@2x.png', 114),\n                # iTunes artwork (ad-hoc)\n                ('iTunes Artwork (ad-hoc)', 'iTunesArtwork', 512),\n                ('iTunes Artwork @2 (ad-hoc)', 'iTunesArtwork@2x', 1024),\n            ]},\n        'playstore': {\n            'directory_name': 'android',\n            'sizes': [\n                ('Google Play icon', '{}-googleplay-512.png', 512),\n                ('Launcher icon MDPI', '{}-48.png', 48),\n                ('Launcher icon HDPI', '{}-72.png', 72),\n                ('Launcher icon XHDPI', '{}-96.png', 96),\n                ('Launcher icon XXHDPI', '{}-144.png', 48),\n                ('Launcher icon XXXHDPI', '{}-192.png', 192),\n            ]},\n        'amazonstore': {\n            'directory_name': 'amazon',\n            'sizes': [\n                ('Small icon', '{}-114.png', 114),\n                ('Large icon', '{}-512.png', 512),\n            ]}}\n\n    def run(self):\n        parser = ArgumentParser(\n                description='Generate icons for various stores')\n        parser.add_argument('--dir', type=str, default=None,\n                help=('Output directory to generate all the icons,'\n                      'defaults to the directory of the source icon'))\n        parser.add_argument('--force', type=bool, default=False,\n                help=('Generate all icons even if the source is not perfect.'))\n        parser.add_argument('icon', type=str,\n                help='Base icon (must be 1024x1024 or 512x512)')\n\n        args = parser.parse_args()\n        if not exists(args.icon):\n            print('Error: No such icon file')\n            sys.exit(1)\n\n        # ensure the destination directory will be set\n        if args.dir is None:\n            args.dir = dirname(args.icon)\n\n        # read the source image, and do some quality checks\n        base_fn = basename(args.icon).rsplit('.', 1)[0]\n        source = Image.open(args.icon)\n        self.ensure_quality(source, args.force)\n\n        for directory_name, sizeinfo in self.iterate():\n            description, pattern_fn, size = sizeinfo\n            print('Generate {}: {}x{}'.format(description, size, size))\n            dest_dir = realpath(join(args.dir, directory_name))\n            if not exists(dest_dir):\n                makedirs(dest_dir)\n            icon_fn = join(dest_dir, pattern_fn.format('Icon'))\n            self.convert_to(source, icon_fn, size)\n\n    def convert_to(self, source, icon_fn, size):\n        dest = source.resize((size, size))\n        dest.save(icon_fn, 'png')\n\n    def ensure_quality(self, image, force=False):\n        messages = []\n        w, h = image.size\n        if w != h:\n            messages.append('Width and height should be the same')\n        if w not in (512, 1024):\n            messages.append(\n                'Source image is recommended to be 1024 (512 minimum)')\n        if not messages:\n            return\n\n        print('Quality check failed')\n        for message in messages:\n            print('- {}'.format(message))\n        if not force:\n            sys.exit(1)\n\n    def iterate(self):\n        for store, infos in Converter.converters.items():\n            for size in infos['sizes']:\n                yield infos['directory_name'], size\n\n\nif __name__ == '__main__':\n    Converter().run()\n"
  },
  {
    "path": "tickeys/kivy/tools/highlight/__init__.py",
    "content": ""
  },
  {
    "path": "tickeys/kivy/tools/highlight/kivy-mode.el",
    "content": ";;; kivy-mode.el --- Emacs major mode for editing Kivy files\n;;\n;; Author: Dean Serenevy <dean@serenevy.net>\n;; Version: 0.1.0\n;;\n;; This document borrowed heavily from yaml-mode.el by Yoshiki Kurihara and\n;; Marshall Vandegrift.\n;;\n;; This file is not part of Emacs\n\n\n;; This file is free software; you can redistribute it and/or modify it\n;; under the terms of the GNU General Public License as published by the\n;; Free Software Foundation; version 3.\n\n;; This file is distributed in the hope that it will be useful, but WITHOUT\n;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\n;; more details.\n\n;; You should have received a copy of the GNU General Public License along\n;; with GNU Emacs; see the file COPYING. If not, write to the Free Software\n;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,\n;; USA.\n\n;;; Installation:\n\n;; To install, just drop this file into a directory in your `load-path' and\n;; (optionally) byte-compile it. To automatically handle files ending in\n;; '.kv', add something like:\n;;\n;;    (require 'kivy-mode)\n;;    (add-to-list 'auto-mode-alist '(\"\\\\.kv$\" . kivy-mode))\n;;\n;; to your .emacs file.\n;;\n;; Unlike python-mode, this mode follows the Emacs convention of not\n;; binding the ENTER key to `newline-and-indent'. To get this behavior, add\n;; the key definition to `kivy-mode-hook':\n;;\n;;    (add-hook 'kivy-mode-hook\n;;     '(lambda ()\n;;        (define-key kivy-mode-map \"\\C-m\" 'newline-and-indent)))\n\n\n;; User definable variables\n\n(defgroup kivy nil\n  \"Support for the kivy user interface definition format\"\n  :group 'languages\n  :prefix \"kivy-\")\n\n(defcustom kivy-mode-hook nil\n  \"*Hook run by `kivy-mode'.\"\n  :type 'hook\n  :group 'kivy)\n\n(defcustom kivy-indent-offset 4\n  \"*Amount of offset per level of indentation.\"\n  :type 'integer\n  :group 'kivy)\n\n(defcustom kivy-backspace-function 'backward-delete-char-untabify\n  \"*Function called by `kivy-electric-backspace' when deleting backwards.\"\n  :type 'function\n  :group 'kivy)\n\n(defface kivy-tab-face\n  '((((class color)) (:background \"red\" :foreground \"red\" :bold t))\n    (t (:reverse-video t)))\n  \"Face to use for highlighting tabs in kivy files.\"\n  :group 'faces\n  :group 'kivy)\n\n(defcustom kivy-imenu-generic-expression\n  '((nil  \"^\\\\([<>a-zA-Z_-]+\\\\):\"          1))\n  \"The imenu regex to parse an outline of the kivy file.\"\n  :type 'string\n  :group 'kivy)\n\n\n;; Constants\n\n(defconst kivy-mode-version \"0.1.0\" \"Version of `kivy-mode.'\")\n\n(defconst kivy-blank-line-re \"^ *$\"\n  \"Regexp matching a line containing only (valid) whitespace.\")\n\n(defconst kivy-comment-re \"\\\\(?:^\\\\|\\\\s-+\\\\)\\\\(#.*\\\\)\"\n  \"Regexp matching a line containing a kivy comment or delimiter.\")\n\n(defconst kivy-directive-re \"^\\\\(?:#:\\\\)\\\\(\\\\w+ +.*\\\\)\"\n  \"Regexp matching a line contatining a kivy directive.\")\n\n(defconst kivy-tag-re \"^ *id: *\\\\([^ \\n]+\\\\)$\"\n  \"Rexexp matching a kivy tag.\")\n\n(defconst kivy-bare-scalar-re\n  \"\\\\(?:[^-:,#!\\n{\\\\[ ]\\\\|[^#!\\n{\\\\[ ]\\\\S-\\\\)[^#\\n]*?\"\n  \"Rexexp matching a kivy bare scalar.\")\n\n(defconst kivy-hash-key-re\n  (concat \"^ *\"\n          \"\\\\(\" kivy-bare-scalar-re \"\\\\) *:\"\n          \"\\\\(?: +\\\\|$\\\\)\")\n  \"Regexp matching a single kivy hash key.\")\n\n(defconst kivy-nested-map-re\n  (concat \".*: *$\")\n  \"Regexp matching a line beginning a kivy nested structure.\")\n\n(defconst kivy-constant-scalars-re\n  (concat \"\\\\(?:^\\\\|\\\\(?::\\\\|-\\\\|,\\\\|{\\\\|\\\\[\\\\) +\\\\) *\"\n          (regexp-opt\n           '(\"True\" \"False\" \"None\") t)\n          \" *$\")\n  \"Regexp matching certain scalar constants in scalar context\")\n\n\n\n;; Mode setup\n\n(defvar kivy-mode-map ()\n  \"Keymap used in `kivy-mode' buffers.\")\n(if kivy-mode-map\n    nil\n  (setq kivy-mode-map (make-sparse-keymap))\n  (define-key kivy-mode-map [backspace] 'kivy-electric-backspace)\n  (define-key kivy-mode-map \"\\C-c<\" 'kivy-indent-shift-left)\n  (define-key kivy-mode-map \"\\C-c>\" 'kivy-indent-shift-right)\n  )\n\n(defvar kivy-mode-syntax-table nil\n  \"Syntax table in use in kivy-mode buffers.\")\n(if kivy-mode-syntax-table\n    nil\n  (setq kivy-mode-syntax-table (make-syntax-table))\n  (modify-syntax-entry ?\\' \"\\\"\" kivy-mode-syntax-table)\n  (modify-syntax-entry ?\\\" \"\\\"\" kivy-mode-syntax-table)\n  (modify-syntax-entry ?# \"<\" kivy-mode-syntax-table)\n  (modify-syntax-entry ?\\n \">\" kivy-mode-syntax-table)\n  (modify-syntax-entry ?\\\\ \"\\\\\" kivy-mode-syntax-table)\n  (modify-syntax-entry ?- \"_\" kivy-mode-syntax-table)\n  (modify-syntax-entry ?_ \"w\" kivy-mode-syntax-table)\n  )\n\n\n;;;###autoload\n(add-to-list 'auto-mode-alist '(\"\\\\.kv$\" . kivy-mode))\n\n\n;;;###autoload\n(define-derived-mode kivy-mode fundamental-mode \"kivy\"\n  \"Simple mode to edit kivy.\n\n\\\\{kivy-mode-map}\"\n  (set (make-local-variable 'comment-start) \"# \")\n  (set (make-local-variable 'comment-start-skip) \"#+ *\")\n  (set (make-local-variable 'indent-line-function) 'kivy-indent-line)\n  (set (make-local-variable 'font-lock-defaults)\n       '(kivy-font-lock-keywords\n         nil nil nil nil\n         (font-lock-syntactic-keywords))))\n\n\n;; Font-lock support\n\n(defvar kivy-font-lock-keywords\n  (list\n   (cons kivy-comment-re '(1 font-lock-comment-face))\n   (cons kivy-constant-scalars-re '(1 font-lock-constant-face))\n   (cons kivy-tag-re '(1 font-lock-function-name-face))\n   (cons kivy-hash-key-re '(1 font-lock-variable-name-face t))\n   (cons kivy-directive-re '(1 font-lock-builtin-face))\n   '(\"^[\\t]+\" 0 'kivy-tab-face t))\n  \"Additional expressions to highlight in kivy mode.\")\n\n(defvar kivy-font-lock-syntactic-keywords\n  (list '())\n  \"Additional syntax features to highlight in kivy mode.\")\n\n\n;; Indentation and electric keys\n\n(defun kivy-compute-indentation ()\n  \"Calculate the maximum sensible indentation for the current line.\"\n  (save-excursion\n    (beginning-of-line)\n    (forward-line -1)\n    (while (and (looking-at kivy-blank-line-re)\n                (> (point) (point-min)))\n      (forward-line -1))\n    (+ (current-indentation)\n       (if (looking-at kivy-nested-map-re) kivy-indent-offset 0)\n       )))\n\n(defun kivy-indent-line ()\n  \"Indent the current line.\nThe first time this command is used, the line will be indented to the\nmaximum sensible indentation.  Each immediately subsequent usage will\nback-dent the line by `kivy-indent-offset' spaces.  On reaching column\n0, it will cycle back to the maximum sensible indentation.\"\n  (interactive \"*\")\n  (let ((ci (current-indentation))\n        (cc (current-column))\n        (need (kivy-compute-indentation)))\n    (save-excursion\n      (beginning-of-line)\n      (delete-horizontal-space)\n      (if (and (equal last-command this-command) (/= ci 0))\n          (indent-to (* (/ (- ci 1) kivy-indent-offset) kivy-indent-offset))\n        (indent-to need)))\n    (if (< (current-column) (current-indentation))\n        (forward-to-indentation 0))))\n\n(defun kivy-electric-backspace (arg)\n  \"Delete characters or back-dent the current line.\nIf invoked following only whitespace on a line, will back-dent to the\nimmediately previous multiple of `kivy-indent-offset' spaces.\"\n  (interactive \"*p\")\n  (if (or (/= (current-indentation) (current-column)) (bolp))\n      (funcall kivy-backspace-function arg)\n    (let ((ci (current-column)))\n      (beginning-of-line)\n      (delete-horizontal-space)\n      (indent-to (* (/ (- ci (* arg kivy-indent-offset))\n                       kivy-indent-offset)\n                    kivy-indent-offset)))))\n\n\n(defun kivy-set-imenu-generic-expression ()\n  (make-local-variable 'imenu-generic-expression)\n  (make-local-variable 'imenu-create-index-function)\n  (setq imenu-create-index-function 'imenu-default-create-index-function)\n  (setq imenu-generic-expression kivy-imenu-generic-expression))\n\n(add-hook 'kivy-mode-hook 'kivy-set-imenu-generic-expression)\n(add-hook 'kivy-mode-hook\n          '(lambda ()\n             (setq indent-tabs-mode 'nil)))\n\n\n(defun kivy-mode-version ()\n  \"Diplay version of `kivy-mode'.\"\n  (interactive)\n  (message \"kivy-mode %s\" kivy-mode-version)\n  kivy-mode-version)\n\n(defun kivy-indent-shift-left (start end &optional count)\n  \"Shift lines contained in region START END by COUNT columns to the left.\nCOUNT defaults to `kivy-indent-offset'.  If region isn't\nactive, the current line is shifted.  The shifted region includes\nthe lines in which START and END lie.  An error is signaled if\nany lines in the region are indented less than COUNT columns.\"\n  (interactive\n   (if mark-active\n       (list (region-beginning) (region-end) current-prefix-arg)\n     (list (line-beginning-position) (line-end-position) current-prefix-arg)))\n  (if count\n      (setq count (prefix-numeric-value count))\n    (setq count kivy-indent-offset))\n  (when (> count 0)\n    (let ((deactivate-mark nil))\n      (save-excursion\n        (goto-char start)\n        (while (< (point) end)\n          (if (and (< (current-indentation) count)\n                   (not (looking-at \"[ \\t]*$\")))\n              (error \"Can't shift all lines enough\"))\n          (forward-line))\n        (indent-rigidly start end (- count))))))\n\n(defun kivy-indent-shift-right (start end &optional count)\n  \"Shift lines contained in region START END by COUNT columns to the left.\nCOUNT defaults to `kivy-indent-offset'.  If region isn't\nactive, the current line is shifted.  The shifted region includes\nthe lines in which START and END lie.\"\n  (interactive\n   (if mark-active\n       (list (region-beginning) (region-end) current-prefix-arg)\n     (list (line-beginning-position) (line-end-position) current-prefix-arg)))\n  (let ((deactivate-mark nil))\n    (if count\n        (setq count (prefix-numeric-value count))\n      (setq count kivy-indent-offset))\n    (indent-rigidly start end count)))\n\n(provide 'kivy-mode)\n\n;;; kivy-mode.el ends here\n"
  },
  {
    "path": "tickeys/kivy/tools/highlight/kivy.vim",
    "content": "\" Vim syntax file\n\" Language:\tKivy\n\" Maintainer:\tGeorge Sebastian <11george.s@gmail.com>\n\" Last Change:\t2011 May 1\n\n\" For version 5.x: Clear all syntax items.\n\" For version 6.x: Quit when a syntax file was already loaded.\nif version < 600\n  syntax clear\nelseif exists(\"b:current_syntax\")\n  finish\nendif\n\nsyn match kivyPreProc       /#:.*/\nsyn match kivyComment       /#.*/\nsyn match kivyRule          /<\\I\\i*\\(,\\s*\\I\\i*\\)*>:/\nsyn match kivyAttribute     /\\<\\I\\i*\\>/ nextgroup=kivyValue\n\nsyn include @pyth $VIMRUNTIME/syntax/python.vim\nsyn region kivyValue start=\":\" end=/$/  contains=@pyth skipwhite\n\nsyn region kivyAttribute matchgroup=kivyIdent start=/[\\a_][\\a\\d_]*:/ end=/$/ contains=@pyth skipwhite\n\nif version >= 508 || !exists(\"did_python_syn_inits\")\n  if version <= 508\n    let did_python_syn_inits = 1\n    command -nargs=+ HiLink hi link <args>\n  else\n    command -nargs=+ HiLink hi def link <args>\n  endif\n\n    HiLink kivyPreproc      PreProc\n    HiLink kivyComment      Comment\n    HiLink kivyRule         Function\n    HiLink kivyIdent        Statement\n    HiLink kivyAttribute    Label\n  delcommand HiLink\nendif\n"
  },
  {
    "path": "tickeys/kivy/tools/packaging/README.txt",
    "content": "The files in the win32 and osx subdirectories are \nsource and resource files that are used in the respective \nportable packaged versions of kivy for each OS.  Here, they\nare under version controll.  \n\nsetup.py copies these files into the portable distribution \npackage that is created when you launch \n'setup.py build_portable'\n\n\nFor example the win32 dir has the READMEand bat file which \nsets up the ENV variables and launches the python interpreter.\n"
  },
  {
    "path": "tickeys/kivy/tools/packaging/__init__.py",
    "content": ""
  },
  {
    "path": "tickeys/kivy/tools/packaging/factory.py",
    "content": "from __future__ import print_function\n\n__all__ = ('FactoryBuild', )\n\nfrom distutils.cmd import Command\nimport fnmatch\nimport os\nimport kivy\nimport types\n\nignore_list = (\n    'kivy.lib',\n    'kivy.input.providers',\n    'kivy.input.postproc',\n    'kivy.modules',\n    'kivy.tools',\n    'kivy.parser',\n    'kivy.tests',\n)\n\n\nclass FactoryBuild(Command):\n    description = 'Build the factory relation file (for factory.py)'\n    user_options = []\n\n    def initialize_options(self):\n        pass\n\n    def finalize_options(self):\n        pass\n\n    def run(self):\n        print('--------------------------------------------')\n        print('Building factory relation file')\n        print('--------------------------------------------')\n\n        root_dir = os.path.dirname(kivy.__file__)\n        filename = os.path.join(root_dir, 'factory_registers.py')\n        with open(filename, 'w') as fd:\n            fd.close()\n\n        # ensure we don't have any thing like doc running\n        symbols = []\n        for root, dirnames, filenames in os.walk(root_dir):\n            if not root.startswith(root_dir):\n                raise Exception('Directory should start with the kivy'\n                                'directory')\n            root = 'kivy' + root[len(root_dir):].replace(os.path.sep, '.')\n            for filename in fnmatch.filter(filenames, '*.[ps][yo]'):\n                module = '%s.%s' % (root, filename[:-3])\n\n                # check ignore list first\n                ignore = False\n                for ignore in ignore_list:\n                    if module.startswith(ignore):\n                        ignore = True\n                        break\n                if ignore is True:\n                    #print('<<< ignored (ignore list)')\n                    continue\n\n                # special case, core providers\n                if root.startswith('kivy.core.'):\n                    if not root.endswith('__init__.py'):\n                        #print('<<< ignored (not a __init__.py)')\n                        continue\n\n                print('>>>', module, '::', end=' ')\n\n                try:\n                    m = __import__(name=module, fromlist='.')\n                except Exception as e:\n                    print()\n                    print('ERROR:', e)\n                    continue\n                if not hasattr(m, '__all__'):\n                    print()\n                    continue\n                for symbol in getattr(m, '__all__'):\n                    if symbol.startswith('_'):\n                        continue\n                    attr = getattr(m, symbol)\n                    if type(attr) not in (type, type):\n                        continue\n                    symbols.append((symbol, module))\n                    print(symbol, end=' ')\n                print()\n\n        print()\n        print('--------------------------------------------')\n        print('Found %d symbols, generating file' % len(symbols))\n        print('--------------------------------------------')\n\n        filename = os.path.join(root_dir, 'factory_registers.py')\n        with open(filename, 'w') as fd:\n            fd.write('# Auto-generated file by setup.py build_factory\\n')\n            fd.write('\\n')\n            fd.write('from kivy.factory import Factory\\n')\n            fd.write('\\n')\n            fd.write('r = Factory.register\\n')\n            for x in symbols:\n                fd.write(\"r('%s', module='%s')\\n\" % x)\n\n        print('File written at', filename)\n"
  },
  {
    "path": "tickeys/kivy/tools/packaging/osx/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>English</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>Kivy</string>\n\t<key>CFBundleDocumentTypes</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>CFBundleTypeExtensions</key>\n\t\t\t<array>\n\t\t\t\t<string>*</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeOSTypes</key>\n\t\t\t<array>\n\t\t\t\t<string>****</string>\n\t\t\t\t<string>fold</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeRole</key>\n\t\t\t<string>Viewer</string>\n\t\t</dict>\n\t</array>\n\t<key>CFBundleExecutable</key>\n\t<string>Kivy</string>\n\t<key>CFBundleGetInfoString</key>\n\t<string>Kivy {{__VERSION__}} Copyright {{__YEAR__}} Kivy Maintainers</string>\n\t<key>CFBundleIconFile</key>\n\t<string>appIcon.icns</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>org.kivy</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>Kivy</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>{{__VERSION__}}</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>LSEnvironment</key>\n\t<dict/>\n\t<key>LSHasLocalizedDisplayName</key>\n\t<false/>\n\t<key>LSMinimumSystemVersion</key>\n\t<string>10.6</string>\n\t<key>LSUIElement</key>\n\t<false/>\n\t<key>NSAppleScriptEnabled</key>\n\t<false/>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Kivy {{__VERSION__}} Copyright {{__YEAR__}} Kivy Maintainers</string>\n\t<key>NSMainNibFile</key>\n\t<string>MainMenu</string>\n\t<key>NSPrincipalClass</key>\n\t<string>NSApplication</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "tickeys/kivy/tools/packaging/osx/InfoPlist.strings",
    "content": "CFBundleName = \"Kivy\";\nCFBundleShortVersionString = \"{{__VERSION__}}\";\nCFBundleGetInfoString = \"Kivy version {{__VERSION__}} Copyright {{__YEAR__}} Kivy Maintainers\";\nNSHumanReadableCopyright = \"Copyright {{__YEAR__}} Kivy Maintainers.\";\n"
  },
  {
    "path": "tickeys/kivy/tools/packaging/osx/kivy.sh",
    "content": "#!/bin/bash\nSCRIPT_PATH=\"${BASH_SOURCE[0]}\";\nif([ -h \"${SCRIPT_PATH}\" ]) then\n  while([ -h \"${SCRIPT_PATH}\" ]) do SCRIPT_PATH=`readlink \"${SCRIPT_PATH}\"`; done\nfi\nSCRIPT_PATH=`dirname ${SCRIPT_PATH}`\n\nexport PYTHONPATH=${SCRIPT_PATH}/kivy:${SCRIPT_PATH}/lib/sitepackages:$PYTHONPATH\nexport DYLD_FALLBACK_LIBRARY_PATH=${SCRIPT_PATH}/lib:$DYLD_FALLBACK_LIBRARY_PATH\nexport LD_PRELOAD_PATH=${SCRIPT_PATH}/lib:$LD_PRELOAD_PATH\nexport GST_PLUGIN_PATH=${SCRIPT_PATH}/lib/gst-plugins:$GST_PLUGIN_PATH\nexport GST_PLUGIN_SCANNER=${SCRIPT_PATH}/lib/bin/gst-plugin-scanner\nexport GST_REGISTRY_FORK=\"no\"\n\nexec $(python -c \"import os, sys; print(os.path.normpath(sys.prefix))\")/bin/python2.7 \"$@\"\n"
  },
  {
    "path": "tickeys/kivy/tools/packaging/pyinstaller_hooks/__init__.py",
    "content": "from os.path import dirname, join\nfrom functools import partial\n\ncurdir = dirname(__file__)\n\n\ndef install_hooks(sym, hookspath=None):\n\n    _hookspath = [curdir]\n    if hookspath is not None:\n        _hookspath += hookspath\n\n    sym['rthooks']['kivy'] = [join(curdir, 'rt-hook-kivy.py')]\n    sym['Analysis'] = partial(sym['Analysis'], hookspath=_hookspath)\n"
  },
  {
    "path": "tickeys/kivy/tools/packaging/pyinstaller_hooks/hook-kivy.py",
    "content": "'''\nKivy hook for PyInstaller\n=========================\n\nKivy load itself in a complete dynamic way. PyImported don't see most of the\nimport cause of the Factory and Core.\nIn addition, the data and missing module are not copied automatically.\n\nWith this hook, everything needed for running kivy is correctly copied.\n\nCheck kivy documentation about how to use these hook for packaging application.\n'''\n\nimport kivy\nfrom kivy.factory import Factory\n\n\ndef get_modules():\n    return [x.get('module', None) for x in Factory.classes.values()]\n\n\ndatas = [\n    (kivy.kivy_data_dir, 'kivy_install'),\n    (kivy.kivy_modules_dir, 'kivy_install'),\n    (kivy.kivy_exts_dir, 'kivy_install'),\n]\n\n# extensions\n_kivy_modules = [\n\n    # sdl2\n\n    # pygame\n    'pygame.event',\n    'pygame.video',\n    'pygame.image',\n    'pygame.display',\n    'pygame',\n\n    # external modules\n    'kivy.cache',\n    'kivy.atlas',\n    'kivy.network',\n    'kivy.network.urlrequest',\n    'kivy.lib.osc',\n    'kivy.lib.osc.OSC',\n    'kivy.lib.osc.oscAPI',\n    'kivy.lib.mtdev',\n    'kivy.lib.sdl2',\n    'kivy.factory_registers',\n    'kivy.input.recorder',\n    'kivy.input.providers',\n    'kivy.input.providers.tuio',\n    'kivy.input.providers.mouse',\n    'kivy.input.providers.wm_common',\n    'kivy.input.providers.wm_touch',\n    'kivy.input.providers.wm_pen',\n    'kivy.input.providers.hidinput',\n    'kivy.input.providers.linuxwacom',\n    'kivy.input.providers.mactouch',\n    'kivy.input.providers.mouse',\n    'kivy.input.providers.mtdev',\n\n    # compiled modules\n    'kivy.event',\n    'kivy.graphics.buffer',\n    'kivy.graphics.c_opengl_debug',\n    'kivy.graphics.compiler',\n    'kivy.graphics.context_instructions',\n    'kivy.graphics.fbo',\n    'kivy.graphics.instructions',\n    'kivy.graphics.opengl',\n    'kivy.graphics.opengl_utils',\n    'kivy.graphics.shader',\n    'kivy.graphics.stenctil_instructions',\n    'kivy.graphics.texture',\n    'kivy.graphics.transformation',\n    'kivy.graphics.vbo',\n    'kivy.graphics.vertex',\n    'kivy.graphics.vertex_instructions',\n    'kivy.properties',\n\n    # core\n    'kivy.core.audio.audio_gstplayer',\n    'kivy.core.audio.audio_pygst',\n    'kivy.core.audio.audio_sdl',\n    'kivy.core.audio.audio_pygame',\n    'kivy.core.camera.camera_avfoundation',\n    'kivy.core.camera.camera_pygst',\n    'kivy.core.camera.camera_opencv',\n    'kivy.core.camera.camera_videocapture',\n    'kivy.core.clipboard.clipboard_sdl2',\n    'kivy.core.clipboard.clipboard_android',\n    'kivy.core.clipboard.clipboard_pygame',\n    'kivy.core.clipboard.clipboard_dummy',\n    'kivy.core.image.img_imageio',\n    'kivy.core.image.img_tex',\n    'kivy.core.image.img_dds',\n    'kivy.core.image.img_sdl2',\n    'kivy.core.image.img_pygame',\n    'kivy.core.image.img_pil',\n    'kivy.core.image.img_gif',\n    'kivy.core.spelling.spelling_enchant',\n    'kivy.core.spelling.spelling_osxappkit',\n    'kivy.core.text.text_sdl2',\n    'kivy.core.text.text_pygame',\n    'kivy.core.text.text_sdlttf',\n    'kivy.core.text.text_pil',\n    'kivy.core.video.video_gstplayer',\n    'kivy.core.video.video_pygst',\n    'kivy.core.video.video_ffmpeg',\n    'kivy.core.video.video_pyglet',\n    'kivy.core.video.video_null',\n    'kivy.core.window.window_sdl2',\n    'kivy.core.window.window_egl_rpi',\n    'kivy.core.window.window_pygame',\n    'kivy.core.window.window_sdl',\n    'kivy.core.window.window_x11',\n]\n\nhiddenimports = _kivy_modules + get_modules()\nhiddenimports = list(set(hiddenimports))\n\n"
  },
  {
    "path": "tickeys/kivy/tools/packaging/pyinstaller_hooks/rt-hook-kivy.py",
    "content": "from os.path import join, dirname\nfrom os import environ, chdir, putenv\nimport sys\n\nroot = 'kivy_install'\nif hasattr(sys, '_MEIPASS'):\n    # PyInstaller >= 1.6\n    chdir(sys._MEIPASS)\n    root = join(sys._MEIPASS, root)\nelif '_MEIPASS2' in environ:\n    # PyInstaller < 1.6 (tested on 1.5 only)\n    chdir(environ['_MEIPASS2'])\n    root = join(environ['_MEIPASS2'], root)\nelse:\n    chdir(dirname(sys.argv[0]))\n    root = join(dirname(sys.argv[0]), root)\n\n\nsys.path += [join(root, '_libs')]\n\nif sys.platform == 'darwin':\n    sitepackages = join(root, '..', 'sitepackages')\n    sys.path += [sitepackages, join(sitepackages, 'gst-0.10')]\n    putenv('GST_REGISTRY_FORK', 'no')\n\nenviron['GST_PLUGIN_PATH'] = join(root, '..', 'gst-plugins')\nenviron['KIVY_DATA_DIR'] = join(root, 'data')\nenviron['KIVY_EXTS_DIR'] = join(root, 'extensions')\nenviron['KIVY_MODULES_DIR'] = join(root, 'modules')\nenviron['KIVY_EMBED'] = '1'\n\n# Monkey-patch pygame to get around an issue with Pygame window icon and\n# PyInstaller 2.1. See kivy issue #1638\nimport pygame.pkgdata\n_original_getResource = pygame.pkgdata.getResource\n\n\ndef getResource(identifier, *args, **kwargs):\n    if identifier == 'pygame_icon.tiff':\n        raise IOError()\n    return _original_getResource(identifier, *args, **kwargs)\npygame.pkgdata.getResource = getResource\n"
  },
  {
    "path": "tickeys/kivy/tools/packaging/win32/README.txt",
    "content": "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\r\nREAD THIS FIRST\r\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\r\n\r\nThis version of Kivy is a portable win32 version, 32 bits. (it work also for\r\n64 bits Windows.) This means everything you need to run kivy (including \r\npython and all other dependencies etc) are included.\r\n\r\nThis README only addresses the things specific to the portable version of kivy.  \r\nFor general information on how to get started, where to find the documentation \r\nand configuration see the README file in the kivy directory about Kivy.\r\n\r\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\r\n\r\n\r\nRunning portable Kivy\r\n=====================\r\n\r\nThe same directory that has this README file in it, contains a file called kivy.bat\r\nrunning this kivy.bat file will set up the environment for kivy and starts the \r\npython interpreter with any arguments you passed\r\n\r\nExample\r\n~~~~~~~\r\n\r\nIf you open a command line and go to the directory (or add it to your PATH) \r\nYou can run the following:\r\n\r\nkivy test.py -w  <-- will run test.py as a python script with kivy ready to use\r\n\r\n\r\nRun a Kivy application without going to the command line\r\n========================================================\r\n\r\nThree options :\r\n\r\n1. You can drag your python script on top the kivy.bat file and it will launch\r\n\r\n2. If you right click on your python script (.py ending or whatever you named it), \r\nyou can select properties and select an application to open this type of file with.\r\nNavigate to the folder that includes this README and select the kivy.bat file.  \r\nNow all you have to do is double click (check do this always for this file type \r\nto make this the default)\r\n\r\n3. Install the Python Launcher for Windows. (Comes with Python 3.3 -- See Python PEP-397)\r\n* in each of your main.py files, add a first line of:\r\n   #!/usr/bin/kivy\r\n* create a file named C:\\Windows\\py.ini containing something like:\r\n   [commands]\r\n   kivy=\"c:\\<path>\\<to>\\<your>\\kivy.bat\"\r\n\r\nIf you already have Python installed\r\n====================================\r\n\r\nThe portable Kivy version shouldn't cause any conflicts and cooperate fairly well \r\n(at least if it's Python 2.7, otherwise some modules might cause problems if there\r\nis entries on PYTHONPATH)\r\n\r\n\r\nInstall Kivy as a standard python module\r\n========================================\r\n\r\nPlease refer to the install instructions in the complete README :\r\n* Inside the kivy folder inside this one\r\n* Kivy documentation at http://kivy.org/docs/\r\n\r\n\r\nInstall development environment inside your current shell\r\n=========================================================\r\n\r\nIf you want to develop with Kivy's python, you may just want to load the\r\nenvironment, and stay in your console. Inside a git bash / mingsys console, you\r\ncan type :\r\n\r\n  source /path/to/kivyenv.sh\r\n\r\nAnd it will load the whole enviroment of Kivy. This will give you an access to:\r\n\r\n  * Python binaries (python, pythonw, easy_install, pip)\r\n  * Cython binaries (cython)\r\n  * Gstreamer binaries (gst-inspect, gst-launch, ...)\r\n  * Pre-configured PYTHONPATH for gst and Kivy\r\n\r\nPlease note that if you already have a Python installed on your system, it will be\r\nnot used.\r\n"
  },
  {
    "path": "tickeys/kivy/tools/report.py",
    "content": "'''\nReport tool\n===========\n\nThis tool is a helper for users. It can be used to dump information\nfor help during the debugging process.\n\n'''\n\nimport os\nimport sys\nimport time\nfrom time import ctime\nfrom configparser import ConfigParser\nfrom io import StringIO\n\nimport kivy\n\nreport = []\nreport_dict = {}  # One key value pair for each title.\n\n\ndef title(t):\n    report.append('')\n    report.append('=' * 80)\n    report.append(t)\n    report.append('=' * 80)\n    report.append('')\n\n# This method sends report to gist(Different file in a single gist) and\n# returns the URL\n\n\ndef send_report(dict_report):\n    import requests\n    import json\n\n    gist_report = {\n        \"description\": \"Report\",\n        \"public\": \"true\",\n        \"files\": {\n            \"Global.txt\": {\n                \"content\": \"\\n\".join(dict_report['Global']),\n                \"type\": 'text'\n            },\n            \"OpenGL.txt\": {\n                \"content\": \"\\n\".join(dict_report['OpenGL']),\n                \"type\": 'text'\n\n            },\n            \"Core selection.txt\": {\n                \"content\": \"\\n\".join(dict_report['Core']),\n                \"type\": 'text'\n            },\n            \"Libraries.txt\": {\n                \"content\": \"\\n\".join(dict_report['Libraries']),\n                \"type\": 'text'\n            },\n            \"Configuration.txt\": {\n                \"content\": \"\\n\".join(dict_report['Configuration']),\n                \"type\": 'text'\n            },\n            \"Input Availablity.txt\": {\n                \"content\": \"\\n\".join(dict_report['InputAvailablity']),\n                \"type\": 'text'\n            },\n            \"Environ.txt\": {\n                \"content\": \"\\n\".join(dict_report['Environ']),\n                \"type\": 'text'\n            },\n            \"Options.txt\": {\n                \"content\": \"\\n\".join(dict_report['Options']),\n                \"type\": 'text'\n            },\n        }\n    }\n    report_json = json.dumps(gist_report)\n    response = requests.post(\"https://api.github.com/gists\", report_json)\n    return json.loads(response.text)['html_url']\n\n# ----------------------------------------------------------\n# Start output debugging\n# ----------------------------------------------------------\n\ntitle('Global')\nreport.append('OS platform     : %s' % sys.platform)\nreport.append('Python EXE      : %s' % sys.executable)\nreport.append('Python Version  : %s' % sys.version)\nreport.append('Python API      : %s' % sys.api_version)\nreport.append('Kivy Version    : %s' % kivy.__version__)\nreport.append('Install path    : %s' % os.path.dirname(kivy.__file__))\nreport.append('Install date    : %s' % ctime(os.path.getctime(kivy.__file__)))\nreport_dict['Global'] = report\nreport = []\n\ntitle('OpenGL')\nfrom kivy.core import gl\nfrom kivy.core.window import Window\nreport.append('GL Vendor: %s' % gl.glGetString(gl.GL_VENDOR))\nreport.append('GL Renderer: %s' % gl.glGetString(gl.GL_RENDERER))\nreport.append('GL Version: %s' % gl.glGetString(gl.GL_VERSION))\next = gl.glGetString(gl.GL_EXTENSIONS)\nif ext is None:\n    report.append('GL Extensions: %s' % ext)\nelse:\n    report.append('GL Extensions:')\n    for x in ext.split():\n        report.append('\\t%s' % x)\nWindow.close()\nreport_dict['OpenGL'] = report\nreport = []\n\ntitle('Core selection')\nfrom kivy.core.audio import SoundLoader\nreport.append('Audio  = %s' % SoundLoader._classes)\nfrom kivy.core.camera import Camera\nreport.append('Camera = %s' % Camera)\nfrom kivy.core.image import ImageLoader\nreport.append('Image  = %s' % ImageLoader.loaders)\nfrom kivy.core.text import Label\nreport.append('Text   = %s' % Label)\nfrom kivy.core.video import Video\nreport.append('Video  = %s' % Video)\nreport.append('Window = %s' % Window)\nreport_dict['Core'] = report\nreport = []\n\ntitle('Libraries')\n\n\ndef testimport(libname):\n    try:\n        l = __import__(libname)\n        report.append('%-20s exist at %s' % (libname, l.__file__))\n    except ImportError:\n        report.append('%-20s is missing' % libname)\n\nfor x in (\n    'gst',\n    'pygame',\n    'pygame.midi',\n    'pyglet',\n    'videocapture',\n    'squirtle',\n    'PIL',\n    'opencv',\n    'opencv.cv',\n    'opencv.highgui',\n    'cython'):\n    testimport(x)\nreport_dict['Libraries'] = report\nreport = []\n\ntitle('Configuration')\ns = StringIO()\nfrom kivy.config import Config\nConfigParser.write(Config, s)\nreport.extend(s.getvalue().split('\\n'))\nreport_dict['Configuration'] = report\nreport = []\n\ntitle('Input availability')\nfrom kivy.input.factory import MotionEventFactory\nfor x in MotionEventFactory.list():\n    report.append(x)\nreport_dict['InputAvailablity'] = report\nreport = []\n\n'''\ntitle('Log')\nfor x in pymt_logger_history.history:\n    report.append(x.message)\n'''\n\ntitle('Environ')\nfor k, v in os.environ.items():\n    report.append('%s = %s' % (k, v))\nreport_dict['Environ'] = report\nreport = []\n\ntitle('Options')\nfor k, v in kivy.kivy_options.items():\n    report.append('%s = %s' % (k, v))\nreport_dict['Options'] = report\nreport = []\n\n# Prints the entire Output\nprint('\\n'.join(report_dict['Global'] + report_dict['OpenGL'] +\n                report_dict['Core'] + report_dict['Libraries'] +\n                report_dict['Configuration'] +\n                report_dict['InputAvailablity'] +\n                report_dict['Environ'] + report_dict['Options']))\nprint()\nprint()\n\ntry:\n    reply = input(\n        'Do you accept to send report to https://gist.github.com/ (Y/n) : ')\nexcept EOFError:\n    sys.exit(0)\n\nif reply.lower().strip() in ('', 'y'):\n    print('Please wait while sending the report...')\n\n    paste_url = send_report(report_dict)\n\n    print()\n    print()\n    print('REPORT posted at %s' % paste_url)\n    print()\n    print()\nelse:\n    print('No report posted.')\n\n# On windows system, the console leave directly after the end\n# of the dump. That's not cool if we want get report url\ninput('Enter any key to leave.')\n"
  },
  {
    "path": "tickeys/kivy/tools/stub-gl-debug.py",
    "content": "from __future__ import print_function\n\na = '''cdef void   glActiveTexture (cgl.GLenum texture)\ncdef void   glAttachShader (cgl.GLuint program, cgl.GLuint shader)\ncdef void   glBindAttribLocation (cgl.GLuint program, cgl.GLuint index,  cgl.GLchar* name)\ncdef void   glBindBuffer (cgl.GLenum target, cgl.GLuint buffer)\ncdef void   glBindFramebuffer (cgl.GLenum target, cgl.GLuint framebuffer)\ncdef void   glBindRenderbuffer (cgl.GLenum target, cgl.GLuint renderbuffer)\ncdef void   glBindTexture (cgl.GLenum target, cgl.GLuint texture)\ncdef void   glBlendColor (cgl.GLclampf red, cgl.GLclampf green, cgl.GLclampf blue, cgl.GLclampf alpha)\ncdef void   glBlendEquation (cgl.GLenum mode)\ncdef void   glBlendEquationSeparate (cgl.GLenum modeRGB, cgl.GLenum modeAlpha)\ncdef void   glBlendFunc (cgl.GLenum sfactor, cgl.GLenum dfactor)\ncdef void   glBlendFuncSeparate (cgl.GLenum srcRGB, cgl.GLenum dstRGB, cgl.GLenum srcAlpha, cgl.GLenum dstAlpha)\ncdef void   glBufferData (cgl.GLenum target, cgl.GLsizeiptr size,  cgl.GLvoid* data, cgl.GLenum usage)\ncdef void   glBufferSubData (cgl.GLenum target, cgl.GLintptr offset, cgl.GLsizeiptr size,  cgl.GLvoid* data)\ncdef cgl.GLenum glCheckFramebufferStatus (cgl.GLenum target)\ncdef void   glClear (cgl.GLbitfield mask)\ncdef void   glClearColor (cgl.GLclampf red, cgl.GLclampf green, cgl.GLclampf blue, cgl.GLclampf alpha)\ncdef void   glClearDepthf (cgl.GLclampf depth)\ncdef void   glClearStencil (cgl.GLint s)\ncdef void   glColorMask (cgl.GLboolean red, cgl.GLboolean green, cgl.GLboolean blue, cgl.GLboolean alpha)\ncdef void   glCompileShader (cgl.GLuint shader)\ncdef void   glCompressedTexImage2D (cgl.GLenum target, cgl.GLint level, cgl.GLenum internalformat, cgl.GLsizei width, cgl.GLsizei height, cgl.GLint border, cgl.GLsizei imageSize,  cgl.GLvoid* data)\ncdef void   glCompressedTexSubImage2D (cgl.GLenum target, cgl.GLint level, cgl.GLint xoffset, cgl.GLint yoffset, cgl.GLsizei width, cgl.GLsizei height, cgl.GLenum format, cgl.GLsizei imageSize,  cgl.GLvoid* data)\ncdef void   glCopyTexImage2D (cgl.GLenum target, cgl.GLint level, cgl.GLenum internalformat, cgl.GLint x, cgl.GLint y, cgl.GLsizei width, cgl.GLsizei height, cgl.GLint border)\ncdef void   glCopyTexSubImage2D (cgl.GLenum target, cgl.GLint level, cgl.GLint xoffset, cgl.GLint yoffset, cgl.GLint x, cgl.GLint y, cgl.GLsizei width, cgl.GLsizei height)\ncdef cgl.GLuint glCreateProgram ()\ncdef cgl.GLuint glCreateShader (cgl.GLenum type)\ncdef void   glCullFace (cgl.GLenum mode)\ncdef void   glDeleteBuffers (cgl.GLsizei n,  cgl.GLuint* buffers)\ncdef void   glDeleteFramebuffers (cgl.GLsizei n,  cgl.GLuint* framebuffers)\ncdef void   glDeleteProgram (cgl.GLuint program)\ncdef void   glDeleteRenderbuffers (cgl.GLsizei n,  cgl.GLuint* renderbuffers)\ncdef void   glDeleteShader (cgl.GLuint shader)\ncdef void   glDeleteTextures (cgl.GLsizei n,  cgl.GLuint* textures)\ncdef void   glDepthFunc (cgl.GLenum func)\ncdef void   glDepthMask (cgl.GLboolean flag)\ncdef void   glDepthRangef (cgl.GLclampf zNear, cgl.GLclampf zFar)\ncdef void   glDetachShader (cgl.GLuint program, cgl.GLuint shader)\ncdef void   glDisable (cgl.GLenum cap)\ncdef void   glDisableVertexAttribArray (cgl.GLuint index)\ncdef void   glDrawArrays (cgl.GLenum mode, cgl.GLint first, cgl.GLsizei count)\ncdef void   glDrawElements (cgl.GLenum mode, cgl.GLsizei count, cgl.GLenum type,  cgl.GLvoid* indices)\ncdef void   glEnable (cgl.GLenum cap)\ncdef void   glEnableVertexAttribArray (cgl.GLuint index)\ncdef void   glFinish ()\ncdef void   glFlush ()\ncdef void   glFramebufferRenderbuffer (cgl.GLenum target, cgl.GLenum attachment, cgl.GLenum renderbuffertarget, cgl.GLuint renderbuffer)\ncdef void   glFramebufferTexture2D (cgl.GLenum target, cgl.GLenum attachment, cgl.GLenum textarget, cgl.GLuint texture, cgl.GLint level)\ncdef void   glFrontFace (cgl.GLenum mode)\ncdef void   glGenBuffers (cgl.GLsizei n, cgl.GLuint* buffers)\ncdef void   glGenerateMipmap (cgl.GLenum target)\ncdef void   glGenFramebuffers (cgl.GLsizei n, cgl.GLuint* framebuffers)\ncdef void   glGenRenderbuffers (cgl.GLsizei n, cgl.GLuint* renderbuffers)\ncdef void   glGenTextures (cgl.GLsizei n, cgl.GLuint* textures)\ncdef void   glGetActiveAttrib (cgl.GLuint program, cgl.GLuint index, cgl.GLsizei bufsize, cgl.GLsizei* length, cgl.GLint* size, cgl.GLenum* type, cgl.GLchar* name)\ncdef void   glGetActiveUniform (cgl.GLuint program, cgl.GLuint index, cgl.GLsizei bufsize, cgl.GLsizei* length, cgl.GLint* size, cgl.GLenum* type, cgl.GLchar* name)\ncdef void   glGetAttachedShaders (cgl.GLuint program, cgl.GLsizei maxcount, cgl.GLsizei* count, cgl.GLuint* shaders)\ncdef int    glGetAttribLocation (cgl.GLuint program,  cgl.GLchar* name)\ncdef void   glGetBooleanv (cgl.GLenum pname, cgl.GLboolean* params)\ncdef void   glGetBufferParameteriv (cgl.GLenum target, cgl.GLenum pname, cgl.GLint* params)\ncdef cgl.GLenum glGetError ()\ncdef void   glGetFloatv (cgl.GLenum pname, cgl.GLfloat* params)\ncdef void   glGetFramebufferAttachmentParameteriv (cgl.GLenum target, cgl.GLenum attachment, cgl.GLenum pname, cgl.GLint* params)\ncdef void   glGetIntegerv (cgl.GLenum pname, cgl.GLint* params)\ncdef void   glGetProgramiv (cgl.GLuint program, cgl.GLenum pname, cgl.GLint* params)\ncdef void   glGetProgramInfoLog (cgl.GLuint program, cgl.GLsizei bufsize, cgl.GLsizei* length, cgl.GLchar* infolog)\ncdef void   glGetRenderbufferParameteriv (cgl.GLenum target, cgl.GLenum pname, cgl.GLint* params)\ncdef void   glGetShaderiv (cgl.GLuint shader, cgl.GLenum pname, cgl.GLint* params)\ncdef void   glGetShaderInfoLog (cgl.GLuint shader, cgl.GLsizei bufsize, cgl.GLsizei* length, cgl.GLchar* infolog)\n#cdef void   glGetShaderPrecisionFormat (cgl.GLenum shadertype, cgl.GLenum precisiontype, cgl.GLint* range, cgl.GLint* precision)\ncdef void   glGetShaderSource (cgl.GLuint shader, cgl.GLsizei bufsize, cgl.GLsizei* length, cgl.GLchar* source)\ncdef   cgl.GLubyte*  glGetString (cgl.GLenum name)\ncdef void   glGetTexParameterfv (cgl.GLenum target, cgl.GLenum pname, cgl.GLfloat* params)\ncdef void   glGetTexParameteriv (cgl.GLenum target, cgl.GLenum pname, cgl.GLint* params)\ncdef void   glGetUniformfv (cgl.GLuint program, cgl.GLint location, cgl.GLfloat* params)\ncdef void   glGetUniformiv (cgl.GLuint program, cgl.GLint location, cgl.GLint* params)\ncdef int    glGetUniformLocation (cgl.GLuint program,  cgl.GLchar* name)\ncdef void   glGetVertexAttribfv (cgl.GLuint index, cgl.GLenum pname, cgl.GLfloat* params)\ncdef void   glGetVertexAttribiv (cgl.GLuint index, cgl.GLenum pname, cgl.GLint* params)\ncdef void   glGetVertexAttribPointerv (cgl.GLuint index, cgl.GLenum pname, cgl.GLvoid** pointer)\ncdef void   glHint (cgl.GLenum target, cgl.GLenum mode)\ncdef cgl.GLboolean  glIsBuffer (cgl.GLuint buffer)\ncdef cgl.GLboolean  glIsEnabled (cgl.GLenum cap)\ncdef cgl.GLboolean  glIsFramebuffer (cgl.GLuint framebuffer)\ncdef cgl.GLboolean  glIsProgram (cgl.GLuint program)\ncdef cgl.GLboolean  glIsRenderbuffer (cgl.GLuint renderbuffer)\ncdef cgl.GLboolean  glIsShader (cgl.GLuint shader)\ncdef cgl.GLboolean  glIsTexture (cgl.GLuint texture)\ncdef void  glLineWidth (cgl.GLfloat width)\ncdef void  glLinkProgram (cgl.GLuint program)\ncdef void  glPixelStorei (cgl.GLenum pname, cgl.GLint param)\ncdef void  glPolygonOffset (cgl.GLfloat factor, cgl.GLfloat units)\ncdef void  glReadPixels (cgl.GLint x, cgl.GLint y, cgl.GLsizei width, cgl.GLsizei height, cgl.GLenum format, cgl.GLenum type, cgl.GLvoid* pixels)\n#cdef void  glReleaseShaderCompiler ()\ncdef void  glRenderbufferStorage (cgl.GLenum target, cgl.GLenum internalformat, cgl.GLsizei width, cgl.GLsizei height)\ncdef void  glSampleCoverage (cgl.GLclampf value, cgl.GLboolean invert)\ncdef void  glScissor (cgl.GLint x, cgl.GLint y, cgl.GLsizei width, cgl.GLsizei height)\n#cdef void  glShaderBinary (cgl.GLsizei n,  cgl.GLuint* shaders, cgl.GLenum binaryformat,  cgl.GLvoid* binary, cgl.GLsizei length)\ncdef void  glShaderSource (cgl.GLuint shader, cgl.GLsizei count,  cgl.GLchar** string,  cgl.GLint* length)\ncdef void  glStencilFunc (cgl.GLenum func, cgl.GLint ref, cgl.GLuint mask)\ncdef void  glStencilFuncSeparate (cgl.GLenum face, cgl.GLenum func, cgl.GLint ref, cgl.GLuint mask)\ncdef void  glStencilMask (cgl.GLuint mask)\ncdef void  glStencilMaskSeparate (cgl.GLenum face, cgl.GLuint mask)\ncdef void  glStencilOp (cgl.GLenum fail, cgl.GLenum zfail, cgl.GLenum zpass)\ncdef void  glStencilOpSeparate (cgl.GLenum face, cgl.GLenum fail, cgl.GLenum zfail, cgl.GLenum zpass)\ncdef void  glTexImage2D (cgl.GLenum target, cgl.GLint level, cgl.GLint internalformat, cgl.GLsizei width, cgl.GLsizei height, cgl.GLint border, cgl.GLenum format, cgl.GLenum type,  cgl.GLvoid* pixels)\ncdef void  glTexParameterf (cgl.GLenum target, cgl.GLenum pname, cgl.GLfloat param)\ncdef void  glTexParameterfv (cgl.GLenum target, cgl.GLenum pname,  cgl.GLfloat* params)\ncdef void  glTexParameteri (cgl.GLenum target, cgl.GLenum pname, cgl.GLint param)\ncdef void  glTexParameteriv (cgl.GLenum target, cgl.GLenum pname,  cgl.GLint* params)\ncdef void  glTexSubImage2D (cgl.GLenum target, cgl.GLint level, cgl.GLint xoffset, cgl.GLint yoffset, cgl.GLsizei width, cgl.GLsizei height, cgl.GLenum format, cgl.GLenum type,  cgl.GLvoid* pixels)\ncdef void  glUniform1f (cgl.GLint location, cgl.GLfloat x)\ncdef void  glUniform1fv (cgl.GLint location, cgl.GLsizei count,  cgl.GLfloat* v)\ncdef void  glUniform1i (cgl.GLint location, cgl.GLint x)\ncdef void  glUniform1iv (cgl.GLint location, cgl.GLsizei count,  cgl.GLint* v)\ncdef void  glUniform2f (cgl.GLint location, cgl.GLfloat x, cgl.GLfloat y)\ncdef void  glUniform2fv (cgl.GLint location, cgl.GLsizei count,  cgl.GLfloat* v)\ncdef void  glUniform2i (cgl.GLint location, cgl.GLint x, cgl.GLint y)\ncdef void  glUniform2iv (cgl.GLint location, cgl.GLsizei count,  cgl.GLint* v)\ncdef void  glUniform3f (cgl.GLint location, cgl.GLfloat x, cgl.GLfloat y, cgl.GLfloat z)\ncdef void  glUniform3fv (cgl.GLint location, cgl.GLsizei count,  cgl.GLfloat* v)\ncdef void  glUniform3i (cgl.GLint location, cgl.GLint x, cgl.GLint y, cgl.GLint z)\ncdef void  glUniform3iv (cgl.GLint location, cgl.GLsizei count,  cgl.GLint* v)\ncdef void  glUniform4f (cgl.GLint location, cgl.GLfloat x, cgl.GLfloat y, cgl.GLfloat z, cgl.GLfloat w)\ncdef void  glUniform4fv (cgl.GLint location, cgl.GLsizei count,  cgl.GLfloat* v)\ncdef void  glUniform4i (cgl.GLint location, cgl.GLint x, cgl.GLint y, cgl.GLint z, cgl.GLint w)\ncdef void  glUniform4iv (cgl.GLint location, cgl.GLsizei count,  cgl.GLint* v)\ncdef void  glUniformMatrix2fv (cgl.GLint location, cgl.GLsizei count, cgl.GLboolean transpose,  cgl.GLfloat* value)\ncdef void  glUniformMatrix3fv (cgl.GLint location, cgl.GLsizei count, cgl.GLboolean transpose,  cgl.GLfloat* value)\ncdef void  glUniformMatrix4fv (cgl.GLint location, cgl.GLsizei count, cgl.GLboolean transpose,  cgl.GLfloat* value)\ncdef void  glUseProgram (cgl.GLuint program)\ncdef void  glValidateProgram (cgl.GLuint program)\ncdef void  glVertexAttrib1f (cgl.GLuint indx, cgl.GLfloat x)\ncdef void  glVertexAttrib1fv (cgl.GLuint indx,  cgl.GLfloat* values)\ncdef void  glVertexAttrib2f (cgl.GLuint indx, cgl.GLfloat x, cgl.GLfloat y)\ncdef void  glVertexAttrib2fv (cgl.GLuint indx,  cgl.GLfloat* values)\ncdef void  glVertexAttrib3f (cgl.GLuint indx, cgl.GLfloat x, cgl.GLfloat y, cgl.GLfloat z)\ncdef void  glVertexAttrib3fv (cgl.GLuint indx,  cgl.GLfloat* values)\ncdef void  glVertexAttrib4f (cgl.GLuint indx, cgl.GLfloat x, cgl.GLfloat y, cgl.GLfloat z, cgl.GLfloat w)\ncdef void  glVertexAttrib4fv (cgl.GLuint indx,  cgl.GLfloat* values)\ncdef void  glVertexAttribPointer (cgl.GLuint indx, cgl.GLint size, cgl.GLenum type, cgl.GLboolean normalized, cgl.GLsizei stride,  cgl.GLvoid* ptr)\ncdef void  glViewport (cgl.GLint x, cgl.GLint y, cgl.GLsizei width, cgl.GLsizei height)'''\n\ndef replace(s):\n    item = s.split(' ')\n    rettype = item[1]\n    item = item[2:]\n    for x in item:\n        x = x.strip()\n        if not x or x.startswith('GL'):\n            continue\n        if x.startswith('(GL'):\n            yield '('\n            continue\n        if x.startswith('gl'):\n            prefix = ''\n            if rettype != 'void':\n                prefix = 'return '\n            yield '%scgl.%s' % (prefix, x)\n            continue\n        yield x\n\nprint('''\n# This file was automatically generated with kivy/tools/stub-gl-debug.py\ncimport c_opengl as cgl\n\n''')\n\nlines = a.splitlines()\nfor x in lines:\n    if x.startswith('#'):\n        # There are some functions that either do not exist or break on OSX.\n        # Just skip those.\n        print('# Skipping generation of: \"%s\"' % x)\n        continue\n    x = x.replace('cgl.', '')\n    y = ' '.join(replace(x))\n\n    print('%s with gil:' % x)\n    s = x.split()\n    print('    print \"GL %s(' % s[2], end=' ')\n    pointer = 0\n    for arg in s[3:]:\n        arg = arg.strip()\n        arg = arg.replace(',', '').replace(')', '')\n        if 'GL' in arg or arg == '(':\n            pointer = arg.count('*')\n            continue\n        pointer = '*' * pointer\n        if pointer:\n            print('%s%s=\", repr(hex(<long> %s)), \",' % (arg, pointer, arg), end=' ')\n        else:\n            print('%s = \", %s, \",' % (arg, arg), end=' ')\n        pointer = 0\n    print(')\"')\n    print('    %s' % y)\n    print('    ret = glGetError()')\n    print('    if ret: print(\"ERR {} / {}\".format(ret, ret))')\n"
  },
  {
    "path": "tickeys/kivy/tools/texturecompress.py",
    "content": "#:/usr/bin/env python2.7\n'''\nTexture compression tool\n========================\n\nThis tool is designed to compress images into:\n\n- PVRTC (PowerVR Texture Compression), mostly iOS devices\n- ETC1 (Ericson compression), working on all GLES2/Android devices\n\nUsage\n-----\n\nIn order to compress a texture::\n\n    texturecompress.py [--dir <directory>] <format> <image.png>\n\nThis will create a `image.tex` file with a json header that contains all the\nimage information and the compressed data.\n\nTODO\n----\n\nSupport more format, such as:\n\n- S3TC (already supported in Kivy)\n- DXT1 (already supported in Kivy)\n'''\n\nimport json\nfrom struct import pack\nfrom pprint import pprint\nfrom subprocess import Popen\nfrom PIL import Image\nfrom argparse import ArgumentParser\nfrom sys import exit\nfrom os.path import join, exists, dirname, basename\nfrom os import environ, unlink\n\n\nclass Tool(object):\n    def __init__(self, options):\n        super(Tool, self).__init__()\n        self.options = options\n        self.source_fn = options.image\n        self.dest_dir = options.dir or dirname(options.image)\n\n    @property\n    def tex_fn(self):\n        fn = basename(self.source_fn).rsplit('.', 1)[0] + '.tex'\n        return join(self.dest_dir, fn)\n\n    def compress(self):\n        pass\n\n    def nearest_pow2(self, v):\n        # Credits: Sean Anderson\n        v -= 1\n        v |= v >> 1\n        v |= v >> 2\n        v |= v >> 4\n        v |= v >> 8\n        v |= v >> 16\n        return v + 1\n\n    def runcmd(self, cmd):\n        print('Run: {}'.format(' '.join(cmd)))\n        Popen(cmd).communicate()\n\n    def write_tex(self, data, fmt, image_size, texture_size, mipmap=False,\n            formatinfo=None):\n        infos = {\n            'datalen': len(data),\n            'image_size': image_size,\n            'texture_size': texture_size,\n            'mipmap': mipmap,\n            'format': fmt}\n        if formatinfo:\n            infos['formatinfo'] = formatinfo\n        header = json.dumps(infos, indent=0, separators=(',', ':'))\n        header = header.replace('\\n', '')\n        with open(self.tex_fn, 'wb') as fd:\n            fd.write('KTEX')\n            fd.write(pack('I', len(header)))\n            fd.write(header)\n            fd.write(data)\n\n        print('Done! Compressed texture written at {}'.format(self.tex_fn))\n        pprint(infos)\n\n    @staticmethod\n    def run():\n        parser = ArgumentParser(\n                description='Convert images to compressed texture')\n        parser.add_argument('--mipmap', type=bool, default=False,\n                help='Auto generate mipmaps')\n        parser.add_argument('--dir', type=str, default=None,\n                help='Output directory to generate the compressed texture')\n        parser.add_argument('format', type=str, choices=['pvrtc', 'etc1'],\n                help='Format of the final texture')\n        parser.add_argument('image', type=str,\n                help='Image filename')\n        args = parser.parse_args()\n\n        if args.format == 'pvrtc':\n            PvrtcTool(args).compress()\n        elif args.format == 'etc1':\n            Etc1Tool(args).compress()\n        else:\n            print('Unknown compression format')\n            exit(1)\n\n\nclass Etc1Tool(Tool):\n    def __init__(self, options):\n        super(Etc1Tool, self).__init__(options)\n        self.etc1tool = None\n        self.locate_etc1tool()\n\n    def locate_etc1tool(self):\n        search_directories = [environ.get('ANDROIDSDK', '/')]\n        search_directories += environ.get('PATH', '').split(':')\n        for directory in search_directories:\n            fn = join(directory, 'etc1tool')\n            if not exists(fn):\n                fn = join(directory, 'tools', 'etc1tool')\n                if not exists(fn):\n                    continue\n            print('Found texturetool at {}'.format(directory))\n            self.etc1tool = fn\n            return\n\n        if self.etc1tool is None:\n            print('Error: Unable to locate \"etc1tool\".\\n'\n                  'Make sure that \"etc1tool\" is available in your PATH.\\n'\n                  'Or export the path of your Android SDK to ANDROIDSDK')\n            exit(1)\n\n    def compress(self):\n        # 1. open the source image, and get the dimensions\n        image = Image.open(self.source_fn)\n        w, h = image.size\n        print('Image size is {}x{}'.format(*image.size))\n\n        # 2. search the nearest 2^\n        w2 = self.nearest_pow2(w)\n        h2 = self.nearest_pow2(h)\n        print('Nearest power-of-2 size is {}x{}'.format(w2, h2))\n\n        # 3. invoke etc1tool\n        raw_tex_fn = self.tex_fn + '.raw'\n        cmd = [self.etc1tool, self.source_fn, '--encodeNoHeader', '-o',\n               raw_tex_fn]\n        try:\n            self.runcmd(cmd)\n            with open(raw_tex_fn, 'rb') as fd:\n                data = fd.read()\n        finally:\n            if exists(raw_tex_fn):\n                unlink(raw_tex_fn)\n\n        # 5. write texture info\n        self.write_tex(data, 'etc1_rgb8', (w, h), (w2, h2), self.options.mipmap)\n\n\nclass PvrtcTool(Tool):\n    def __init__(self, options):\n        super(PvrtcTool, self).__init__(options)\n        self.texturetool = None\n        self.locate_texturetool()\n\n    def locate_texturetool(self):\n        search_directories = [\n            ('/Applications/Xcode.app/Contents/Developer/Platforms/'\n             'iPhoneOS.platform/Developer/usr/bin/'),\n            '/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/']\n        search_directories += environ.get('PATH', '').split(':')\n\n        for directory in search_directories:\n            fn = join(directory, 'texturetool')\n            if not exists(fn):\n                continue\n            print('Found texturetool at {}'.format(directory))\n            self.texturetool = fn\n            return\n\n        print('Error: Unable to locate \"texturetool\".\\n'\n              'Please install the iPhone SDK, or the PowerVR SDK.\\n'\n              'Then make sure that \"texturetool\" is available in your PATH.')\n        exit(1)\n\n    def compress(self):\n        # 1. open the source image, and get the dimensions\n        image = Image.open(self.source_fn)\n        w, h = image.size\n        print('Image size is {}x{}'.format(*image.size))\n\n        # 2. search the nearest 2^\n        w2 = self.nearest_pow2(w)\n        h2 = self.nearest_pow2(h)\n        print('Nearest power-of-2 size is {}x{}'.format(w2, h2))\n\n        # 3. for PVR, the image MUST be a square. use the bigger size then\n        s2 = max(w2, h2)\n        print('PVR need a square image, the texture will be {0}x{0}'.format(s2))\n\n        ext = self.source_fn.rsplit('.', 1)[-1]\n        tmpfile = '/tmp/ktexturecompress.{}'.format(ext)\n        image = image.resize((s2, s2))\n        image.save(tmpfile)\n\n        # 4. invoke texture tool\n        raw_tex_fn = self.tex_fn + '.raw'\n        cmd = [self.texturetool]\n        if self.options.mipmap:\n            cmd += ['-m']\n        cmd += ['-e', 'PVRTC', '-o', raw_tex_fn, '-f', 'RAW', tmpfile]\n        try:\n            self.runcmd(cmd)\n            with open(raw_tex_fn, 'rb') as fd:\n                data = fd.read()\n        finally:\n            if exists(raw_tex_fn):\n                unlink(raw_tex_fn)\n\n        # 5. write texture info\n        self.write_tex(data, 'pvrtc_rgba4', (w, h), (s2, s2),\n                       self.options.mipmap)\n\n\nif __name__ == '__main__':\n    Tool.run()\n"
  },
  {
    "path": "tickeys/kivy/uix/__init__.py",
    "content": "'''\nWidgets\n=======\n\nWidgets are elements of a graphical user interface that form part of the\n`User Experience <http://en.wikipedia.org/wiki/User_experience>`_.\nThe `kivy.uix` module contains classes for creating and managing Widgets.\nPlease refer to the :doc:`api-kivy.uix.widget` documentation for further\ninformation.\n\nKivy widgets can be categorized as follows:\n\n- **UX widgets**: Classical user interface widgets, ready to be assembled to\n  create more complex widgets.\n\n    :doc:`api-kivy.uix.label`, :doc:`api-kivy.uix.button`,\n    :doc:`api-kivy.uix.checkbox`,\n    :doc:`api-kivy.uix.image`, :doc:`api-kivy.uix.slider`,\n    :doc:`api-kivy.uix.progressbar`, :doc:`api-kivy.uix.textinput`,\n    :doc:`api-kivy.uix.togglebutton`, :doc:`api-kivy.uix.switch`,\n    :doc:`api-kivy.uix.video`\n\n- **Layouts**: A layout widget does no rendering but just acts as a trigger\n  that arranges its children in a specific way. Read more on\n  :doc:`Layouts here <api-kivy.uix.layout>`.\n\n    :doc:`api-kivy.uix.anchorlayout`, :doc:`api-kivy.uix.boxlayout`,\n    :doc:`api-kivy.uix.floatlayout`,\n    :doc:`api-kivy.uix.gridlayout`, :doc:`api-kivy.uix.pagelayout`,\n    :doc:`api-kivy.uix.relativelayout`, :doc:`api-kivy.uix.scatterlayout`,\n    :doc:`api-kivy.uix.stacklayout`\n\n- **Complex UX widgets**: Non-atomic widgets that are the result of\n  combining multiple classic widgets.\n  We call them complex because their assembly and usage are not as\n  generic as the classical widgets.\n\n    :doc:`api-kivy.uix.bubble`, :doc:`api-kivy.uix.dropdown`,\n    :doc:`api-kivy.uix.filechooser`, :doc:`api-kivy.uix.popup`,\n    :doc:`api-kivy.uix.spinner`,\n    :doc:`api-kivy.uix.listview`,\n    :doc:`api-kivy.uix.tabbedpanel`, :doc:`api-kivy.uix.videoplayer`,\n    :doc:`api-kivy.uix.vkeyboard`,\n\n- **Behaviors widgets**: Theses widgets do no rendering but act on the\n  graphics instructions or interaction (touch) behavior of their children.\n\n    :doc:`api-kivy.uix.scatter`, :doc:`api-kivy.uix.stencilview`\n\n- **Screen manager**: Manages screens and transitions when switching\n  from one to another.\n\n    :doc:`api-kivy.uix.screenmanager`\n\n----\n'''\n"
  },
  {
    "path": "tickeys/kivy/uix/abstractview.py",
    "content": "'''\nAbstract View\n=============\n\n.. versionadded:: 1.5\n\n.. warning::\n\n    This code is still experimental, and its API is subject to change in a\n    future version.\n\nThe :class:`~kivy.uix.abstractview.AbstractView` widget has an adapter property\nfor an adapter that mediates to data. The adapter manages an\nitem_view_instance dict property that holds views for each data item,\noperating as a cache.\n\n'''\n\n__all__ = ('AbstractView', )\n\nfrom kivy.uix.floatlayout import FloatLayout\nfrom kivy.properties import ObjectProperty\n\n\nclass AbstractView(FloatLayout):\n    '''\n    View using an :class:`~kivy.adapters.adapter.Adapter` as a data provider.\n    '''\n\n    adapter = ObjectProperty(None)\n    '''The adapter can be one of several kinds of\n    :class:`adapters <kivy.adapters.adapter.Adapter>`. The most\n    common example is the :class:`~kivy.adapters.listadapter.ListAdapter` used\n    for managing data items in a list.\n    '''\n"
  },
  {
    "path": "tickeys/kivy/uix/accordion.py",
    "content": "'''\nAccordion\n=========\n\n.. versionadded:: 1.0.8\n\n\n.. image:: images/accordion.jpg\n    :align: right\n\nThe Accordion widget is a form of menu where the options are stacked either\nvertically or horizontally and the item in focus (when touched) opens up to\ndisplay its content.\n\nThe :class:`Accordion` should contain one or many :class:`AccordionItem`\ninstances, each of which should contain one root content widget. You'll end up\nwith a Tree something like this:\n\n- Accordion\n\n  - AccordionItem\n\n    - YourContent\n\n  - AccordionItem\n\n    - BoxLayout\n\n      - Another user content 1\n\n      - Another user content 2\n\n  - AccordionItem\n\n    - Another user content\n\n\nThe current implementation divides the :class:`AccordionItem` into two parts:\n\n#. One container for the title bar\n#. One container for the content\n\nThe title bar is made from a Kv template. We'll see how to create a new\ntemplate to customize the design of the title bar.\n\n.. warning::\n\n    If you see message like::\n\n        [WARNING] [Accordion] not have enough space for displaying all children\n        [WARNING] [Accordion] need 440px, got 100px\n        [WARNING] [Accordion] layout aborted.\n\n    That means you have too many children and there is no more space to\n    display the content. This is \"normal\" and nothing will be done. Try to\n    increase the space for the accordion or reduce the number of children. You\n    can also reduce the :attr:`Accordion.min_space`.\n\nSimple example\n--------------\n\n.. include:: ../../examples/widgets/accordion_1.py\n    :literal:\n\nCustomize the accordion\n-----------------------\n\nYou can increase the default size of the title bar::\n\n    root = Accordion(min_space=60)\n\nOr change the orientation to vertical::\n\n    root = Accordion(orientation='vertical')\n\nThe AccordionItem is more configurable and you can set your own title\nbackground when the item is collapsed or opened::\n\n    item = AccordionItem(background_normal='image_when_collapsed.png',\n        background_selected='image_when_selected.png')\n\n'''\n\n__all__ = ('Accordion', 'AccordionItem', 'AccordionException')\n\nfrom kivy.animation import Animation\nfrom kivy.uix.floatlayout import FloatLayout\nfrom kivy.clock import Clock\nfrom kivy.lang import Builder\nfrom kivy.properties import (ObjectProperty, StringProperty,\n                             BooleanProperty, NumericProperty,\n                             ListProperty, OptionProperty, DictProperty)\nfrom kivy.uix.widget import Widget\nfrom kivy.logger import Logger\n\n\nclass AccordionException(Exception):\n    '''AccordionException class.\n    '''\n    pass\n\n\nclass AccordionItem(FloatLayout):\n    '''AccordionItem class that must be used in conjunction with the\n    :class:`Accordion` class. See the module documentation for more\n    information.\n    '''\n\n    title = StringProperty('')\n    '''Title string of the item. The title might be used in conjuction with the\n    `AccordionItemTitle` template. If you are using a custom template, you can\n    use that property as a text entry, or not. By default, it's used for the\n    title text. See title_template and the example below.\n\n    :attr:`title` is a :class:`~kivy.properties.StringProperty` and defaults\n    to ''.\n    '''\n\n    title_template = StringProperty('AccordionItemTitle')\n    '''Template to use for creating the title part of the accordion item. The\n    default template is a simple Label, not customizable (except the text) that\n    supports vertical and horizontal orientation and different backgrounds for\n    collapse and selected mode.\n\n    It's better to create and use your own template if the default template\n    does not suffice.\n\n    :attr:`title` is a :class:`~kivy.properties.StringProperty` and defaults to\n    'AccordionItemTitle'. The current default template lives in the\n    `kivy/data/style.kv` file.\n\n    Here is the code if you want to build your own template::\n\n        [AccordionItemTitle@Label]:\n            text: ctx.title\n            canvas.before:\n                Color:\n                    rgb: 1, 1, 1\n                BorderImage:\n                    source:\n                        ctx.item.background_normal \\\n                        if ctx.item.collapse \\\n                        else ctx.item.background_selected\n                    pos: self.pos\n                    size: self.size\n                PushMatrix\n                Translate:\n                    xy: self.center_x, self.center_y\n                Rotate:\n                    angle: 90 if ctx.item.orientation == 'horizontal' else 0\n                    axis: 0, 0, 1\n                Translate:\n                    xy: -self.center_x, -self.center_y\n            canvas.after:\n                PopMatrix\n\n\n    '''\n\n    title_args = DictProperty({})\n    '''Default arguments that will be passed to the\n    :meth:`kivy.lang.Builder.template` method.\n\n    :attr:`title_args` is a :class:`~kivy.properties.DictProperty` and defaults\n    to {}.\n    '''\n\n    collapse = BooleanProperty(True)\n    '''Boolean to indicate if the current item is collapsed or not.\n\n    :attr:`collapse` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n\n    collapse_alpha = NumericProperty(1.)\n    '''Value between 0 and 1 to indicate how much the item is collasped (1) or\n    whether it is selected (0). It's mostly used for animation.\n\n    :attr:`collapse_alpha` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 1.\n    '''\n\n    accordion = ObjectProperty(None)\n    '''Instance of the :class:`Accordion` that the item belongs to.\n\n    :attr:`accordion` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    background_normal = StringProperty(\n        'atlas://data/images/defaulttheme/button')\n    '''Background image of the accordion item used for the default graphical\n    representation when the item is collapsed.\n\n    :attr:`background_normal` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/button'.\n    '''\n\n    background_disabled_normal = StringProperty(\n        'atlas://data/images/defaulttheme/button_disabled')\n    '''Background image of the accordion item used for the default graphical\n    representation when the item is collapsed and disabled.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`background__disabled_normal` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/button_disabled'.\n    '''\n\n    background_selected = StringProperty(\n        'atlas://data/images/defaulttheme/button_pressed')\n    '''Background image of the accordion item used for the default graphical\n    representation when the item is selected (not collapsed).\n\n    :attr:`background_normal` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/button_pressed'.\n    '''\n\n    background_disabled_selected = StringProperty(\n        'atlas://data/images/defaulttheme/button_disabled_pressed')\n    '''Background image of the accordion item used for the default graphical\n    representation when the item is selected (not collapsed) and disabled.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`background_disabled_selected` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/button_disabled_pressed'.\n    '''\n\n    orientation = OptionProperty('vertical', options=(\n        'horizontal', 'vertical'))\n    '''Link to the :attr:`Accordion.orientation` property.\n    '''\n\n    min_space = NumericProperty('44dp')\n    '''Link to the :attr:`Accordion.min_space` property.\n    '''\n\n    content_size = ListProperty([100, 100])\n    '''(internal) Set by the :class:`Accordion` to the size allocated for the\n    content.\n    '''\n\n    container = ObjectProperty(None)\n    '''(internal) Property that will be set to the container of children inside\n    the AccordionItem representation.\n    '''\n\n    container_title = ObjectProperty(None)\n    '''(internal) Property that will be set to the container of title inside\n    the AccordionItem representation.\n    '''\n\n    def __init__(self, **kwargs):\n        self._trigger_title = Clock.create_trigger(self._update_title, -1)\n        self._anim_collapse = None\n        super(AccordionItem, self).__init__(**kwargs)\n        self.bind(title=self._trigger_title,\n                  title_template=self._trigger_title,\n                  title_args=self._trigger_title)\n        self._trigger_title()\n\n    def add_widget(self, widget):\n        if self.container is None:\n            return super(AccordionItem, self).add_widget(widget)\n        return self.container.add_widget(widget)\n\n    def remove_widget(self, widget):\n        if self.container:\n            self.container.remove_widget(widget)\n        super(AccordionItem, self).remove_widget(widget)\n\n    def on_collapse(self, instance, value):\n        accordion = self.accordion\n        if accordion is None:\n            return\n        if not value:\n            self.accordion.select(self)\n        collapse_alpha = float(value)\n        if self._anim_collapse:\n            self._anim_collapse.stop()\n            self._anim_collapse = None\n        if self.collapse_alpha != collapse_alpha:\n            self._anim_collapse = Animation(\n                collapse_alpha=collapse_alpha,\n                t=accordion.anim_func,\n                d=accordion.anim_duration).start(self)\n\n    def on_collapse_alpha(self, instance, value):\n        self.accordion._trigger_layout()\n\n    def on_touch_down(self, touch):\n        if not self.collide_point(*touch.pos):\n            return\n        if self.disabled:\n            return True\n        if self.collapse:\n            self.collapse = False\n            return True\n        else:\n            return super(AccordionItem, self).on_touch_down(touch)\n\n    def _update_title(self, dt):\n        if not self.container_title:\n            self._trigger_title()\n            return\n        c = self.container_title\n        c.clear_widgets()\n        instance = Builder.template(self.title_template,\n                                    title=self.title,\n                                    item=self,\n                                    **self.title_args)\n        c.add_widget(instance)\n\n\nclass Accordion(Widget):\n    '''Accordion class. See module documentation for more information.\n    '''\n\n    orientation = OptionProperty('horizontal', options=(\n        'horizontal', 'vertical'))\n    '''Orientation of the layout.\n\n    :attr:`orientation` is an :class:`~kivy.properties.OptionProperty`\n    and defaults to 'horizontal'. Can take a value of 'vertical' or\n    'horizontal'.\n\n    '''\n\n    anim_duration = NumericProperty(.25)\n    '''Duration of the animation in seconds when a new accordion item is\n    selected.\n\n    :attr:`anim_duration` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to .25 (250ms).\n    '''\n\n    anim_func = ObjectProperty('out_expo')\n    '''Easing function to use for the animation. Check\n    :class:`kivy.animation.AnimationTransition` for more information about\n    available animation functions.\n\n    :attr:`anim_func` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to 'out_expo'. You can set a string or a function to use as an\n    easing function.\n    '''\n\n    min_space = NumericProperty('44dp')\n    '''Minimum space to use for the title of each item. This value is\n    automatically set for each child every time the layout event occurs.\n\n    :attr:`min_space` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 44 (px).\n    '''\n\n    def __init__(self, **kwargs):\n        super(Accordion, self).__init__(**kwargs)\n        self._trigger_layout = Clock.create_trigger(self._do_layout, -1)\n        self.bind(\n            orientation=self._trigger_layout,\n            children=self._trigger_layout,\n            size=self._trigger_layout,\n            pos=self._trigger_layout,\n            min_space=self._trigger_layout)\n\n    def add_widget(self, widget, *largs):\n        if not isinstance(widget, AccordionItem):\n            raise AccordionException('Accordion accept only AccordionItem')\n\n        widget.accordion = self\n        ret = super(Accordion, self).add_widget(widget, *largs)\n        return ret\n\n    def select(self, instance):\n        if instance not in self.children:\n            raise AccordionException(\n                'Accordion: instance not found in children')\n        for widget in self.children:\n            widget.collapse = widget is not instance\n        self._trigger_layout()\n\n    def _do_layout(self, dt):\n        children = self.children\n        if children:\n            all_collapsed = all(x.collapse for x in children)\n        else:\n            all_collapsed = False\n\n        if all_collapsed:\n            children[0].collapse = False\n\n        orientation = self.orientation\n        min_space = self.min_space\n        min_space_total = len(children) * self.min_space\n        w, h = self.size\n        x, y = self.pos\n        if orientation == 'horizontal':\n            display_space = self.width - min_space_total\n        else:\n            display_space = self.height - min_space_total\n\n        if display_space <= 0:\n            Logger.warning('Accordion: not enough space '\n                           'for displaying all children')\n            Logger.warning('Accordion: need %dpx, got %dpx' % (\n                min_space_total, min_space_total + display_space))\n            Logger.warning('Accordion: layout aborted.')\n            return\n\n        if orientation == 'horizontal':\n            children = reversed(children)\n\n        for child in children:\n            child_space = min_space\n            child_space += display_space * (1 - child.collapse_alpha)\n            child._min_space = min_space\n            child.x = x\n            child.y = y\n            child.orientation = self.orientation\n            if orientation == 'horizontal':\n                child.content_size = display_space, h\n                child.width = child_space\n                child.height = h\n                x += child_space\n            else:\n                child.content_size = w, display_space\n                child.width = w\n                child.height = child_space\n                y += child_space\n\nif __name__ == '__main__':\n    from kivy.base import runTouchApp\n    from kivy.uix.button import Button\n    from kivy.uix.boxlayout import BoxLayout\n    from kivy.uix.label import Label\n\n    acc = Accordion()\n    for x in range(10):\n        item = AccordionItem(title='Title %d' % x)\n        if x == 0:\n            item.add_widget(Button(text='Content %d' % x))\n        elif x == 1:\n            l = BoxLayout(orientation='vertical')\n            l.add_widget(Button(text=str(x), size_hint_y=None, height=35))\n            l.add_widget(Label(text='Content %d' % x))\n            item.add_widget(l)\n        else:\n            item.add_widget(Label(text='This is a big content\\n' * 20))\n        acc.add_widget(item)\n\n    def toggle_layout(*l):\n        o = acc.orientation\n        acc.orientation = 'vertical' if o == 'horizontal' else 'horizontal'\n    btn = Button(text='Toggle layout')\n    btn.bind(on_release=toggle_layout)\n\n    def select_2nd_item(*l):\n        acc.select(acc.children[-2])\n    btn2 = Button(text='Select 2nd item')\n    btn2.bind(on_release=select_2nd_item)\n\n    from kivy.uix.slider import Slider\n    slider = Slider()\n\n    def update_min_space(instance, value):\n        acc.min_space = value\n\n    slider.bind(value=update_min_space)\n\n    root = BoxLayout(spacing=20, padding=20)\n    controls = BoxLayout(orientation='vertical', size_hint_x=.3)\n    controls.add_widget(btn)\n    controls.add_widget(btn2)\n    controls.add_widget(slider)\n    root.add_widget(controls)\n    root.add_widget(acc)\n    runTouchApp(root)\n"
  },
  {
    "path": "tickeys/kivy/uix/actionbar.py",
    "content": "'''\nAction Bar\n==========\n\n.. versionadded:: 1.8.0\n\n.. image:: images/actionbar.png\n    :align: right\n\nThe ActionBar widget is like Android's ActionBar, where items are stacked\nhorizontally.\n\nThe :class:`ActionBar` will contain one :class:`ActionView` and many\n:class:`ContextualActionView`\\s.\nAn :class:`ActionView` will contain an :class:`ActionPrevious` having title,\napp_icon and previous_icon properties. An :class:`ActionView` will contain\nsubclasses of :class:`ActionItem`\\s. Some predefined ones inlcude an\n:class:`ActionButton`, an :class:`ActionToggleButton`, an :class:`ActionCheck`,\nan :class:`ActionSeparator` and an :class:`ActionGroup`.\n\nAn :class:`ActionGroup` is used to display :class:`ActionItem`\\s in a group.\nAn :class:`ActionView` will always display an :class:`ActionGroup` after other\n:class:`ActionItem`\\s.\nAn :class:`ActionView` will contain an :class:`ActionOverflow`.\nA :class:`ContextualActionView` is a subclass of an :class:`ActionView`.\n'''\n\n__all__ = ('ActionBarException', 'ActionItem', 'ActionButton',\n           'ActionToggleButton', 'ActionCheck', 'ActionSeparator',\n           'ActionDropDown', 'ActionGroup', 'ActionOverflow',\n           'ActionView', 'ContextualActionView', 'ActionPrevious',\n           'ActionBar')\n\nfrom kivy.uix.boxlayout import BoxLayout\nfrom kivy.uix.dropdown import DropDown\nfrom kivy.uix.widget import Widget\nfrom kivy.uix.button import Button\nfrom kivy.uix.togglebutton import ToggleButton\nfrom kivy.uix.checkbox import CheckBox\nfrom kivy.uix.spinner import Spinner\nfrom kivy.config import Config\nfrom kivy.properties import ObjectProperty, NumericProperty, \\\n    BooleanProperty, StringProperty, ListProperty, OptionProperty\nfrom kivy.metrics import sp\nfrom kivy.lang import Builder\nfrom functools import partial\n\n\nwindow_icon = ''\nif Config:\n    window_icon = Config.get('kivy', 'window_icon')\n\n\nclass ActionBarException(Exception):\n    '''ActionBarException class\n    '''\n    pass\n\n\nclass ActionItem(object):\n    '''ActionItem class, an abstract class for all ActionBar widgets. To create\n       a custom widget for an ActionBar, inherit from this\n       class. See module documentation for more information.\n    '''\n\n    minimum_width = NumericProperty('90sp')\n    '''Minimum Width required by an ActionItem.\n\n       :attr:`minimum_width` is a :class:`~kivy.properties.NumericProperty` and\n       defaults to '90sp'.\n    '''\n\n    important = BooleanProperty(False)\n    '''Determines if an ActionItem is important or not.\n\n       :attr:`important` is a :class:`~kivy.properties.BooleanProperty` and\n       defaults to False.\n    '''\n\n    inside_group = BooleanProperty(False)\n    '''(internal) Determines if an ActionItem is displayed inside an\n       ActionGroup or not.\n\n       :attr:`inside_group` is a :class:`~kivy.properties.BooleanProperty` and\n       defaults to False.\n    '''\n\n    background_normal = StringProperty(\n        'atlas://data/images/defaulttheme/action_item')\n    '''Background image of the ActionItem used for the default graphical\n       representation when the ActionItem is not pressed.\n\n       :attr:`background_normal` is a :class:`~kivy.properties.StringProperty`\n       and defaults to 'atlas://data/images/defaulttheme/action_item'.\n    '''\n\n    background_down = StringProperty(\n        'atlas://data/images/defaulttheme/action_item_down')\n    '''Background image of the ActionItem used for default graphical\n       representation when an ActionItem is pressed.\n\n       :attr:`background_down` is a :class:`~kivy.properties.StringProperty`\n       and defaults to 'atlas://data/images/defaulttheme/action_item_down'.\n    '''\n\n    mipmap = BooleanProperty(True)\n    '''Defines whether the image/icon dispayed on top of the button uses a\n    mipmap or not.\n\n    :attr:`mipmap` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to `True`.\n    '''\n\n\nclass ActionButton(Button, ActionItem):\n    '''ActionButton class, see module documentation for more information.\n\n    The text color, width and size_hint_x are set manually via the Kv language\n    file. It covers a lot of cases: with/without an icon, with/without a group\n    and takes care of the padding between elements.\n\n    You don't have much control over these properties, so if you want to\n    customize it's appearance, we suggest you create you own button\n    representation. You can do this by creating a class that subclasses an\n    existing widget and an :class:`ActionItem`::\n\n        class MyOwnActionButton(Button, ActionItem):\n            pass\n\n    You can then create your own style using the Kv language.\n    '''\n\n    icon = StringProperty(None, allownone=True)\n    '''Source image to use when the Button is part of the ActionBar. If the\n    Button is in a group, the text will be preferred.\n    '''\n\n\nclass ActionPrevious(ActionButton):\n    '''ActionPrevious class, see module documentation for more information.\n    '''\n\n    with_previous = BooleanProperty(True)\n    '''Specifies whether clicking on ActionPrevious will load the previous\n       screen or not. If True, the previous_icon will be shown otherwise it\n       will not.\n\n       :attr:`with_previous` is a :class:`~kivy.properties.BooleanProperty` and\n       defaults to True.\n    '''\n\n    app_icon = StringProperty(window_icon)\n    '''Application icon for the ActionView.\n\n       :attr:`app_icon` is a :class:`~kivy.properties.StringProperty`\n       and defaults to the window icon if set, otherwise\n       'data/logo/kivy-icon-32.png'.\n    '''\n\n    app_icon_width = NumericProperty(0)\n    '''Width of app_icon image.\n    '''\n\n    app_icon_height = NumericProperty(0)\n    '''Height of app_icon image.\n    '''\n\n    previous_image = StringProperty(\n        'atlas://data/images/defaulttheme/previous_normal')\n    '''Image for the 'previous' ActionButtons default graphical representation.\n\n       :attr:`previous_image` is a :class:`~kivy.properties.StringProperty` and\n       defaults to 'atlas://data/images/defaulttheme/previous_normal'.\n    '''\n\n    previous_image_width = NumericProperty(0)\n    '''Width of previous_image image.\n    '''\n\n    previous_image_height = NumericProperty(0)\n    '''Height of previous_image image.\n    '''\n\n    title = StringProperty('')\n    '''Title for ActionView.\n\n       :attr:`title` is a :class:`~kivy.properties.StringProperty` and\n       defaults to ''.\n    '''\n\n    def __init__(self, **kwargs):\n        super(ActionPrevious, self).__init__(**kwargs)\n        if not self.app_icon:\n            self.app_icon = 'data/logo/kivy-icon-32.png'\n\n\nclass ActionToggleButton(ActionItem, ToggleButton):\n    '''ActionToggleButton class, see module documentation for more information.\n    '''\n\n    icon = StringProperty(None, allownone=True)\n    '''Source image to use when the Button is part of the ActionBar. If the\n    Button is in a group, the text will be preferred.\n    '''\n\n\nclass ActionCheck(ActionItem, CheckBox):\n    '''ActionCheck class, see module documentation for more information.\n    '''\n    pass\n\n\nclass ActionSeparator(ActionItem, Widget):\n    '''ActionSeparator class, see module documentation for more information.\n    '''\n\n    background_image = StringProperty(\n        'atlas://data/images/defaulttheme/separator')\n    '''Background image for the separators default graphical representation.\n\n       :attr:`background_image` is a :class:`~kivy.properties.StringProperty`\n       and defaults to 'atlas://data/images/defaulttheme/separator'.\n    '''\n\n\nclass ActionDropDown(DropDown):\n    '''ActionDropDown class, see module documentation for more information.\n    '''\n    pass\n\n\nclass ActionGroup(ActionItem, Spinner):\n    '''ActionGroup class, see module documentation for more information.\n    '''\n\n    use_separator = BooleanProperty(False)\n    '''Specifies whether to use a separator after/before this group or not.\n\n       :attr:`use_separator` is a :class:`~kivy.properties.BooleanProperty` and\n       defaults to False.\n    '''\n\n    separator_image = StringProperty(\n        'atlas://data/images/defaulttheme/separator')\n    '''Background Image for an ActionSeparator in an ActionView.\n\n       :attr:`separator_image` is a :class:`~kivy.properties.StringProperty`\n       and defaults to 'atlas://data/images/defaulttheme/separator'.\n    '''\n\n    separator_width = NumericProperty(0)\n    '''Width of the ActionSeparator in an ActionView.\n\n       :attr:`separator_width` is a :class:`~kivy.properties.NumericProperty`\n       and defaults to 0.\n    '''\n\n    mode = OptionProperty('normal', options=('normal', 'spinner'))\n    '''Sets the current mode of an ActionGroup. If mode is 'normal', the\n       ActionGroups children will be displayed normally if there is enough\n       space, otherwise they will be displayed in a spinner. If mode is\n       'spinner', then the children will always be displayed in a spinner.\n\n       :attr:`mode` is a :class:`~kivy.properties.OptionProperty` and\n       defaults to 'normal'.\n    '''\n\n    def __init__(self, **kwargs):\n        self.list_action_item = []\n        self._list_overflow_items = []\n        super(ActionGroup, self).__init__(**kwargs)\n        self.dropdown_cls = ActionDropDown\n\n    def add_widget(self, item):\n        if isinstance(item, ActionSeparator):\n            super(ActionGroup, self).add_widget(item)\n            return\n\n        if not isinstance(item, ActionItem):\n            raise ActionBarException('ActionGroup only accepts ActionItem')\n\n        self.list_action_item.append(item)\n\n    def show_group(self):\n        self.clear_widgets()\n        for item in self._list_overflow_items + self.list_action_item:\n            item.inside_group = True\n            self._dropdown.add_widget(item)\n\n    def _build_dropdown(self, *largs):\n        if self._dropdown:\n            self._dropdown.unbind(on_dismiss=self._toggle_dropdown)\n            self._dropdown.dismiss()\n            self._dropdown = None\n        self._dropdown = self.dropdown_cls()\n        self._dropdown.bind(on_dismiss=self._toggle_dropdown)\n\n    def _update_dropdown(self, *largs):\n        pass\n\n    def _toggle_dropdown(self, *largs):\n        self.is_open = not self.is_open\n        ddn = self._dropdown\n        ddn.size_hint_x = None\n        if not ddn.container:\n            return\n        children = ddn.container.children\n\n        if children:\n            ddn.width = max([self.width, children[0].minimum_width])\n        else:\n            ddn.width = self.width\n\n        for item in children:\n            item.size_hint_y = None\n            item.height = max([self.height, sp(48)])\n\n    def clear_widgets(self):\n        self._dropdown.clear_widgets()\n\n\nclass ActionOverflow(ActionGroup):\n    '''ActionOverflow class, see module documentation for more information.\n    '''\n\n    overflow_image = StringProperty(\n        'atlas://data/images/defaulttheme/overflow')\n    '''Image to be used as an Overflow Image.\n\n      :attr:`overflow_image` is an :class:`~kivy.properties.ObjectProperty` and\n       defaults to 'atlas://data/images/defaulttheme/overflow'.\n    '''\n\n    def add_widget(self, action_item, index=0):\n        if action_item is None:\n            return\n\n        if isinstance(action_item, ActionSeparator):\n            return\n\n        if not isinstance(action_item, ActionItem):\n            raise ActionBarException('ActionView only accepts ActionItem'\n                                     ' (got {!r}'.format(action_item))\n\n        else:\n            if index == 0:\n                index = len(self._list_overflow_items)\n            self._list_overflow_items.insert(index, action_item)\n\n    def show_default_items(self, parent):\n        # display overflow and it's items if widget's directly added to it\n        if self._list_overflow_items == []:\n            return\n        self.show_group()\n        super(ActionView, parent).add_widget(self)\n\n\nclass ActionView(BoxLayout):\n    '''ActionView class, see module documentation for more information.\n    '''\n\n    action_previous = ObjectProperty(None)\n    '''Previous button for an ActionView.\n\n       :attr:`action_previous` is an :class:`~kivy.properties.ObjectProperty`\n        and defaults to None.\n    '''\n\n    background_color = ListProperty([1, 1, 1, 1])\n    '''Background color in the format (r, g, b, a).\n\n       :attr:`background_color` is a :class:`~kivy.properties.ListProperty` and\n        defaults to [1, 1, 1, 1].\n    '''\n\n    background_image = StringProperty(\n        'atlas://data/images/defaulttheme/action_view')\n    '''Background image of an ActionViews default graphical representation.\n\n      :attr:`background_image` is an :class:`~kivy.properties.StringProperty`\n      and defaults to 'atlas://data/images/defaulttheme/action_view'.\n    '''\n\n    use_separator = BooleanProperty(False)\n    '''Specify whether to use a separator before every ActionGroup or not.\n\n       :attr:`use_separator` is a :class:`~kivy.properties.BooleanProperty` and\n       defaults to False.\n    '''\n\n    overflow_group = ObjectProperty(None)\n    '''Widget to be used for the overflow.\n\n       :attr:`overflow_group` is an :class:`~kivy.properties.ObjectProperty`\n       and defaults to an instance of :class:`ActionOverflow`.\n    '''\n\n    def __init__(self, **kwargs):\n        self._list_action_items = []\n        self._list_action_group = []\n        super(ActionView, self).__init__(**kwargs)\n        self._state = ''\n        if not self.overflow_group:\n            self.overflow_group = ActionOverflow(\n                use_separator=self.use_separator)\n\n    def on_action_previous(self, instance, value):\n        self._list_action_items.insert(0, value)\n\n    def add_widget(self, action_item, index=0):\n        if action_item is None:\n            return\n\n        if not isinstance(action_item, ActionItem):\n            raise ActionBarException('ActionView only accepts ActionItem'\n                                     ' (got {!r}'.format(action_item))\n\n        elif isinstance(action_item, ActionOverflow):\n            self.overflow_group = action_item\n            action_item.use_separator = self.use_separator\n\n        elif isinstance(action_item, ActionGroup):\n            self._list_action_group.append(action_item)\n            action_item.use_separator = self.use_separator\n\n        elif isinstance(action_item, ActionPrevious):\n            self.action_previous = action_item\n\n        else:\n            super(ActionView, self).add_widget(action_item, index)\n            if index == 0:\n                index = len(self._list_action_items)\n            self._list_action_items.insert(index, action_item)\n\n    def on_use_separator(self, instance, value):\n        for group in self._list_action_group:\n            group.use_separator = value\n        self.overflow_group.use_separator = value\n\n    def _clear_all(self):\n        self.clear_widgets()\n        for group in self._list_action_group:\n            group.clear_widgets()\n\n        self.overflow_group.clear_widgets()\n        self.overflow_group.list_action_item = []\n\n    def _layout_all(self):\n        # all the items can fit to the view, so expand everything\n        super_add = super(ActionView, self).add_widget\n        self._state = 'all'\n        self._clear_all()\n        super_add(self.action_previous)\n        if len(self._list_action_items) > 1:\n            for child in self._list_action_items[1:]:\n                child.inside_group = False\n                super_add(child)\n\n        for group in self._list_action_group:\n            if group.mode == 'spinner':\n                super_add(group)\n                group.show_group()\n            else:\n                if group.list_action_item != []:\n                    super_add(ActionSeparator())\n                for child in group.list_action_item:\n                    child.inside_group = False\n                    super_add(child)\n\n        self.overflow_group.show_default_items(self)\n\n    def _layout_group(self):\n        # layout all the items in order to pack them per group\n        super_add = super(ActionView, self).add_widget\n        self._state = 'group'\n        self._clear_all()\n        super_add(self.action_previous)\n        if len(self._list_action_items) > 1:\n            for child in self._list_action_items[1:]:\n                super_add(child)\n                child.inside_group = False\n\n        for group in self._list_action_group:\n            super_add(group)\n            group.show_group()\n\n        self.overflow_group.show_default_items(self)\n\n    def _layout_random(self):\n        # layout the items in order to pack all of them grouped, and display\n        # only the action items having 'important'\n        super_add = super(ActionView, self).add_widget\n        self._state = 'random'\n        self._clear_all()\n        hidden_items = []\n        hidden_groups = []\n        total_width = 0\n        super_add(self.action_previous)\n\n        width = (self.width - self.overflow_group.minimum_width -\n                 self.action_previous.minimum_width)\n\n        if len(self._list_action_items):\n            for child in self._list_action_items[1:]:\n                if child.important:\n                    if child.minimum_width + total_width < width:\n                        super_add(child)\n                        child.inside_group = False\n                        total_width += child.minimum_width\n                    else:\n                        hidden_items.append(child)\n                else:\n                    hidden_items.append(child)\n\n        # if space is left then display ActionItem inside their\n        # ActionGroup\n        if total_width < self.width:\n            for group in self._list_action_group:\n                if group.minimum_width + total_width +\\\n                   group.separator_width < width:\n                    super_add(group)\n                    group.show_group()\n                    total_width += (group.minimum_width +\n                                    group.separator_width)\n\n                else:\n                    hidden_groups.append(group)\n\n        group_index = len(self.children) - 1\n        # if space is left then display other ActionItems\n        if total_width < self.width:\n            for child in hidden_items[:]:\n                if child.minimum_width + total_width < width:\n                    super_add(child, group_index)\n                    total_width += child.minimum_width\n                    child.inside_group = False\n                    hidden_items.remove(child)\n\n        # for all the remaining ActionItems and ActionItems with in\n        # ActionGroups, Display them inside overflow_group\n        extend_hidden = hidden_items.extend\n        for group in hidden_groups:\n            extend_hidden(group.list_action_item)\n\n        overflow_group = self.overflow_group\n\n        if hidden_items != []:\n            over_add = super(overflow_group.__class__,\n                             overflow_group).add_widget\n            for child in hidden_items:\n                over_add(child)\n\n            overflow_group.show_group()\n            super_add(overflow_group)\n\n    def on_width(self, width, *args):\n        # determine the layout to use\n\n        # can we display all of them?\n        total_width = 0\n        for child in self._list_action_items:\n            total_width += child.minimum_width\n        for group in self._list_action_group:\n            for child in group.list_action_item:\n                total_width += child.minimum_width\n        if total_width <= self.width:\n            if self._state != 'all':\n                self._layout_all()\n            return\n\n        # can we display them per group?\n        total_width = 0\n        for child in self._list_action_items:\n            total_width += child.minimum_width\n        for group in self._list_action_group:\n            total_width += group.minimum_width\n        if total_width < self.width:\n            # ok, we can display all the items grouped\n            if self._state != 'group':\n                self._layout_group()\n            return\n\n        # none of the solutions worked, display them in pack mode\n        self._layout_random()\n\n\nclass ContextualActionView(ActionView):\n    '''ContextualActionView class, see the module documentation\n       for more information.\n    '''\n    pass\n\n\nclass ActionBar(BoxLayout):\n    '''ActionBar, see the module documentation for more information.\n\n    :Events:\n        `on_previous`\n            Fired when action_previous of action_view is pressed.\n    '''\n\n    action_view = ObjectProperty(None)\n    '''action_view of ActionBar.\n\n       :attr:`action_view` is an :class:`~kivy.properties.ObjectProperty` and\n       defaults to an instance of ActionView.\n    '''\n\n    background_color = ListProperty([1, 1, 1, 1])\n    '''Background color, in the format (r, g, b, a).\n\n       :attr:`background_color` is a :class:`~kivy.properties.ListProperty` and\n        defaults to [1, 1, 1, 1].\n    '''\n\n    background_image = StringProperty(\n        'atlas://data/images/defaulttheme/action_bar')\n\n    '''Background image of the ActionBars default graphical representation.\n\n      :attr:`background_image` is an :class:`~kivy.properties.StringProperty`\n      and defaults to 'atlas://data/images/defaulttheme/action_bar'.\n    '''\n\n    border = ListProperty([2, 2, 2, 2])\n    ''':attr:`border` to be applied to the :attr:`background_image`.\n    '''\n\n    __events__ = ('on_previous',)\n\n    def __init__(self, **kwargs):\n        super(ActionBar, self).__init__(**kwargs)\n        self._stack_cont_action_view = []\n        self._emit_previous = partial(self.dispatch, 'on_previous')\n\n    def add_widget(self, view):\n        if isinstance(view, ContextualActionView):\n            self._stack_cont_action_view.append(view)\n            if view.action_previous is not None:\n                view.action_previous.unbind(on_release=self._emit_previous)\n                view.action_previous.bind(on_release=self._emit_previous)\n            self.clear_widgets()\n            super(ActionBar, self).add_widget(view)\n\n        elif isinstance(view, ActionView):\n            self.action_view = view\n            super(ActionBar, self).add_widget(view)\n\n        else:\n            raise ActionBarException(\n                'ActionBar can only add ContextualActionView or ActionView')\n\n    def on_previous(self, *args):\n        self._pop_contextual_action_view()\n\n    def _pop_contextual_action_view(self):\n        '''Remove the current ContextualActionView and display either the\n           previous one or the ActionView.\n        '''\n        self._stack_cont_action_view.pop()\n        self.clear_widgets()\n        if self._stack_cont_action_view == []:\n            super(ActionBar, self).add_widget(self.action_view)\n        else:\n            super(ActionBar, self).add_widget(self._stack_cont_action_view[-1])\n\n\nif __name__ == \"__main__\":\n    from kivy.base import runTouchApp\n    from kivy.uix.floatlayout import FloatLayout\n    from kivy.factory import Factory\n\n    # XXX clean the first registration done from '__main__' here.\n    # otherwise kivy.uix.actionbar.ActionPrevious != __main__.ActionPrevious\n    Factory.unregister('ActionPrevious')\n\n    Builder.load_string('''\n<MainWindow>:\n    ActionBar:\n        pos_hint: {'top':1}\n        ActionView:\n            use_separator: True\n            ActionPrevious:\n                title: 'Action Bar'\n                with_previous: False\n            ActionOverflow:\n            ActionButton:\n                text: 'Btn0'\n                icon: 'atlas://data/images/defaulttheme/audio-volume-high'\n            ActionButton:\n                text: 'Btn1'\n            ActionButton:\n                text: 'Btn2'\n            ActionGroup:\n                text: 'Group 2'\n                ActionButton:\n                    text: 'Btn3'\n                ActionButton:\n                    text: 'Btn4'\n            ActionGroup:\n                text: 'Group1'\n                ActionButton:\n                    text: 'Btn5'\n                ActionButton:\n                    text: 'Btn6'\n                ActionButton:\n                    text: 'Btn7'\n''')\n\n    class MainWindow(FloatLayout):\n        pass\n\n    float_layout = MainWindow()\n    runTouchApp(float_layout)\n"
  },
  {
    "path": "tickeys/kivy/uix/anchorlayout.py",
    "content": "'''\nAnchor Layout\n=============\n\n.. only:: html\n\n    .. image:: images/anchorlayout.gif\n        :align: right\n\n.. only:: latex\n\n    .. image:: images/anchorlayout.png\n        :align: right\n\nThe :class:`AnchorLayout` aligns its children to a border (top, bottom,\nleft, right) or center.\n\n\nTo draw a button in the lower-right corner::\n\n    layout = AnchorLayout(\n        anchor_x='right', anchor_y='bottom')\n    btn = Button(text='Hello World')\n    layout.add_widget(btn)\n\n'''\n\n__all__ = ('AnchorLayout', )\n\nfrom kivy.uix.layout import Layout\nfrom kivy.properties import OptionProperty, VariableListProperty\n\n\nclass AnchorLayout(Layout):\n    '''Anchor layout class. See the module documentation for more information.\n    '''\n\n    padding = VariableListProperty([0, 0, 0, 0])\n    '''Padding between the widget box and its children, in pixels:\n    [padding_left, padding_top, padding_right, padding_bottom].\n\n    padding also accepts a two argument form [padding_horizontal,\n    padding_vertical] and a one argument form [padding].\n\n    :attr:`padding` is a :class:`~kivy.properties.VariableListProperty` and\n    defaults to [0, 0, 0, 0].\n    '''\n\n    anchor_x = OptionProperty('center', options=(\n        'left', 'center', 'right'))\n    '''Horizontal anchor.\n\n    :attr:`anchor_x` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to 'center'. It accepts values of 'left', 'center' or\n    'right'.\n    '''\n\n    anchor_y = OptionProperty('center', options=(\n        'top', 'center', 'bottom'))\n    '''Vertical anchor.\n\n    :attr:`anchor_y` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to 'center'. It accepts values of 'top', 'center' or\n    'bottom'.\n    '''\n\n    def __init__(self, **kwargs):\n        super(AnchorLayout, self).__init__(**kwargs)\n        self.bind(\n            children=self._trigger_layout,\n            parent=self._trigger_layout,\n            padding=self._trigger_layout,\n            anchor_x=self._trigger_layout,\n            anchor_y=self._trigger_layout,\n            size=self._trigger_layout,\n            pos=self._trigger_layout)\n\n    def do_layout(self, *largs):\n        _x, _y = self.pos\n        width = self.width\n        height = self.height\n        anchor_x = self.anchor_x\n        anchor_y = self.anchor_y\n        padding = self.padding\n\n        for c in self.children:\n            x, y = _x, _y\n            w, h = c.size\n            if c.size_hint[0] is not None:\n                w = c.size_hint[0] * width - (padding[0] + padding[2])\n            if c.size_hint[1] is not None:\n                h = c.size_hint[1] * height - (padding[1] + padding[3])\n\n            if anchor_x == 'left':\n                x = x + padding[0]\n            if anchor_x == 'right':\n                x = x + width - (w + padding[2])\n            if self.anchor_x == 'center':\n                x = x + (width / 2) - (w / 2)\n            if anchor_y == 'bottom':\n                y = y + padding[1]\n            if anchor_y == 'top':\n                y = y + height - (h + padding[3])\n            if anchor_y == 'center':\n                y = y + (height / 2) - (h / 2)\n\n            c.x = x\n            c.y = y\n            c.width = w\n            c.height = h\n"
  },
  {
    "path": "tickeys/kivy/uix/behaviors.py",
    "content": "'''\nBehaviors\n=========\n\n.. versionadded:: 1.8.0\n\nThis module implements behaviors that can be mixed with existing base widgets.\nFor example, if you want to add a \"button\" capability to an `Image`, you could\ndo::\n\n\n    class IconButton(ButtonBehavior, Image):\n        pass\n\n.. note::\n\n    The behavior class must always be _before_ the widget class. If you don't\n    specify the inheritance in this order, the behavior will not work because\n    the behavior methods are overwritten by the class method listed first.\n\n    Similarly, if you combine a behavior class with a class which\n    requires the use of the methods also defined by the behavior class, the\n    resulting class may not function properly. E.g. combining a ButtonBehavior\n    with a Slider, both of which require the on_touch_up methods, the resulting\n    class will not work.\n\n'''\n\n__all__ = ('ButtonBehavior', 'ToggleButtonBehavior', 'DragBehavior',\n           'FocusBehavior', 'CompoundSelectionBehavior')\n\nfrom kivy.clock import Clock\nfrom kivy.properties import OptionProperty, ObjectProperty, NumericProperty,\\\n    ReferenceListProperty, BooleanProperty, ListProperty, AliasProperty\nfrom kivy.config import Config\nfrom kivy.metrics import sp\nfrom kivy.base import EventLoop\nfrom kivy.logger import Logger\nfrom functools import partial\nfrom weakref import ref\nfrom time import time\nimport string\n\n# When we are generating documentation, Config doesn't exist\n_scroll_timeout = _scroll_distance = 0\n_is_desktop = False\n_keyboard_mode = 'system'\nif Config:\n    _scroll_timeout = Config.getint('widgets', 'scroll_timeout')\n    _scroll_distance = Config.getint('widgets', 'scroll_distance')\n    _is_desktop = Config.getboolean('kivy', 'desktop')\n    _keyboard_mode = Config.get('kivy', 'keyboard_mode')\n\n\nclass ButtonBehavior(object):\n    '''Button behavior.\n\n    :Events:\n        `on_press`\n            Fired when the button is pressed.\n        `on_release`\n            Fired when the button is released (i.e. the touch/click that\n            pressed the button goes away).\n    '''\n\n    state = OptionProperty('normal', options=('normal', 'down'))\n    '''State of the button, must be one of 'normal' or 'down'.\n    The state is 'down' only when the button is currently touched/clicked,\n    otherwise 'normal'.\n\n    :attr:`state` is an :class:`~kivy.properties.OptionProperty`.\n    '''\n\n    last_touch = ObjectProperty(None)\n    '''Contains the last relevant touch received by the Button. This can\n    be used in `on_press` or `on_release` in order to know which touch\n    dispatched the event.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`last_touch` is a :class:`~kivy.properties.ObjectProperty`,\n    defaults to None.\n    '''\n\n    MIN_STATE_TIME = 0.035\n    '''The minimum period of time which the widget must remain in the\n    `'down'` state.\n\n    :attr:`MIN_STATE_TIME` is a float.\n    '''\n\n    always_release = BooleanProperty(True)\n    '''This determines if the widget fires a `on_release` event if\n    the touch_up is outside the widget.\n\n    ..versionadded:: 1.9.0\n\n    :attr:`always_release` is a :class:`~kivy.properties.BooleanProperty`,\n    defaults to `True`.\n    '''\n\n    def __init__(self, **kwargs):\n        self.register_event_type('on_press')\n        self.register_event_type('on_release')\n        super(ButtonBehavior, self).__init__(**kwargs)\n        self.__state_event = None\n        self.__touch_time = None\n        self.bind(state=self.cancel_event)\n\n    def _do_press(self):\n        self.state = 'down'\n\n    def _do_release(self, *args):\n        self.state = 'normal'\n\n    def cancel_event(self, *args):\n        if self.__state_event:\n            self.__state_event.cancel()\n            self.__state_event = None\n\n    def on_touch_down(self, touch):\n        if super(ButtonBehavior, self).on_touch_down(touch):\n            return True\n        if touch.is_mouse_scrolling:\n            return False\n        if not self.collide_point(touch.x, touch.y):\n            return False\n        if self in touch.ud:\n            return False\n        touch.grab(self)\n        touch.ud[self] = True\n        self.last_touch = touch\n        self.__touch_time = time()\n        self._do_press()\n        self.dispatch('on_press')\n        return True\n\n    def on_touch_move(self, touch):\n        if touch.grab_current is self:\n            return True\n        if super(ButtonBehavior, self).on_touch_move(touch):\n            return True\n        return self in touch.ud\n\n    def on_touch_up(self, touch):\n        if touch.grab_current is not self:\n            return super(ButtonBehavior, self).on_touch_up(touch)\n        assert(self in touch.ud)\n        touch.ungrab(self)\n        self.last_touch = touch\n\n        if (not self.always_release\n                and not self.collide_point(*touch.pos)):\n            self.state = 'normal'\n            return\n\n        touchtime = time() - self.__touch_time\n        if touchtime < self.MIN_STATE_TIME:\n            self.__state_event = Clock.schedule_once(\n                self._do_release, self.MIN_STATE_TIME - touchtime)\n        else:\n            self._do_release()\n        self.dispatch('on_release')\n        return True\n\n    def on_press(self):\n        pass\n\n    def on_release(self):\n        pass\n\n    def trigger_action(self, duration=0.1):\n        '''Trigger whatever action(s) have been bound to the button by calling\n        both the on_press and on_release callbacks.\n\n        This simulates a quick button press without using any touch events.\n\n        Duration is the length of the press in seconds. Pass 0 if you want\n        the action to happen instantly.\n\n        .. versionadded:: 1.8.0\n        '''\n        self._do_press()\n        self.dispatch('on_press')\n\n        def trigger_release(dt):\n            self._do_release()\n            self.dispatch('on_release')\n        if not duration:\n            trigger_release(0)\n        else:\n            Clock.schedule_once(trigger_release, duration)\n\n\nclass ToggleButtonBehavior(ButtonBehavior):\n    '''ToggleButton behavior, see ToggleButton module documentation for more\n    information.\n\n    .. versionadded:: 1.8.0\n    '''\n\n    __groups = {}\n\n    group = ObjectProperty(None, allownone=True)\n    '''Group of the button. If None, no group will be used (button is\n    independent). If specified, :attr:`group` must be a hashable object, like\n    a string. Only one button in a group can be in 'down' state.\n\n    :attr:`group` is a :class:`~kivy.properties.ObjectProperty`\n    '''\n\n    allow_no_selection = BooleanProperty(True)\n    '''This specifies whether the checkbox in group allows everything to\n    be deselected.\n\n    ..versionadded::1.9.0\n\n    :attr:`allow_no_selection` is a :class:`BooleanProperty` defaults to\n    `True`\n    '''\n\n    def __init__(self, **kwargs):\n        self._previous_group = None\n        super(ToggleButtonBehavior, self).__init__(**kwargs)\n\n    def on_group(self, *largs):\n        groups = ToggleButtonBehavior.__groups\n        if self._previous_group:\n            group = groups[self._previous_group]\n            for item in group[:]:\n                if item() is self:\n                    group.remove(item)\n                    break\n        group = self._previous_group = self.group\n        if group not in groups:\n            groups[group] = []\n        r = ref(self, ToggleButtonBehavior._clear_groups)\n        groups[group].append(r)\n\n    def _release_group(self, current):\n        if self.group is None:\n            return\n        group = self.__groups[self.group]\n        for item in group[:]:\n            widget = item()\n            if widget is None:\n                group.remove(item)\n            if widget is current:\n                continue\n            widget.state = 'normal'\n\n    def _do_press(self):\n        if (not self.allow_no_selection and\n            self.group and self.state == 'down'):\n            return\n        self._release_group(self)\n        self.state = 'normal' if self.state == 'down' else 'down'\n\n    def _do_release(self, *args):\n        pass\n\n    @staticmethod\n    def _clear_groups(wk):\n        # auto flush the element when the weak reference have been deleted\n        groups = ToggleButtonBehavior.__groups\n        for group in list(groups.values()):\n            if wk in group:\n                group.remove(wk)\n                break\n\n    @staticmethod\n    def get_widgets(groupname):\n        '''Return the widgets contained in a specific group. If the group\n        doesn't exist, an empty list will be returned.\n\n        .. important::\n\n            Always release the result of this method! In doubt, do::\n\n                l = ToggleButtonBehavior.get_widgets('mygroup')\n                # do your job\n                del l\n\n        .. warning::\n\n            It's possible that some widgets that you have previously\n            deleted are still in the list. Garbage collector might need\n            more elements before flushing it. The return of this method\n            is informative, you've been warned!\n        '''\n        groups = ToggleButtonBehavior.__groups\n        if groupname not in groups:\n            return []\n        return [x() for x in groups[groupname] if x()][:]\n\n\nclass DragBehavior(object):\n    '''Drag behavior. When combined with a widget, dragging in the rectangle\n    defined by :attr:`drag_rectangle` will drag the widget.\n\n    For example, to make a popup which is draggable by its title do::\n\n        from kivy.uix.behaviors import DragBehavior\n        from kivy.uix.popup import Popup\n\n        class DragPopup(DragBehavior, Popup):\n            pass\n\n    And in .kv do::\n        <DragPopup>:\n            drag_rectangle: self.x, self.y+self._container.height, self.width,\\\n            self.height - self._container.height\n            drag_timeout: 10000000\n            drag_distance: 0\n\n    .. versionadded:: 1.8.0\n    '''\n\n    drag_distance = NumericProperty(_scroll_distance)\n    '''Distance to move before dragging the :class:`DragBehavior`, in pixels.\n    As soon as the distance has been traveled, the :class:`DragBehavior` will\n    start to drag, and no touch event will go to children.\n    It is advisable that you base this value on the dpi of your target device's\n    screen.\n\n    :attr:`drag_distance` is a :class:`~kivy.properties.NumericProperty`,\n    defaults to 20 (pixels), according to the default value of scroll_distance\n    in user configuration.\n    '''\n\n    drag_timeout = NumericProperty(_scroll_timeout)\n    '''Timeout allowed to trigger the :attr:`drag_distance`, in milliseconds.\n    If the user has not moved :attr:`drag_distance` within the timeout,\n    dragging will be disabled, and the touch event will go to the children.\n\n    :attr:`drag_timeout` is a :class:`~kivy.properties.NumericProperty`,\n    defaults to 55 (milliseconds), according to the default value of\n    scroll_timeout in user configuration.\n    '''\n\n    drag_rect_x = NumericProperty(0)\n    '''X position of the axis aligned bounding rectangle where dragging\n    is allowed. In window coordinates.\n\n    :attr:`drag_rect_x` is a :class:`~kivy.properties.NumericProperty`,\n    defaults to 0.\n    '''\n\n    drag_rect_y = NumericProperty(0)\n    '''Y position of the axis aligned bounding rectangle where dragging\n    is allowed. In window coordinates.\n\n    :attr:`drag_rect_Y` is a :class:`~kivy.properties.NumericProperty`,\n    defaults to 0.\n    '''\n\n    drag_rect_width = NumericProperty(100)\n    '''Width of the axis aligned bounding rectangle where dragging is allowed.\n\n    :attr:`drag_rect_width` is a :class:`~kivy.properties.NumericProperty`,\n    defaults to 100.\n    '''\n\n    drag_rect_height = NumericProperty(100)\n    '''Height of the axis aligned bounding rectangle where dragging is allowed.\n\n    :attr:`drag_rect_height` is a :class:`~kivy.properties.NumericProperty`,\n    defaults to 100.\n    '''\n\n    drag_rectangle = ReferenceListProperty(drag_rect_x, drag_rect_y,\n                                           drag_rect_width, drag_rect_height)\n    '''Position and size of the axis aligned bounding rectangle where dragging\n    is allowed.\n\n    :attr:`drag_rectangle` is a :class:`~kivy.properties.ReferenceListProperty`\n    of (:attr:`drag_rect_x`, :attr:`drag_rect_y`, :attr:`drag_rect_width`,\n    :attr:`drag_rect_height`) properties.\n    '''\n\n    def __init__(self, **kwargs):\n        self._drag_touch = None\n        super(DragBehavior, self).__init__(**kwargs)\n\n    def _get_uid(self, prefix='sv'):\n        return '{0}.{1}'.format(prefix, self.uid)\n\n    def on_touch_down(self, touch):\n        xx, yy, w, h = self.drag_rectangle\n        x, y = touch.pos\n        if not self.collide_point(x, y):\n            touch.ud[self._get_uid('svavoid')] = True\n            return super(DragBehavior, self).on_touch_down(touch)\n        if self._drag_touch or ('button' in touch.profile and\n                                touch.button.startswith('scroll')) or\\\n                not ((xx < x <= xx + w) and (yy < y <= yy + h)):\n            return super(DragBehavior, self).on_touch_down(touch)\n\n        # no mouse scrolling, so the user is going to drag with this touch.\n        self._drag_touch = touch\n        uid = self._get_uid()\n        touch.grab(self)\n        touch.ud[uid] = {\n            'mode': 'unknown',\n            'dx': 0,\n            'dy': 0}\n        Clock.schedule_once(self._change_touch_mode,\n                            self.drag_timeout / 1000.)\n        return True\n\n    def on_touch_move(self, touch):\n        if self._get_uid('svavoid') in touch.ud or\\\n                self._drag_touch is not touch:\n            return super(DragBehavior, self).on_touch_move(touch) or\\\n                self._get_uid() in touch.ud\n        if touch.grab_current is not self:\n            return True\n\n        uid = self._get_uid()\n        ud = touch.ud[uid]\n        mode = ud['mode']\n        if mode == 'unknown':\n            ud['dx'] += abs(touch.dx)\n            ud['dy'] += abs(touch.dy)\n            if ud['dx'] > sp(self.drag_distance):\n                mode = 'drag'\n            if ud['dy'] > sp(self.drag_distance):\n                mode = 'drag'\n            ud['mode'] = mode\n        if mode == 'drag':\n            self.x += touch.dx\n            self.y += touch.dy\n        return True\n\n    def on_touch_up(self, touch):\n        if self._get_uid('svavoid') in touch.ud:\n            return super(DragBehavior, self).on_touch_up(touch)\n\n        if self._drag_touch and self in [x() for x in touch.grab_list]:\n            touch.ungrab(self)\n            self._drag_touch = None\n            ud = touch.ud[self._get_uid()]\n            if ud['mode'] == 'unknown':\n                super(DragBehavior, self).on_touch_down(touch)\n                Clock.schedule_once(partial(self._do_touch_up, touch), .1)\n        else:\n            if self._drag_touch is not touch:\n                super(DragBehavior, self).on_touch_up(touch)\n        return self._get_uid() in touch.ud\n\n    def _do_touch_up(self, touch, *largs):\n        super(DragBehavior, self).on_touch_up(touch)\n        # don't forget about grab event!\n        for x in touch.grab_list[:]:\n            touch.grab_list.remove(x)\n            x = x()\n            if not x:\n                continue\n            touch.grab_current = x\n            super(DragBehavior, self).on_touch_up(touch)\n        touch.grab_current = None\n\n    def _change_touch_mode(self, *largs):\n        if not self._drag_touch:\n            return\n        uid = self._get_uid()\n        touch = self._drag_touch\n        ud = touch.ud[uid]\n        if ud['mode'] != 'unknown':\n            return\n        touch.ungrab(self)\n        self._drag_touch = None\n        super(DragBehavior, self).on_touch_down(touch)\n        return\n\n\nclass FocusBehavior(object):\n    '''Implements keyboard focus behavior. When combined with other\n    FocusBehavior widgets it allows one to cycle focus among them by pressing\n    tab. In addition, upon gaining focus the instance will automatically\n    receive keyboard input.\n\n    Focus, very different then selection, is intimately tied with the keyboard;\n    each keyboard can focus on zero or one widgets, and each widget can only\n    have the focus of one keyboard. However, multiple keyboards can focus\n    simultaneously on different widgets. When escape is hit, the widget having\n    the focus of that keyboard will de-focus.\n\n    In essence, focus is implemented as a doubly linked list, where each\n    node holds a (weak) reference to the instance before it and after it,\n    as visualized when cycling through the nodes using tab (forward) or\n    shift+tab (backward). If previous or next widget is not specified,\n    :attr:`focus_next` and :attr:`focus_previous` defaults to `None`,\n    which means that the children list and parents are walked to find\n    the next focusable widget, unless :attr:`focus_next` or\n    :attr:`focus_previous` is set to the `StopIteration` class, in which case\n    focus stops there.\n\n    For example, to cycle focus between :class:`~kivy.uix.button.Button`\n    elements of a :class:`~kivy.uix.gridlayout.GridLayout`::\n\n        class FocusButton(FocusBehavior, Button):\n            pass\n\n        grid = GridLayout(cols=4)\n        for i in range(40):\n            grid.add_widget(FocusButton(text=str(i)))\n        # clicking on a widget will activate focus, and tab can now be used\n        # to cycle through\n\n\n    .. versionadded:: 1.9.0\n\n    .. warning::\n\n        This code is still experimental, and its API is subject to change in a\n        future version.\n    '''\n\n    _requested_keyboard = False\n    _keyboard = ObjectProperty(None, allownone=True)\n    _keyboards = {}\n\n    ignored_touch = []\n    '''A list of touches that should not be used to defocus. After on_touch_up,\n    every touch that is not in :attr:`ignored_touch` will defocus all the\n    focused widgets, if, the config keyboard mode is not multi. Touches on\n    focusable widgets that were used to focus are automatically added here.\n\n    Example usage::\n\n        class Unfocusable(Widget):\n\n            def on_touch_down(self, touch):\n                if self.collide_point(*touch.pos):\n                    FocusBehavior.ignored_touch.append(touch)\n\n    Notice that you need to access this as class, not instance variable.\n    '''\n\n    def _set_keyboard(self, value):\n        focus = self.focus\n        keyboard = self._keyboard\n        keyboards = FocusBehavior._keyboards\n        if keyboard:\n            self.focus = False    # this'll unbind\n            if self._keyboard:  # remove assigned keyboard from dict\n                del keyboards[keyboard]\n        if value and not value in keyboards:\n            keyboards[value] = None\n        self._keyboard = value\n        self.focus = focus\n\n    def _get_keyboard(self):\n        return self._keyboard\n    keyboard = AliasProperty(_get_keyboard, _set_keyboard,\n                             bind=('_keyboard', ))\n    '''The keyboard to bind, or bound to the widget when focused.\n\n    When None, a keyboard is requested and released whenever the widget comes\n    into and out of focus. If not None, it must be a keyboard, which gets\n    bound and unbound from the widget whenever it's in or out of focus. It is\n    useful only when more than one keyboard is available, so it is recommended\n    to be set to None when only one keyboard is available\n\n    If more than one keyboard is available, whenever an instance get focused\n    a new keyboard will be requested if None. Unless, the other instances lose\n    focus (e.g. if tab was used), a new keyboard will appear. When this is\n    undesired, the keyboard property can be used. For example, if there are\n    two users with two keyboards, then each keyboard can be assigned to\n    different groups of instances of FocusBehavior, ensuring that within\n    each group, only one FocusBehavior will have focus, and will receive input\n    from the correct keyboard. see `keyboard_mode` in :mod:`~kivy.config` for\n    information on the keyboard modes.\n\n    :attr:`keyboard` is a :class:`~kivy.properties.AliasProperty`, defaults to\n    None.\n\n    .. note::\n\n        When Config's `keyboard_mode` is multi, each new touch is considered\n        a touch by a different user and will focus (if clicked on a\n        focusable) with a new keyboard. Already focused elements will not lose\n        their focus (even if clicked on a unfocusable).\n\n    .. note:\n\n        If the keyboard property is set, that keyboard will be used when the\n        instance gets focused. If widgets with different keyboards are linked\n        through :attr:`focus_next` and :attr:`focus_previous`, then as they are\n        tabbed through, different keyboards will become active. Therefore,\n        typically it's undesirable to link instances which are assigned\n        different keyboards.\n\n    .. note:\n\n        When an instance has focus, setting keyboard to None will remove the\n        current keyboard, but will then try to get a keyboard back. It is\n        better to set :attr:`focus` to False.\n\n    .. warning:\n\n        When assigning a keyboard, the keyboard must not be released while\n        it is still assigned to an instance. Similarly, the keyboard created\n        by the instance on focus and assigned to :attr:`keyboard` if None,\n        will be released by the instance when the instance loses focus.\n        Therefore, it is not safe to assign this keyboard to another instance's\n        :attr:`keyboard`.\n    '''\n\n    is_focusable = BooleanProperty(_is_desktop)\n    '''Whether the instance can become focused. If focused, it'll lose focus\n    when set to False.\n\n    :attr:`is_focusable` is a :class:`~kivy.properties.BooleanProperty`,\n    defaults to True on a desktop (i.e. desktop is True in\n    :mod:`~kivy.config`), False otherwise.\n    '''\n\n    focus = BooleanProperty(False)\n    '''Whether the instance currently has focus.\n\n    Setting it to True, will bind to and/or request the keyboard, and input\n    will be forwarded to the instance. Setting it to False, will unbind\n    and/or release the keyboard. For a given keyboard, only one widget can\n    have its focus, so focusing one will automatically unfocus the other\n    instance holding its focus.\n\n    :attr:`focus` is a :class:`~kivy.properties.BooleanProperty`, defaults to\n    False.\n    '''\n\n    focused = focus\n    '''An alias of :attr:`focus`.\n\n    :attr:`focused` is a :class:`~kivy.properties.BooleanProperty`, defaults to\n    False.\n\n    .. warning::\n        :attr:`focused` is an alias of :attr:`focus` and will be removed in\n        2.0.0.\n    '''\n\n    def _set_on_focus_next(self, instance, value):\n        ''' If changing code, ensure following code is not infinite loop:\n        widget.focus_next = widget\n        widget.focus_previous = widget\n        widget.focus_previous = widget2\n        '''\n        next = self._old_focus_next\n        if next is value:   # prevent infinite loop\n            return\n\n        if isinstance(next, FocusBehavior):\n            next.focus_previous = None\n        self._old_focus_next = value\n        if value is None or value is StopIteration:\n            return\n        if not isinstance(value, FocusBehavior):\n            raise ValueError('focus_next accepts only objects based'\n                             ' on FocusBehavior, or the StopIteration class.')\n        value.focus_previous = self\n\n    focus_next = ObjectProperty(None, allownone=True)\n    '''The :class:`FocusBehavior` instance to acquire focus when\n    tab is pressed when this instance has focus, if not `None` or\n    `'StopIteration'`.\n\n    When tab is pressed, focus cycles through all the :class:`FocusBehavior`\n    widgets that are linked through :attr:`focus_next` and are focusable. If\n    :attr:`focus_next` is `None`, it instead walks the children lists to find\n    the next focusable widget. Finally, if :attr:`focus_next` is\n    the `StopIteration` class, focus won't move forward, but end here.\n\n    .. note:\n\n        Setting :attr:`focus_next` automatically sets :attr:`focus_previous`\n        of the other instance to point to this instance, if not None or\n        `StopIteration`. Similarly, if it wasn't None or `StopIteration`, it\n        also sets the :attr:`focus_previous` property of the instance\n        previously in :attr:`focus_next` to `None`. Therefore, it is only\n        required to set one side of the :attr:`focus_previous`,\n        :attr:`focus_next`, links since the other side will be set\n        automatically.\n\n    :attr:`focus_next` is a :class:`~kivy.properties.ObjectProperty`, defaults\n    to `None`.\n    '''\n\n    def _set_on_focus_previous(self, instance, value):\n        prev = self._old_focus_previous\n        if prev is value:\n            return\n\n        if isinstance(prev, FocusBehavior):\n            prev.focus_next = None\n        self._old_focus_previous = value\n        if value is None or value is StopIteration:\n            return\n        if not isinstance(value, FocusBehavior):\n            raise ValueError('focus_previous accepts only objects based'\n                             ' on FocusBehavior, or the StopIteration class.')\n        value.focus_next = self\n\n    focus_previous = ObjectProperty(None, allownone=True)\n    '''The :class:`FocusBehavior` instance to acquire focus when\n    shift+tab is pressed on this instance, if not None or `StopIteration`.\n\n    When shift+tab is pressed, focus cycles through all the\n    :class:`FocusBehavior` widgets that are linked through\n    :attr:`focus_previous` and are focusable. If :attr:`focus_previous` is\n    `None', it instead walks the children tree to find the\n    previous focusable widget. Finally, if :attr:`focus_previous` is the\n    `StopIteration` class, focus won't move backward, but end here.\n\n    .. note:\n\n        Setting :attr:`focus_previous` automatically sets :attr:`focus_next`\n        of the other instance to point to this instance, if not None or\n        `StopIteration`. Similarly, if it wasn't None or `StopIteration`, it\n        also sets the :attr:`focus_next` property of the instance previously in\n        :attr:`focus_previous` to `None`. Therefore, it is only required\n        to set one side of the :attr:`focus_previous`, :attr:`focus_next`,\n        links since the other side will be set automatically.\n\n    :attr:`focus_previous` is a :class:`~kivy.properties.ObjectProperty`,\n    defaults to  `None`.\n    '''\n\n    keyboard_mode = OptionProperty('auto', options=('auto', 'managed'))\n    '''How the keyboard visibility should be managed (auto will have standard\n    behaviour to show/hide on focus, managed requires setting keyboard_visible\n    manually, or calling the helper functions ``show_keyboard()``\n    and ``hide_keyboard()``.\n\n    :attr:`keyboard_mode` is an :class:`~kivy.properties.OptionsProperty` and\n    defaults to 'auto'. Can be one of 'auto' or 'managed'.\n    '''\n\n    input_type = OptionProperty('text', options=('text', 'number', 'url',\n                                                 'mail', 'datetime', 'tel',\n                                                 'address'))\n    '''The kind of input keyboard to request.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`input_type` is an :class:`~kivy.properties.OptionsProperty` and\n    defaults to 'text'. Can be one of 'text', 'number', 'url', 'mail',\n    'datetime', 'tel', 'address'.\n    '''\n\n    unfocus_on_touch = BooleanProperty(_keyboard_mode not in\n                                       ('multi', 'systemandmulti'))\n    '''Whether a instance should lose focus when clicked outside the instance.\n\n    When a user clicks on a widget that is focus aware and shares the same\n    keyboard as the this widget (which in the case of only one keyboard, are\n    all focus aware widgets), then as the other widgets gains focus, this\n    widget loses focus. In addition to that, if this property is `True`,\n    clicking on any widget other than this widget, will remove focus form this\n    widget.\n\n    :attr:`unfocus_on_touch` is a :class:`~kivy.properties.BooleanProperty`,\n    defaults to `False` if the `keyboard_mode` in :attr:`~kivy.config.Config`\n    is `'multi'` or `'systemandmulti'`, otherwise it defaults to `True`.\n    '''\n\n    def __init__(self, **kwargs):\n        self._old_focus_next = None\n        self._old_focus_previous = None\n        super(FocusBehavior, self).__init__(**kwargs)\n\n        self._keyboard_mode = _keyboard_mode\n        self.bind(focus=self._on_focus, disabled=self._on_focusable,\n                  is_focusable=self._on_focusable,\n                  focus_next=self._set_on_focus_next,\n                  focus_previous=self._set_on_focus_previous)\n\n    def _on_focusable(self, instance, value):\n        if self.disabled or not self.is_focusable:\n            self.focus = False\n\n    def _on_focus(self, instance, value, *largs):\n        if self.keyboard_mode == 'auto':\n            if value:\n                self._bind_keyboard()\n            else:\n                self._unbind_keyboard()\n\n    def _ensure_keyboard(self):\n        if self._keyboard is None:\n            self._requested_keyboard = True\n            keyboard = self._keyboard =\\\n                EventLoop.window.request_keyboard(\n                    self._keyboard_released, self, input_type=self.input_type)\n            keyboards = FocusBehavior._keyboards\n            if keyboard not in keyboards:\n                keyboards[keyboard] = None\n\n    def _bind_keyboard(self):\n        self._ensure_keyboard()\n        keyboard = self._keyboard\n\n        if not keyboard or self.disabled or not self.is_focusable:\n            self.focus = False\n            return\n        keyboards = FocusBehavior._keyboards\n        old_focus = keyboards[keyboard]  # keyboard should be in dict\n        if old_focus:\n            old_focus.focus = False\n            # keyboard shouldn't have been released here, see keyboard warning\n        keyboards[keyboard] = self\n        keyboard.bind(on_key_down=self.keyboard_on_key_down,\n                      on_key_up=self.keyboard_on_key_up,\n                      on_textinput=self.keyboard_on_textinput)\n\n    def _unbind_keyboard(self):\n        keyboard = self._keyboard\n        if keyboard:\n            keyboard.unbind(on_key_down=self.keyboard_on_key_down,\n                            on_key_up=self.keyboard_on_key_up,\n                            on_textinput=self.keyboard_on_textinput)\n            if self._requested_keyboard:\n                keyboard.release()\n                self._keyboard = None\n                self._requested_keyboard = False\n                del FocusBehavior._keyboards[keyboard]\n            else:\n                FocusBehavior._keyboards[keyboard] = None\n\n    def keyboard_on_textinput(self, window, text):\n        pass\n\n    def _keyboard_released(self):\n        self.focus = False\n\n    def on_touch_down(self, touch):\n        if not self.collide_point(*touch.pos):\n            return\n        if (not self.disabled and self.is_focusable and\n            ('button' not in touch.profile or\n             not touch.button.startswith('scroll'))):\n            self.focus = True\n            FocusBehavior.ignored_touch.append(touch)\n        return super(FocusBehavior, self).on_touch_down(touch)\n\n    @staticmethod\n    def _handle_post_on_touch_up(touch):\n        ''' Called by window after each touch has finished.\n        '''\n        touches = FocusBehavior.ignored_touch\n        if touch in touches:\n            touches.remove(touch)\n            return\n        for focusable in list(FocusBehavior._keyboards.values()):\n            if focusable is None or not focusable.unfocus_on_touch:\n                continue\n            focusable.focus = False\n\n    def _get_focus_next(self, focus_dir):\n        current = self\n        walk_tree = 'walk' if focus_dir is 'focus_next' else 'walk_reverse'\n\n        while 1:\n            # if we hit a focusable, walk through focus_xxx\n            while getattr(current, focus_dir) is not None:\n                current = getattr(current, focus_dir)\n                if current is self or current is StopIteration:\n                    return None  # make sure we don't loop forever\n                if current.is_focusable and not current.disabled:\n                    return current\n\n            # hit unfocusable, walk widget tree\n            itr = getattr(current, walk_tree)(loopback=True)\n            if focus_dir is 'focus_next':\n                next(itr)  # current is returned first  when walking forward\n            for current in itr:\n                if isinstance(current, FocusBehavior):\n                    break\n            # why did we stop\n            if isinstance(current, FocusBehavior):\n                if current is self:\n                    return None\n                if current.is_focusable and not current.disabled:\n                    return current\n            else:\n                return None\n\n    def keyboard_on_key_down(self, window, keycode, text, modifiers):\n        '''The method bound to the keyboard when the instance has focus.\n\n        When the instance becomes focused, this method is bound to the\n        keyboard and will be called for every input press. The parameters are\n        the same as :meth:`kivy.core.window.WindowBase.on_key_down`.\n\n        When overwriting the method in the derived widget, super should be\n        called to enable tab cycling. If the derived widget wishes to use tab\n        for its own purposes, it can call super at the end after it is done if\n        it didn't consume tab.\n\n        Similar to other keyboard functions, it should return True if the\n        key was consumed.\n        '''\n        if keycode[1] == 'tab':  # deal with cycle\n            if ['shift'] == modifiers:\n                next = self._get_focus_next('focus_previous')\n            else:\n                next = self._get_focus_next('focus_next')\n            if next:\n                self.focus = False\n\n                next.focus = True\n\n            return True\n        return False\n\n    def keyboard_on_key_up(self, window, keycode):\n        '''The method bound to the keyboard when the instance has focus.\n\n        When the instance becomes focused, this method is bound to the\n        keyboard and will be called for every input release. The parameters are\n        the same as :meth:`kivy.core.window.WindowBase.on_key_up`.\n\n        When overwriting the method in the derived widget, super should be\n        called to enable de-focusing on escape. If the derived widget wishes\n        to use escape for its own purposes, it can call super at the end after\n        it is done if it didn't consume escape.\n\n        See :meth:`on_key_down`\n        '''\n        if keycode[1] == 'escape':\n            self.focus = False\n            return True\n        return False\n\n    def show_keyboard(self):\n        '''\n        Convenience function to show the keyboard in managed mode.\n        '''\n        if self.keyboard_mode == 'managed':\n            self._bind_keyboard()\n\n    def hide_keyboard(self):\n        '''\n        Convenience function to hide the keyboard in managed mode.\n        '''\n        if self.keyboard_mode == 'managed':\n            self._unbind_keyboard()\n\n\nclass CompoundSelectionBehavior(object):\n    '''Selection behavior implements the logic behind keyboard and touch\n    selection of selectable widgets managed by the derived widget.\n    For example, it could be combined with a\n    :class:`~kivy.uix.gridlayout.GridLayout` to add selection to the layout.\n\n    At its core, it keeps a dynamic list of widgets that can be selected.\n    Then, as the touches and keyboard input are passed in, it selects one or\n    more of the widgets based on these inputs. For example, it uses the mouse\n    scroll and keyboard up/down buttons to scroll through the list of widgets.\n    Multiselection can also be achieved using the keyboard shift and ctrl keys.\n    Finally, in addition to the up/down type keyboard inputs, it can also\n    accepts letters from the kayboard to be used to select nodes with\n    associated strings that start with those letters, similar to how files\n    are selected by a file browser.\n\n    When the controller needs to select a node it calls :meth:`select_node` and\n    :meth:`deselect_node`. Therefore, they must be overwritten in order affect\n    the selected nodes. By default, the class doesn't listen to keyboard and\n    touch events, therefore, the derived widget must call\n    :meth:`select_with_touch`, :meth:`select_with_key_down`, and\n    :meth:`select_with_key_up` on events that it wants to pass on for selection\n    purposes.\n\n    For example, to add selection to a grid layout which will contain\n    :class:`~kivy.uix.Button` widgets::\n\n        class SelectableGrid(CompoundSelectionBehavior, GridLayout):\n\n            def __init__(self, **kwargs):\n                super(CompoundSelectionBehavior, self).__init__(**kwargs)\n                keyboard = Window.request_keyboard(None, self)\n                keyboard.bind(on_key_down=self.select_with_key_down,\n                on_key_up=self.select_with_key_up)\n\n            def select_node(self, node):\n                node.background_color = (1, 0, 0, 1)\n                return super(CompoundSelectionBehavior, self).select_node(node)\n\n            def deselect_node(self, node):\n                node.background_color = (1, 1, 1, 1)\n                super(CompoundSelectionBehavior, self).deselect_node(node)\n\n    Then, for each button added to the layout, bind on_touch_down of the button\n    to :meth:`select_with_touch` to pass on the touch events.\n\n    .. versionadded:: 1.9.0\n\n    .. warning::\n\n        This code is still experimental, and its API is subject to change in a\n        future version.\n    '''\n\n    selected_nodes = ListProperty([])\n    '''The list of selected nodes.\n\n    .. note:\n\n        Multiple nodes can be selected right after another using e.g. the\n        keyboard, so when listening to :attr:`selected_nodes` one should be\n        aware of this.\n\n    :attr:`selected_nodes` is a :class:`~kivy.properties.ListProperty` and\n    defaults to the empty list, []. It is read-only and should not be modified.\n    '''\n\n    touch_multiselect = BooleanProperty(False)\n    '''A special touch mode which determines whether touch events, as\n    processed with :meth:`select_with_touch`, will add to the selection the\n    currently touched node, or if it will clear the selection before adding the\n    node. This allows the selection of multiple nodes by simply touching them.\n    This is different than :attr:`multiselect`, because when this is True\n    simply touching an unselected node will select it, even if e.g. ctrl is not\n    pressed. If this is False, however, ctrl is required to be held in order to\n    add to selection when :attr:`multiselect` is True.\n\n    .. note::\n\n        :attr:`multiselect`, when False, will disable\n        :attr:`touch_multiselect`.\n\n    :attr:`touch_multiselect` is a :class:`~kivy.properties.BooleanProperty`,\n    defaults to False.\n    '''\n\n    multiselect = BooleanProperty(False)\n    '''Determines whether multiple nodes can be selected. If enabled, keyboard\n    shift and ctrl selection, optionally combined with touch, for example, will\n    be able to select multiple widgets in the normally expected manner.\n    This dominates :attr:`touch_multiselect` when False.\n\n    :attr:`multiselect` is a :class:`~kivy.properties.BooleanProperty`\n    , defaults to False.\n    '''\n\n    keyboard_select = BooleanProperty(True)\n    ''' Whether the keybaord can be used for selection. If False, keyboard\n    inputs will be ignored.\n\n    :attr:`keyboard_select` is a :class:`~kivy.properties.BooleanProperty`\n    , defaults to True.\n    '''\n\n    page_count = NumericProperty(10)\n    '''Determines by how much the selected node is moved up or down, relative\n    to position of the last selected node, when pageup (or pagedown) is\n    pressed.\n\n    :attr:`page_count` is a :class:`~kivy.properties.NumericProperty`,\n    defaults to 10.\n    '''\n\n    up_count = NumericProperty(1)\n    '''Determines by how much the selected node is moved up or down, relative\n    to position of the last selected node, when the up (or down) arrow on the\n    keyboard is pressed.\n\n    :attr:`up_count` is a :class:`~kivy.properties.NumericProperty`,\n    defaults to 1.\n    '''\n\n    right_count = NumericProperty(1)\n    '''Determines by how much the selected node is moved up or down, relative\n    to position of the last selected node, when the right (or left) arrow on\n    the keyboard is pressed.\n\n    :attr:`right_count` is a :class:`~kivy.properties.NumericProperty`,\n    defaults to 1.\n    '''\n\n    scroll_count = NumericProperty(0)\n    '''Determines by how much the selected node is moved up or down, relative\n    to position of the last selected node, when the mouse scroll wheel is\n    scrolled.\n\n    :attr:`right_count` is a :class:`~kivy.properties.NumericProperty`,\n    defaults to 0.\n    '''\n\n    _anchor = None  # the last anchor node selected (e.g. shift relative node)\n    # the idx may be out of sync\n    _anchor_idx = 0  # cache indexs in case list hasn't changed\n    _last_selected_node = None  # the absolute last node selected\n    _last_node_idx = 0\n    _ctrl_down = False  # if it's pressed - for e.g. shift selection\n    _shift_down = False\n    # holds str used to find node, e.g. if word is typed. passed to goto_node\n    _word_filter = ''\n    _last_key_time = 0  # time since last press, for finding whole strs in node\n    _printable = set(string.printable)\n    _key_list = []  # keys that are already pressed, to not press continuously\n    _offset_counts = {}  # cache of counts for faster access\n\n    def __init__(self, **kwargs):\n        super(CompoundSelectionBehavior, self).__init__(**kwargs)\n\n        def ensure_single_select(*l):\n            if (not self.multiselect) and len(self.selected_nodes) > 1:\n                self.clear_selection()\n        self._update_counts()\n        self.bind(multiselect=ensure_single_select,\n        page_count=self._update_counts, up_count=self._update_counts,\n        right_count=self._update_counts, scroll_count=self._update_counts)\n\n    def select_with_touch(self, node, touch=None):\n        '''(internal) Processes a touch on the node. This should be called by\n        the derived widget when a node is touched and is to be used for\n        selection. Depending on the keyboard keys pressed and the\n        configuration, it could select or deslect this and other nodes in the\n        selectable nodes list, :meth:`get_selectable_nodes`.\n\n        :Parameters:\n            `node`\n                The node that recieved the touch. Can be None for a scroll\n                type touch.\n            `touch`\n                Optionally, the touch. Defaults to None.\n\n        :Returns:\n            bool, True if the touch was used, False otherwise.\n        '''\n        multi = self.multiselect\n        multiselect = multi and (self._ctrl_down or self.touch_multiselect)\n        range_select = multi and self._shift_down\n\n        if touch and 'button' in touch.profile and touch.button in\\\n            ('scrollup', 'scrolldown', 'scrollleft', 'scrollright'):\n            node_src, idx_src = self._reslove_last_node()\n            node, idx = self.goto_node(touch.button, node_src, idx_src)\n            if node == node_src:\n                return False\n            if range_select:\n                self._select_range(multiselect, True, node, idx)\n            else:\n                if not multiselect:\n                    self.clear_selection()\n                self.select_node(node)\n            return True\n        if node is None:\n            return False\n\n        if (node in self.selected_nodes and (not range_select)):  # selected\n            if multiselect:\n                self.deselect_node(node)\n            else:\n                self.clear_selection()\n                self.select_node(node)\n        elif range_select:\n            # keep anchor only if not multislect (ctrl-type selection)\n            self._select_range(multiselect, not multiselect, node, 0)\n        else:   # it's not selected at this point\n            if not multiselect:\n                self.clear_selection()\n            self.select_node(node)\n        return True\n\n    def select_with_key_down(self, keyboard, scancode, codepoint, modifiers,\n                             **kwargs):\n        '''Processes a key press. This is called when a key press is to be used\n        for selection. Depending on the keyboard keys pressed and the\n        configuration, it could select or deslect nodes or node ranges\n        from the selectable nodes list, :meth:`get_selectable_nodes`.\n\n        The parameters are such that it could be bound directly to the\n        on_key_down event of a keyboard. Therefore, it is safe to be called\n        repeatedly when the key is held down as is done by the keyboard.\n\n        :Returns:\n            bool, True if the keypress was used, False otherwise.\n        '''\n        if not self.keyboard_select:\n            return False\n        keys = self._key_list\n        multi = self.multiselect\n        node_src, idx_src = self._reslove_last_node()\n\n        if scancode[1] == 'shift':\n            self._shift_down = True\n        elif scancode[1] == 'ctrl':\n            self._ctrl_down = True\n        elif (multi and 'ctrl' in modifiers and scancode[1] in ('a', 'A')\n              and scancode[1] not in keys):\n            sister_nodes = self.get_selectable_nodes()\n            select = self.select_node\n            for node in sister_nodes:\n                select(node)\n            keys.append(scancode[1])\n        else:\n            if scancode[1] in self._printable:\n                if time() - self._last_key_time <= 1.:\n                    self._word_filter += scancode[1]\n                else:\n                    self._word_filter = scancode[1]\n                self._last_key_time = time()\n                node, idx = self.goto_node(self._word_filter, node_src,\n                                           idx_src)\n            else:\n                node, idx = self.goto_node(scancode[1], node_src, idx_src)\n            if node == node_src:\n                return False\n\n            multiselect = multi and 'ctrl' in modifiers\n            if multi and 'shift' in modifiers:\n                self._select_range(multiselect, True, node, idx)\n            else:\n                if not multiselect:\n                    self.clear_selection()\n                self.select_node(node)\n            return True\n        return False\n\n    def select_with_key_up(self, keyboard, scancode, **kwargs):\n        '''(internal) Processes a key release. This must be called by the\n        derived widget when a key that :meth:`select_with_key_down` returned\n        True is released.\n\n        The parameters are such that it could be bound directly to the\n        on_key_up event of a keyboard.\n\n        :Returns:\n            bool, True if the key release was used, False otherwise.\n        '''\n        if scancode[1] == 'shift':\n            self._shift_down = False\n        elif scancode[1] == 'ctrl':\n            self._ctrl_down = False\n        else:\n            try:\n                self._key_list.remove(scancode[1])\n                return True\n            except ValueError:\n                return False\n        return True\n\n    def _update_counts(self, *largs):\n        # doesn't invert indices here\n        pc = self.page_count\n        uc = self.up_count\n        rc = self.right_count\n        sc = self.scroll_count\n        self._offset_counts = {'pageup': -pc, 'pagedown': pc, 'up': -uc,\n        'down': uc, 'right': rc, 'left': -rc, 'scrollup': sc,\n        'scrolldown': -sc, 'scrollright': -sc, 'scrollleft': sc}\n\n    def _reslove_last_node(self):\n        # for offset selection, we have a anchor, and we select everything\n        # between anchor and added offset relative to last node\n        sister_nodes = self.get_selectable_nodes()\n        if not len(sister_nodes):\n            return None, 0\n        last_node = self._last_selected_node\n        last_idx = self._last_node_idx\n        end = len(sister_nodes) - 1\n\n        if last_node is None:\n            last_node = self._anchor\n            last_idx = self._anchor_idx\n        if last_node is None:\n            return sister_nodes[end], end\n        if last_idx > end or sister_nodes[last_idx] != last_node:\n            try:\n                return last_node, sister_nodes.index(last_node)\n            except ValueError:\n                return sister_nodes[end], end\n        return last_node, last_idx\n\n    def _select_range(self, multiselect, keep_anchor, node, idx):\n        '''Selects a range between self._anchor and node or idx.\n        If multiselect, it'll add to selection, otherwise it will unselect\n        everything before selecting the range. This is only called if\n        self.multiselect is True.\n        If keep anchor is False, the anchor is moved to node. This should\n        always be True of keyboard selection.\n        '''\n        select = self.select_node\n        sister_nodes = self.get_selectable_nodes()\n        end = len(sister_nodes) - 1\n        last_node = self._anchor\n        last_idx = self._anchor_idx\n\n        if last_node is None:\n            last_idx = end\n            last_node = sister_nodes[end]\n        else:\n            if last_idx > end or sister_nodes[last_idx] != last_node:\n                try:\n                    last_idx = sister_nodes.index(last_node)\n                except ValueError:\n                    # list changed - cannot do select across them\n                    return\n        if idx > end or sister_nodes[idx] != node:\n            try:    # just in case\n                idx = sister_nodes.index(node)\n            except ValueError:\n                return\n\n        if last_idx > idx:\n            last_idx, idx = idx, last_idx\n        if not multiselect:\n            self.clear_selection()\n        for item in sister_nodes[last_idx:idx + 1]:\n            select(item)\n\n        if keep_anchor:\n            self._anchor = last_node\n            self._anchor_idx = last_idx\n        else:\n            self._anchor = node  # in case idx was reversed, reset\n            self._anchor_idx = idx\n        self._last_selected_node = node\n        self._last_node_idx = idx\n\n    def clear_selection(self):\n        ''' Deselects all the currently selected nodes.\n        '''\n        # keep the anchor and last selected node\n        deselect = self.deselect_node\n        nodes = self.selected_nodes\n        # empty beforehand so lookup in deselect will be fast\n        self.selected_nodes = []\n        for node in nodes:\n            deselect(node)\n\n    def get_selectable_nodes(self):\n        '''(internal) Returns a list of the nodes that can be selected. It can\n        be overwritten by the derived widget to return the correct list.\n\n        This list is used to determine which nodes to select with group\n        selection. E.g. the last element in the list will be selected when\n        home is pressed, pagedown will move (or add to, if shift is held) the\n        selection from the current position by negative :attr:`page_count`\n        nodes starting from the position of the currently selected node in\n        this list and so on. Still, nodes can be selected even if they are not\n        in this list.\n\n        .. note::\n\n            It is safe to dynamically change this list including removing,\n            adding, or re-arranging its elements. Nodes can be selected even\n            if they are not on this list. And selected nodes removed from the\n            list will remain selected until :meth:`deselect_node` is called.\n\n        .. warning::\n\n            Layouts display their children in the reverse order. That is, the\n            contents of :attr:`~kivy.uix.widget.Widget.children` is displayed\n            form right to left, bottom to top. Therefore, internally, the\n            indices of the elements returned by this function is reversed to\n            make it work by default for most layouts so that the final result\n            is that e.g. home, although it will select the last element on this\n            list, visually it'll select the first element when counting from\n            top to bottom and left to right. If this behavior is not desired,\n            a reversed list should be returned instead.\n\n        Defaults to returning :attr:`~kivy.uix.widget.Widget.children`.\n        '''\n        return self.children\n\n    def goto_node(self, key, last_node, last_node_idx):\n        '''(internal) Used by the controller to get the node at the position\n        indicated by key. The key can be keyboard inputs, e.g. pageup,\n        or scroll inputs from the mouse scroll wheel, e.g. scrollup.\n        Last node is the last node selected and is used to find the resulting\n        node. For example, if the key is up, the returned node is one node\n        up from the last node.\n\n        It can be overwritten by the derived widget.\n\n        :Parameters:\n            `key`\n                str, the string used to find the desired node. It can be any\n                of the keyboard keys, as well as the mouse scrollup,\n                scrolldown, scrollright, and scrollleft strings. If letters\n                are typed in quick succession, the letters will be combined\n                before it's passed in as key and can be used to find nodes that\n                have an associated string that starts with those letters.\n            `last_node`\n                The last node that was selected.\n            `last_node_idx`\n                The cached index of the last node selected in the\n                :meth:`get_selectable_nodes` list. If the list hasn't changed\n                it saves having to look up the index of `last_node` in that\n                list.\n\n        :Returns:\n            tuple, the node targeted by key and its index in the\n            :meth:`get_selectable_nodes` list. Returning\n            `(last_node, last_node_idx)` indicates a node wasn't found.\n        '''\n        sister_nodes = self.get_selectable_nodes()\n        end = len(sister_nodes) - 1\n        counts = self._offset_counts\n        if end == -1:\n            return last_node, last_node_idx\n        if last_node_idx > end or sister_nodes[last_node_idx] != last_node:\n            try:    # just in case\n                last_node_idx = sister_nodes.index(last_node)\n            except ValueError:\n                return last_node, last_node_idx\n\n        try:\n            idx = max(min(-counts[key] + last_node_idx, end), 0)\n            return sister_nodes[idx], idx\n        except KeyError:\n            pass\n        if key == 'home':\n            return sister_nodes[end], end\n        elif key == 'end':\n            return sister_nodes[0], 0\n        else:\n            return last_node, last_node_idx\n\n    def select_node(self, node):\n        ''' Selects a node.\n\n        It is called by the controller when it selects a node and can be\n        called from the outside to select a node directly. The derived widget\n        should overwrite this method and change the node to its selected state\n        when this is called\n\n        :Parameters:\n            `node`\n                The node to be selected.\n\n        :Returns:\n            bool, True if the node was selected, False otherwise.\n\n        .. warning::\n\n            This method must be called by the derived widget using super if it\n            is overwritten.\n        '''\n        nodes = self.selected_nodes\n        if (not self.multiselect) and len(nodes):\n            self.clear_selection()\n        if node not in nodes:\n            nodes.append(node)\n        self._anchor = node\n        self._last_selected_node = node\n        return True\n\n    def deselect_node(self, node):\n        ''' Deselects a possibly selected node.\n\n        It is called by the controller when it deselects a node and can also\n        be called from the outside to deselect a node directly. The derived\n        widget should overwrite this method and change the node to its\n        unselected state when this is called\n\n        :Parameters:\n            `node`\n                The node to be deselected.\n\n        .. warning::\n\n            This method must be called by the derived widget using super if it\n            is overwritten.\n        '''\n        try:\n            self.selected_nodes.remove(node)\n        except ValueError:\n            pass\n"
  },
  {
    "path": "tickeys/kivy/uix/boxlayout.py",
    "content": "'''\nBox Layout\n==========\n\n.. only:: html\n\n    .. image:: images/boxlayout.gif\n        :align: right\n\n.. only:: latex\n\n    .. image:: images/boxlayout.png\n        :align: right\n\n:class:`BoxLayout` arranges children in a vertical or horizontal box.\n\nTo position widgets above/below each other, use a vertical BoxLayout::\n\n    layout = BoxLayout(orientation='vertical')\n    btn1 = Button(text='Hello')\n    btn2 = Button(text='World')\n    layout.add_widget(btn1)\n    layout.add_widget(btn2)\n\nTo position widgets next to each other, use a horizontal BoxLayout. In this\nexample, we use 10 pixel spacing between children; the first button covers\n70% of the horizontal space, the second covers 30%::\n\n    layout = BoxLayout(spacing=10)\n    btn1 = Button(text='Hello', size_hint=(.7, 1))\n    btn2 = Button(text='World', size_hint=(.3, 1))\n    layout.add_widget(btn1)\n    layout.add_widget(btn2)\n\nPosition hints are partially working, depending on the orientation:\n\n* If the orientation is `vertical`: `x`, `right` and `center_x` will be used.\n* If the orientation is `horizontal`: `y`, `top` and `center_y` will be used.\n\nYou can check the `examples/widgets/boxlayout_poshint.py` for a live example.\n\n.. note::\n\n    The `size_hint` uses the available space after subtracting all the\n    fixed-size widgets. For example, if you have a layout that is 800px\n    wide, and add three buttons like this:\n\n    btn1 = Button(text='Hello', size=(200, 100), size_hint=(None, None))\n    btn2 = Button(text='Kivy', size_hint=(.5, 1))\n    btn3 = Button(text='World', size_hint=(.5, 1))\n\n    The first button will be 200px wide as specified, the second and third\n    will be 300px each, e.g. (800-200) * 0.5\n\n\n.. versionchanged:: 1.4.1\n    Added support for `pos_hint`.\n\n'''\n\n__all__ = ('BoxLayout', )\n\nfrom kivy.uix.layout import Layout\nfrom kivy.properties import (NumericProperty, OptionProperty,\n                             VariableListProperty)\n\n\nclass BoxLayout(Layout):\n    '''Box layout class. See module documentation for more information.\n    '''\n\n    spacing = NumericProperty(0)\n    '''Spacing between children, in pixels.\n\n    :attr:`spacing` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 0.\n    '''\n\n    padding = VariableListProperty([0, 0, 0, 0])\n    '''Padding between layout box and children: [padding_left, padding_top,\n    padding_right, padding_bottom].\n\n    padding also accepts a two argument form [padding_horizontal,\n    padding_vertical] and a one argument form [padding].\n\n    .. versionchanged:: 1.7.0\n        Replaced NumericProperty with VariableListProperty.\n\n    :attr:`padding` is a :class:`~kivy.properties.VariableListProperty` and\n    defaults to [0, 0, 0, 0].\n    '''\n\n    orientation = OptionProperty('horizontal', options=(\n        'horizontal', 'vertical'))\n    '''Orientation of the layout.\n\n    :attr:`orientation` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to 'horizontal'. Can be 'vertical' or 'horizontal'.\n    '''\n\n    def __init__(self, **kwargs):\n        super(BoxLayout, self).__init__(**kwargs)\n        self.bind(\n            spacing=self._trigger_layout,\n            padding=self._trigger_layout,\n            children=self._trigger_layout,\n            orientation=self._trigger_layout,\n            parent=self._trigger_layout,\n            size=self._trigger_layout,\n            pos=self._trigger_layout)\n\n    def do_layout(self, *largs):\n        # optimize layout by preventing looking at the same attribute in a loop\n        len_children = len(self.children)\n        if len_children == 0:\n            return\n        selfx = self.x\n        selfy = self.y\n        selfw = self.width\n        selfh = self.height\n        padding_left = self.padding[0]\n        padding_top = self.padding[1]\n        padding_right = self.padding[2]\n        padding_bottom = self.padding[3]\n        spacing = self.spacing\n        orientation = self.orientation\n        padding_x = padding_left + padding_right\n        padding_y = padding_top + padding_bottom\n\n        # calculate maximum space used by size_hint\n        stretch_weight_x = 0.\n        stretch_weight_y = 0.\n        minimum_size_x = padding_x + spacing * (len_children - 1)\n        minimum_size_y = padding_y + spacing * (len_children - 1)\n        for w in self.children:\n            shw = w.size_hint_x\n            shh = w.size_hint_y\n            if shw is None:\n                minimum_size_x += w.width\n            else:\n                stretch_weight_x += shw\n            if shh is None:\n                minimum_size_y += w.height\n            else:\n                stretch_weight_y += shh\n\n        if orientation == 'horizontal':\n            x = padding_left\n            stretch_space = max(0.0, selfw - minimum_size_x)\n            for c in reversed(self.children):\n                shw = c.size_hint_x\n                shh = c.size_hint_y\n                w = c.width\n                h = c.height\n                cx = selfx + x\n                cy = selfy + padding_bottom\n\n                if shw:\n                    w = stretch_space * shw / stretch_weight_x\n                if shh:\n                    h = max(0, shh * (selfh - padding_y))\n\n                for key, value in c.pos_hint.items():\n                    posy = value * (selfh - padding_y)\n                    if key == 'y':\n                        cy += posy\n                    elif key == 'top':\n                        cy += posy - h\n                    elif key == 'center_y':\n                        cy += posy - (h / 2.)\n\n                c.x = cx\n                c.y = cy\n                c.width = w\n                c.height = h\n                x += w + spacing\n\n        if orientation == 'vertical':\n            y = padding_bottom\n            stretch_space = max(0.0, selfh - minimum_size_y)\n            for c in self.children:\n                shw = c.size_hint_x\n                shh = c.size_hint_y\n                w = c.width\n                h = c.height\n                cx = selfx + padding_left\n                cy = selfy + y\n\n                if shh:\n                    h = stretch_space * shh / stretch_weight_y\n                if shw:\n                    w = max(0, shw * (selfw - padding_x))\n\n                for key, value in c.pos_hint.items():\n                    posx = value * (selfw - padding_x)\n                    if key == 'x':\n                        cx += posx\n                    elif key == 'right':\n                        cx += posx - w\n                    elif key == 'center_x':\n                        cx += posx - (w / 2.)\n\n                c.x = cx\n                c.y = cy\n                c.width = w\n                c.height = h\n                y += h + spacing\n\n    def add_widget(self, widget, index=0):\n        widget.bind(\n            pos_hint=self._trigger_layout)\n        return super(BoxLayout, self).add_widget(widget, index)\n\n    def remove_widget(self, widget):\n        widget.unbind(\n            pos_hint=self._trigger_layout)\n        return super(BoxLayout, self).remove_widget(widget)\n"
  },
  {
    "path": "tickeys/kivy/uix/bubble.py",
    "content": "'''\nBubble\n======\n\n.. versionadded:: 1.1.0\n\n.. image:: images/bubble.jpg\n    :align: right\n\nThe Bubble widget is a form of menu or a small popup where the menu options\nare stacked either vertically or horizontally.\n\nThe :class:`Bubble` contains an arrow pointing in the direction you\nchoose.\n\nSimple example\n--------------\n\n.. include:: ../../examples/widgets/bubble_test.py\n    :literal:\n\nCustomize the Bubble\n--------------------\n\nYou can choose the direction in which the arrow points::\n\n    Bubble(arrow_pos='top_mid')\n\nThe widgets added to the Bubble are ordered horizontally by default, like a\nBoxlayout. You can change that by::\n\n    orientation = 'vertical'\n\nTo add items to the bubble::\n\n    bubble = Bubble(orientation = 'vertical')\n    bubble.add_widget(your_widget_instance)\n\nTo remove items::\n\n    bubble.remove_widget(widget)\n    or\n    bubble.clear_widgets()\n\nTo access the list of children, use content.children::\n\n    bubble.content.children\n\n.. warning::\n  This is important! Do not use bubble.children\n\nTo change the appearance of the bubble::\n\n    bubble.background_color = (1, 0, 0, .5) #50% translucent red\n    bubble.border = [0, 0, 0, 0]\n    background_image = 'path/to/background/image'\n    arrow_image = 'path/to/arrow/image'\n'''\n\n__all__ = ('Bubble', 'BubbleButton', 'BubbleContent')\n\nfrom kivy.uix.image import Image\nfrom kivy.uix.widget import Widget\nfrom kivy.uix.scatter import Scatter\nfrom kivy.uix.gridlayout import GridLayout\nfrom kivy.uix.boxlayout import BoxLayout\nfrom kivy.uix.button import Button\nfrom kivy.properties import ObjectProperty, StringProperty, OptionProperty, \\\n    ListProperty, BooleanProperty\nfrom kivy.clock import Clock\nfrom kivy.base import EventLoop\nfrom kivy.metrics import dp\n\n\nclass BubbleButton(Button):\n    '''A button intended for use in a Bubble widget.\n    You can use a \"normal\" button class, but it will not look good unless\n    the background is changed.\n\n    Rather use this BubbleButton widget that is already defined and provides a\n    suitable background for you.\n    '''\n    pass\n\n\nclass BubbleContent(GridLayout):\n    pass\n\n\nclass Bubble(GridLayout):\n    '''Bubble class. See module documentation for more information.\n    '''\n\n    background_color = ListProperty([1, 1, 1, 1])\n    '''Background color, in the format (r, g, b, a).\n\n    :attr:`background_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [1, 1, 1, 1].\n    '''\n\n    border = ListProperty([16, 16, 16, 16])\n    '''Border used for :class:`~kivy.graphics.vertex_instructions.BorderImage`\n    graphics instruction. Used with the :attr:`background_image`.\n    It should be used when using custom backgrounds.\n\n    It must be a list of 4 values: (top, right, bottom, left). Read the\n    BorderImage instructions for more information about how to use it.\n\n    :attr:`border` is a :class:`~kivy.properties.ListProperty` and defaults to\n    (16, 16, 16, 16)\n    '''\n\n    background_image = StringProperty(\n        'atlas://data/images/defaulttheme/bubble')\n    '''Background image of the bubble.\n\n    :attr:`background_image` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/bubble'.\n    '''\n\n    arrow_image = StringProperty(\n        'atlas://data/images/defaulttheme/bubble_arrow')\n    ''' Image of the arrow pointing to the bubble.\n\n    :attr:`arrow_image` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/bubble_arrow'.\n    '''\n\n    show_arrow = BooleanProperty(True)\n    ''' Indicates whether to show arrow.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`show_arrow` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to `True`.\n    '''\n\n    arrow_pos = OptionProperty('bottom_mid', options=(\n        'left_top', 'left_mid', 'left_bottom', 'top_left', 'top_mid',\n        'top_right', 'right_top', 'right_mid', 'right_bottom',\n        'bottom_left', 'bottom_mid', 'bottom_right'))\n    '''Specifies the position of the arrow relative to the bubble.\n    Can be one of: left_top, left_mid, left_bottom top_left, top_mid, top_right\n    right_top, right_mid, right_bottom bottom_left, bottom_mid, bottom_right.\n\n    :attr:`arrow_pos` is a :class:`~kivy.properties.OptionProperty` and\n    defaults to 'bottom_mid'.\n    '''\n\n    content = ObjectProperty(None)\n    '''This is the object where the main content of the bubble is held.\n\n    :attr:`content` is a :class:`~kivy.properties.ObjectProperty` and\n    defaults to 'None'.\n    '''\n\n    orientation = OptionProperty('horizontal',\n                                 options=('horizontal', 'vertical'))\n    '''This specifies the manner in which the children inside bubble\n    are arranged. Can be one of 'vertical' or 'horizontal'.\n\n    :attr:`orientation` is a :class:`~kivy.properties.OptionProperty` and\n    defaults to 'horizontal'.\n    '''\n\n    limit_to = ObjectProperty(None, allownone=True)\n    '''Specifies the widget to which the bubbles position is restricted.\n\n    .. versionadded:: 1.6.0\n\n    :attr:`limit_to` is a :class:`~kivy.properties.ObjectProperty` and\n    defaults to 'None'.\n    '''\n\n    def __init__(self, **kwargs):\n        self._prev_arrow_pos = None\n        self._arrow_layout = BoxLayout()\n        self._bk_img = Image(\n            source=self.background_image, allow_stretch=True,\n            keep_ratio=False, color=self.background_color)\n        self.background_texture = self._bk_img.texture\n        self._arrow_img = Image(source=self.arrow_image,\n                                allow_stretch=True,\n                                color=self.background_color)\n        self.content = content = BubbleContent(parent=self)\n        super(Bubble, self).__init__(**kwargs)\n        content.parent = None\n        self.add_widget(content)\n        self.on_arrow_pos()\n\n    def add_widget(self, *l):\n        content = self.content\n        if content is None:\n            return\n        if l[0] == content or l[0] == self._arrow_img\\\n                or l[0] == self._arrow_layout:\n            super(Bubble, self).add_widget(*l)\n        else:\n            content.add_widget(*l)\n\n    def remove_widget(self, *l):\n        content = self.content\n        if not content:\n            return\n        if l[0] == content or l[0] == self._arrow_img\\\n                or l[0] == self._arrow_layout:\n            super(Bubble, self).remove_widget(*l)\n        else:\n            content.remove_widget(l[0])\n\n    def clear_widgets(self, **kwargs):\n        content = self.content\n        if not content:\n            return\n        if kwargs.get('do_super', False):\n            super(Bubble, self).clear_widgets()\n        else:\n            content.clear_widgets()\n\n    def on_show_arrow(self, instance, value):\n        self._arrow_img.opacity = int(value)\n\n    def on_parent(self, instance, value):\n        Clock.schedule_once(self._update_arrow)\n\n    def on_pos(self, instance, pos):\n        lt = self.limit_to\n\n        if lt:\n            self.limit_to = None\n            if lt is EventLoop.window:\n                x = y = 0\n                top = lt.height\n                right = lt.width\n            else:\n                x, y = lt.x, lt.y\n                top, right = lt.top, lt.right\n\n            self.x = max(self.x, x)\n            self.right = min(self.right, right)\n            self.top = min(self.top, top)\n            self.y = max(self.y, y)\n            self.limit_to = lt\n\n    def on_background_image(self, *l):\n        self._bk_img.source = self.background_image\n\n    def on_background_color(self, *l):\n        if self.content is None:\n            return\n        self._arrow_img.color = self._bk_img.color = self.background_color\n\n    def on_orientation(self, *l):\n        content = self.content\n        if not content:\n            return\n        if self.orientation[0] == 'v':\n            content.cols = 1\n            content.rows = 99\n        else:\n            content.cols = 99\n            content.rows = 1\n\n    def on_arrow_image(self, *l):\n        self._arrow_img.source = self.arrow_image\n\n    def on_arrow_pos(self, *l):\n        self_content = self.content\n        if not self_content:\n            Clock.schedule_once(self.on_arrow_pos)\n            return\n        if self_content not in self.children:\n            Clock.schedule_once(self.on_arrow_pos)\n            return\n        self_arrow_pos = self.arrow_pos\n        if self._prev_arrow_pos == self_arrow_pos:\n            return\n        self._prev_arrow_pos = self_arrow_pos\n\n        self_arrow_layout = self._arrow_layout\n        self_arrow_layout.clear_widgets()\n        self_arrow_img = self._arrow_img\n        self._sctr = self._arrow_img\n        self.clear_widgets(do_super=True)\n        self_content.parent = None\n\n        self_arrow_img.size_hint = (1, None)\n        self_arrow_img.height = dp(self_arrow_img.texture_size[1])\n        self_arrow_img.pos = 0, 0\n        widget_list = []\n        arrow_list = []\n        parent = self_arrow_img.parent\n        if parent:\n            parent.remove_widget(self_arrow_img)\n\n        if self_arrow_pos[0] == 'b' or self_arrow_pos[0] == 't':\n            self.cols = 1\n            self.rows = 3\n            self_arrow_layout.orientation = 'horizontal'\n            self_arrow_img.width = self.width / 3\n            self_arrow_layout.size_hint = (1, None)\n            self_arrow_layout.height = self_arrow_img.height\n            if self_arrow_pos[0] == 'b':\n                if self_arrow_pos == 'bottom_mid':\n                    widget_list = (self_content, self_arrow_img)\n                else:\n                    if self_arrow_pos == 'bottom_left':\n                        arrow_list = (self_arrow_img, Widget(), Widget())\n                    elif self_arrow_pos == 'bottom_right':\n                        #add two dummy widgets\n                        arrow_list = (Widget(), Widget(), self_arrow_img)\n                    widget_list = (self_content, self_arrow_layout)\n            else:\n                sctr = Scatter(do_translation=False,\n                               rotation=180,\n                               do_rotation=False,\n                               do_scale=False,\n                               size_hint=(None, None),\n                               size=self_arrow_img.size)\n                sctr.add_widget(self_arrow_img)\n                if self_arrow_pos == 'top_mid':\n                    #add two dummy widgets\n                    arrow_list = (Widget(), sctr, Widget())\n                elif self_arrow_pos == 'top_left':\n                    arrow_list = (sctr, Widget(), Widget())\n                elif self_arrow_pos == 'top_right':\n                    arrow_list = (Widget(), Widget(), sctr)\n                widget_list = (self_arrow_layout, self_content)\n        elif self_arrow_pos[0] == 'l' or self_arrow_pos[0] == 'r':\n            self.cols = 3\n            self.rows = 1\n            self_arrow_img.width = self.height / 3\n            self_arrow_layout.orientation = 'vertical'\n            self_arrow_layout.cols = 1\n            self_arrow_layout.size_hint = (None, 1)\n            self_arrow_layout.width = self_arrow_img.height\n\n            rotation = -90 if self_arrow_pos[0] == 'l' else 90\n            self._sctr = sctr = Scatter(do_translation=False,\n                                        rotation=rotation,\n                                        do_rotation=False,\n                                        do_scale=False,\n                                        size_hint=(None, None),\n                                        size=(self_arrow_img.size))\n            sctr.add_widget(self_arrow_img)\n\n            if self_arrow_pos[-4:] == '_top':\n                arrow_list = (Widget(size_hint=(1, .07)),\n                              sctr, Widget(size_hint=(1, .3)))\n            elif self_arrow_pos[-4:] == '_mid':\n                arrow_list = (Widget(), sctr, Widget())\n                Clock.schedule_once(self._update_arrow)\n            elif self_arrow_pos[-7:] == '_bottom':\n                arrow_list = (Widget(), Widget(), sctr)\n\n            if self_arrow_pos[0] == 'l':\n                widget_list = (self_arrow_layout, self_content)\n            else:\n                widget_list = (self_content, self_arrow_layout)\n\n        # add widgets to arrow_layout\n        add = self_arrow_layout.add_widget\n        for widg in arrow_list:\n            add(widg)\n\n        # add widgets to self\n        add = self.add_widget\n        for widg in widget_list:\n            add(widg)\n\n    def _update_arrow(self, *dt):\n        if self.arrow_pos in ('left_mid', 'right_mid'):\n            self._sctr.center_y = self._arrow_layout.center_y\n"
  },
  {
    "path": "tickeys/kivy/uix/button.py",
    "content": "'''\nButton\n======\n\n.. image:: images/button.jpg\n    :align: right\n\nThe :class:`Button` is a :class:`~kivy.uix.label.Label` with associated actions\nthat are triggered when the button is pressed (or released after a\nclick/touch). To configure the button, the same properties are used\nas for the Label class::\n\n    button = Button(text='Hello world', font_size=14)\n\nTo attach a callback when the button is pressed (clicked/touched), use\n:class:`~kivy.uix.widget.Widget.bind`::\n\n    def callback(instance):\n        print('The button <%s> is being pressed' % instance.text)\n\n    btn1 = Button(text='Hello world 1')\n    btn1.bind(on_press=callback)\n    btn2 = Button(text='Hello world 2')\n    btn2.bind(on_press=callback)\n\nIf you want to be notified every time the button state changes, you can bind\nto the :attr:`Button.state` property::\n\n    def callback(instance, value):\n        print('My button <%s> state is <%s>' % (instance, value))\n    btn1 = Button(text='Hello world 1')\n    btn1.bind(state=callback)\n\n'''\n\n__all__ = ('Button', )\n\nfrom kivy.uix.label import Label\nfrom kivy.properties import StringProperty, ListProperty\nfrom kivy.uix.behaviors import ButtonBehavior\n\n\nclass Button(ButtonBehavior, Label):\n    '''Button class, see module documentation for more information.\n\n    .. versionchanged:: 1.8.0\n        The behavior / logic of the button has been moved to\n        :class:`~kivy.uix.behaviors.ButtonBehaviors`.\n\n    '''\n\n    background_color = ListProperty([1, 1, 1, 1])\n    '''Background color, in the format (r, g, b, a).\n\n    This acts as a *multiplier* to the texture colour. The default\n    texture is grey, so just setting the background color will give\n    a darker result. To set a plain color, set the\n    :attr:`background_normal` to ``''``.\n\n    .. versionadded:: 1.0.8\n\n    The :attr:`background_color` is a\n    :class:`~kivy.properties.ListProperty` and defaults to [1, 1, 1, 1].\n    '''\n\n    background_normal = StringProperty(\n        'atlas://data/images/defaulttheme/button')\n    '''Background image of the button used for the default graphical\n    representation when the button is not pressed.\n\n    .. versionadded:: 1.0.4\n\n    :attr:`background_normal` is a :class:`~kivy.properties.StringProperty`\n    and defaults to 'atlas://data/images/defaulttheme/button'.\n    '''\n\n    background_down = StringProperty(\n        'atlas://data/images/defaulttheme/button_pressed')\n    '''Background image of the button used for the default graphical\n    representation when the button is pressed.\n\n    .. versionadded:: 1.0.4\n\n    :attr:`background_down` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/button_pressed'.\n    '''\n\n    background_disabled_normal = StringProperty(\n        'atlas://data/images/defaulttheme/button_disabled')\n    '''Background image of the button used for the default graphical\n    representation when the button is disabled and not pressed.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`background_disabled_normal` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/button_disabled'.\n    '''\n\n    background_disabled_down = StringProperty(\n        'atlas://data/images/defaulttheme/button_disabled_pressed')\n    '''Background image of the button used for the default graphical\n    representation when the button is disabled and pressed.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`background_disabled_down` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/button_disabled_pressed'.\n    '''\n\n    border = ListProperty([16, 16, 16, 16])\n    '''Border used for :class:`~kivy.graphics.vertex_instructions.BorderImage`\n    graphics instruction. Used with :attr:`background_normal` and\n    :attr:`background_down`. Can be used for custom backgrounds.\n\n    It must be a list of four values: (top, right, bottom, left). Read the\n    BorderImage instruction for more information about how to use it.\n\n    :attr:`border` is a :class:`~kivy.properties.ListProperty` and defaults to\n    (16, 16, 16, 16)\n    '''\n"
  },
  {
    "path": "tickeys/kivy/uix/camera.py",
    "content": "'''\nCamera\n======\n\nThe :class:`Camera` widget is used to capture and display video from a camera.\nOnce the widget is created, the texture inside the widget will be automatically\nupdated. Our :class:`~kivy.core.camera.CameraBase` implementation is used under\nthe hood::\n\n    cam = Camera()\n\nBy default, the first camera found on your system is used. To use a different\ncamera, set the index property::\n\n    cam = Camera(index=1)\n\nYou can also select the camera resolution::\n\n    cam = Camera(resolution=(320, 240))\n\n.. warning::\n\n    The camera texture is not updated as soon as you have created the object.\n    The camera initialization is asynchronous, so there may be a delay before\n    the requested texture is created.\n'''\n\n__all__ = ('Camera', )\n\nfrom kivy.uix.image import Image\nfrom kivy.core.camera import Camera as CoreCamera\nfrom kivy.properties import NumericProperty, ListProperty, \\\n    BooleanProperty\n\n\nclass Camera(Image):\n    '''Camera class. See module documentation for more information.\n    '''\n\n    play = BooleanProperty(True)\n    '''Boolean indicating whether the camera is playing or not.\n    You can start/stop the camera by setting this property::\n\n        # start the camera playing at creation (default)\n        cam = Camera(play=True)\n\n        # create the camera, and start later\n        cam = Camera(play=False)\n        # and later\n        cam.play = True\n\n    :attr:`play` is a :class:`~kivy.properties.BooleanProperty` and defaults to\n    True.\n    '''\n\n    index = NumericProperty(-1)\n    '''Index of the used camera, starting from 0.\n\n    :attr:`index` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to -1 to allow auto selection.\n    '''\n\n    resolution = ListProperty([-1, -1])\n    '''Preferred resolution to use when invoking the camera. If you are using\n    [-1, -1], the resolution will be the default one::\n\n        # create a camera object with the best image available\n        cam = Camera()\n\n        # create a camera object with an image of 320x240 if possible\n        cam = Camera(resolution=(320, 240))\n\n    .. warning::\n\n        Depending on the implementation, the camera may not respect this\n        property.\n\n    :attr:`resolution` is a :class:`~kivy.properties.ListProperty` and defaults\n    to [-1, -1].\n    '''\n\n    def __init__(self, **kwargs):\n        self._camera = None\n        super(Camera, self).__init__(**kwargs)\n        if self.index == -1:\n            self.index = 0\n        self.bind(index=self._on_index,\n                  resolution=self._on_index)\n        self._on_index()\n\n    def on_tex(self, *l):\n        self.canvas.ask_update()\n\n    def _on_index(self, *largs):\n        self._camera = None\n        if self.index < 0:\n            return\n        if self.resolution[0] < 0 or self.resolution[1] < 0:\n            return\n        self._camera = CoreCamera(index=self.index,\n                                  resolution=self.resolution, stopped=True)\n        self._camera.bind(on_load=self._camera_loaded)\n        if self.play:\n            self._camera.start()\n            self._camera.bind(on_texture=self.on_tex)\n\n    def _camera_loaded(self, *largs):\n        self.texture = self._camera.texture\n        self.texture_size = list(self.texture.size)\n\n    def on_play(self, instance, value):\n        if not self._camera:\n            return\n        if value:\n            self._camera.start()\n        else:\n            self._camera.stop()\n"
  },
  {
    "path": "tickeys/kivy/uix/carousel.py",
    "content": "'''\nCarousel\n========\n\n.. versionadded:: 1.4.0\n\nThe :class:`Carousel` widget provides the classic mobile-friendly carousel view\nwhere you can swipe between slides.\nYou can add any content to the carousel and use it horizontally or verticaly.\nThe carousel can display pages in loop or not.\n\nExample::\n\n    class Example1(App):\n\n        def build(self):\n            carousel = Carousel(direction='right')\n            for i in range(10):\n                src = \"http://placehold.it/480x270.png&text=slide-%d&.png\" % i\n                image = Factory.AsyncImage(source=src, allow_stretch=True)\n                carousel.add_widget(image)\n            return carousel\n\n    Example1().run()\n\n.. versionchanged:: 1.5.0\n    The carousel now supports active children, like the\n    :class:`~kivy.uix.scrollview.ScrollView`. It will detect a swipe gesture\n    according to :attr:`Carousel.scroll_timeout` and\n    :attr:`Carousel.scroll_distance`.\n\n    In addition, the container used for adding a slide is now hidden in\n    the API. We made a mistake by exposing it to the user. The impacted\n    properties are:\n    :attr:`Carousel.slides`, :attr:`Carousel.current_slide`,\n    :attr:`Carousel.previous_slide` and :attr:`Carousel.next_slide`.\n\n'''\n\n__all__ = ('Carousel', )\n\nfrom functools import partial\nfrom kivy.clock import Clock\nfrom kivy.factory import Factory\nfrom kivy.animation import Animation\nfrom kivy.uix.stencilview import StencilView\nfrom kivy.uix.relativelayout import RelativeLayout\nfrom kivy.properties import BooleanProperty, OptionProperty, AliasProperty, \\\n    NumericProperty, ListProperty, ObjectProperty, StringProperty\n\n\nclass Carousel(StencilView):\n    '''Carousel class. See module documentation for more information.\n    '''\n\n    slides = ListProperty([])\n    '''List of slides inside the Carousel. The slides are added when a\n    widget is added to Carousel using add_widget().\n\n    :attr:`slides` is a :class:`~kivy.properties.ListProperty` and is\n    read-only.\n    '''\n\n    def _get_slides_container(self):\n        return [x.parent for x in self.slides]\n\n    slides_container = AliasProperty(_get_slides_container, None,\n                                     bind=('slides', ))\n\n    direction = OptionProperty('right',\n                               options=('right', 'left', 'top', 'bottom'))\n    '''Specifies the direction in which the slides are ordered i.e. the\n    direction from which the user swipes to go from one slide to the next.\n    Can be `right`, `left`, 'top', or `bottom`. For example, with\n    the default value of `right`, the second slide is to the right\n    of the first and the user would swipe from the right towards the\n    left to get to the second slide.\n\n    :attr:`direction` is a :class:`~kivy.properties.OptionProperty` and\n    defaults to 'right'.\n    '''\n\n    min_move = NumericProperty(0.2)\n    '''Defines the minimal distance from the edge where the movement is\n    considered a swipe gesture and the Carousel will change its content.\n    This is a percentage of the Carousel width.\n    If the movement doesn't reach this minimal value, then the movement is\n    cancelled and the content is restored to its original position.\n\n    :attr:`min_move` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.2.\n    '''\n\n    anim_move_duration = NumericProperty(0.5)\n    '''Defines the duration of the Carousel animation between pages.\n\n    :attr:`anim_move_duration` is a :class:`~kivy.properties.NumericProperty`\n    and defaults to 0.5.\n    '''\n\n    anim_cancel_duration = NumericProperty(0.3)\n    '''Defines the duration of the animation when a swipe movement is not\n    accepted. This is generally when the user doesnt swipe enough.\n    See :attr:`min_move`.\n\n    :attr:`anim_cancel_duration` is a :class:`~kivy.properties.NumericProperty`\n    and defaults to 0.3.\n    '''\n\n    loop = BooleanProperty(False)\n    '''Allow the Carousel to swipe infinitely. When the user reaches the last\n    page, they will return to first page when trying to swipe to the next.\n\n    :attr:`loop` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    def _get_index(self):\n        if self.slides:\n            return self._index % len(self.slides)\n        return None\n\n    def _set_index(self, value):\n        if self.slides:\n            self._index = value % len(self.slides)\n        else:\n            self._index = None\n    index = AliasProperty(_get_index, _set_index, bind=('_index', 'slides'))\n    '''Get/Set the current visible slide based on the index.\n\n    :attr:`index` is a :class:`~kivy.properties.AliasProperty` and defaults\n    to 0 (the first item).\n    '''\n\n    def _prev_slide(self):\n        slides = self.slides\n        len_slides = len(slides)\n        index = self.index\n        if len_slides < 2:  # None, or 1 slide\n            return None\n        if len_slides == 2:\n            if index == 0:\n                return None\n            if index == 1:\n                return slides[0]\n        if self.loop and index == 0:\n            return slides[-1]\n        if index > 0:\n            return slides[index - 1]\n\n    previous_slide = AliasProperty(_prev_slide, None, bind=('slides', 'index'))\n    '''The previous slide in the Carousel. It is None if the current slide is\n    the first slide in the Carousel. If :attr:`orientation` is 'horizontal',\n    the previous slide is to the left. If :attr:`orientation` is 'vertical',\n    the previous slide towards the bottom.\n\n    :attr:`previous_slide` is a :class:`~kivy.properties.AliasProperty`.\n\n    .. versionchanged:: 1.5.0\n        This property doesn't expose the container used for storing the slide.\n        It returns the widget you have added.\n    '''\n\n    def _curr_slide(self):\n        if len(self.slides):\n            return self.slides[self.index]\n    current_slide = AliasProperty(_curr_slide, None, bind=('slides', 'index'))\n    '''The currently shown slide.\n\n    :attr:`current_slide` is an :class:`~kivy.properties.AliasProperty`.\n\n    .. versionchanged:: 1.5.0\n        The property doesn't expose the container used for storing the slide.\n        It returns widget you have added.\n    '''\n\n    def _next_slide(self):\n        if len(self.slides) < 2:  # None, or 1 slide\n            return None\n        if len(self.slides) == 2:\n            if self.index == 0:\n                return self.slides[1]\n            if self.index == 1:\n                return None\n        if self.loop and self.index == len(self.slides) - 1:\n            return self.slides[0]\n        if self.index < len(self.slides) - 1:\n            return self.slides[self.index + 1]\n    next_slide = AliasProperty(_next_slide, None, bind=('slides', 'index'))\n    '''The next slide in the Carousel. It is None if the current slide is\n    the last slide in the Carousel. If :attr:`orientation` is 'horizontal',\n    the next slide is to the right. If :attr:`orientation` is 'vertical',\n    the next slide is towards the bottom.\n\n    :attr:`next_slide` is a :class:`~kivy.properties.AliasProperty`.\n\n    .. versionchanged:: 1.5.0\n        The property doesn't expose the container used for storing the slide.\n        It returns the widget you have added.\n    '''\n\n    scroll_timeout = NumericProperty(200)\n    '''Timeout allowed to trigger the :attr:`scroll_distance`, in milliseconds.\n    If the user has not moved :attr:`scroll_distance` within the timeout,\n    the scrolling will be disabled and the touch event will go to the children.\n\n    :attr:`scroll_timeout` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 200 (milliseconds)\n\n    .. versionadded:: 1.5.0\n    '''\n\n    scroll_distance = NumericProperty('20dp')\n    '''Distance to move before scrolling the :class:`Carousel` in pixels. As\n    soon as the distance has been traveled, the :class:`Carousel` will start\n    to scroll, and no touch event will go to children.\n    It is advisable that you base this value on the dpi of your target device's\n    screen.\n\n    :attr:`scroll_distance` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 20dp.\n\n    .. versionadded:: 1.5.0\n    '''\n\n    anim_type = StringProperty('out_quad')\n    '''Type of animation to use while animating in the next/previous slide.\n\n    .. versionadded:: 1.8.0\n    '''\n\n    #### private properties, for internal use only ###\n    _index = NumericProperty(0, allownone=True)\n    _prev = ObjectProperty(None, allownone=True)\n    _current = ObjectProperty(None, allownone=True)\n    _next = ObjectProperty(None, allownone=True)\n    _offset = NumericProperty(0)\n    _touch = ObjectProperty(None, allownone=True)\n\n    def __init__(self, **kwargs):\n        self._trigger_position_visible_slides = Clock.create_trigger(\n            self._position_visible_slides, -1)\n        super(Carousel, self).__init__(**kwargs)\n        self._skip_slide = None\n\n    def load_slide(self, slide):\n        '''Animate to the slide that is passed as the argument.\n\n        .. versionchanged:: 1.8.0\n        '''\n        slides = self.slides\n        start, stop = slides.index(self.current_slide), slides.index(slide)\n        if start == stop:\n            return\n\n        self._skip_slide = stop\n        if stop > start:\n            self._insert_visible_slides(_next_slide=slide)\n            self.load_next()\n        else:\n            self._insert_visible_slides(_prev_slide=slide)\n            self.load_previous()\n\n    def load_previous(self):\n        '''Animate to the previous slide.\n\n        .. versionadded:: 1.7.0\n        '''\n        self.load_next(mode='prev')\n\n    def load_next(self, mode='next'):\n        '''Animate to next slide.\n\n        .. versionadded:: 1.7.0\n        '''\n        if not self.index is None:\n            w, h = self.size\n            _direction = {\n                'top': -h / 2,\n                'bottom': h / 2,\n                'left': w / 2,\n                'right': -w / 2}\n            _offset = _direction[self.direction]\n            if mode == 'prev':\n                _offset = -_offset\n\n            self._start_animation(min_move=0, offset=_offset)\n\n    def get_slide_container(self, slide):\n        return slide.parent\n\n    def _insert_visible_slides(self, _next_slide=None, _prev_slide=None):\n        get_slide_container = self.get_slide_container\n\n        previous_slide = _prev_slide if _prev_slide else self.previous_slide\n        if previous_slide:\n            self._prev = get_slide_container(previous_slide)\n        else:\n            self._prev = None\n\n        current_slide = self.current_slide\n        if current_slide:\n            self._current = get_slide_container(current_slide)\n        else:\n            self._current = None\n\n        next_slide = _next_slide if _next_slide else self.next_slide\n        if next_slide:\n            self._next = get_slide_container(next_slide)\n        else:\n            self._next = None\n\n        super_remove = super(Carousel, self).remove_widget\n        for container in self.slides_container:\n            super_remove(container)\n\n        if self._prev:\n            super(Carousel, self).add_widget(self._prev)\n        if self._next:\n            super(Carousel, self).add_widget(self._next)\n        if self._current:\n            super(Carousel, self).add_widget(self._current)\n\n    def _position_visible_slides(self, *args):\n        slides, index = self.slides, self.index\n        no_of_slides = len(slides) - 1\n        if not slides:\n            return\n        x, y, width, height = self.x, self.y, self.width, self.height\n        _offset, direction = self._offset, self.direction\n        _prev, _next, _current = self._prev, self._next, self._current\n        get_slide_container = self.get_slide_container\n        last_slide = get_slide_container(slides[-1])\n        first_slide = get_slide_container(slides[0])\n        skip_next = False\n        _loop = self.loop\n\n        if direction[0] in ['r', 'l']:\n            xoff = x + _offset\n            x_prev = {'l': xoff + width, 'r': xoff - width}\n            x_next = {'l': xoff - width, 'r': xoff + width}\n            if _prev:\n                _prev.pos = (x_prev[direction[0]], y)\n            elif _loop and _next and index == 0:\n                # if first slide is moving to right with direction set to right\n                # or toward left with direction set to left\n                if ((_offset > 0 and direction[0] == 'r') or\n                        (_offset < 0 and direction[0] == 'l')):\n                    # put last_slide before first slide\n                    last_slide.pos = (x_prev[direction[0]], y)\n                    skip_next = True\n            if _current:\n                _current.pos = (xoff, y)\n            if skip_next:\n                return\n            if _next:\n                _next.pos = (x_next[direction[0]], y)\n            elif _loop and _prev and index == no_of_slides:\n                if ((_offset < 0 and direction[0] == 'r') or\n                        (_offset > 0 and direction[0] == 'l')):\n                    first_slide.pos = (x_next[direction[0]], y)\n        if direction[0] in ['t', 'b']:\n            yoff = y + _offset\n            y_prev = {'t': yoff - height, 'b': yoff + height}\n            y_next = {'t': yoff + height, 'b': yoff - height}\n            if _prev:\n                _prev.pos = (x, y_prev[direction[0]])\n            elif _loop and _next and index == 0:\n                if ((_offset > 0 and direction[0] == 't') or\n                        (_offset < 0 and direction[0] == 'b')):\n                    last_slide.pos = (x, y_prev[direction[0]])\n                    skip_next = True\n            if _current:\n                _current.pos = (x, yoff)\n            if skip_next:\n                return\n            if _next:\n                _next.pos = (x, y_next[direction[0]])\n            elif _loop and _prev and index == no_of_slides:\n                if ((_offset < 0 and direction[0] == 't') or\n                        (_offset > 0 and direction[0] == 'b')):\n                    first_slide.pos = (x, y_next[direction[0]])\n\n    def on_size(self, *args):\n        size = self.size\n        for slide in self.slides_container:\n            slide.size = size\n        self._trigger_position_visible_slides()\n\n    def on_pos(self, *args):\n        self._trigger_position_visible_slides()\n\n    def on_index(self, *args):\n        self._insert_visible_slides()\n        self._trigger_position_visible_slides()\n        self._offset = 0\n\n    def on_slides(self, *args):\n        if self.slides:\n            self.index = self.index % len(self.slides)\n        self._insert_visible_slides()\n        self._trigger_position_visible_slides()\n\n    def on__offset(self, *args):\n        self._trigger_position_visible_slides()\n        # if reached full offset, switch index to next or prev\n        direction = self.direction\n        _offset = self._offset\n        width = self.width\n        height = self.height\n        index = self.index\n        if self._skip_slide is not None or index is None:\n            return\n\n        if direction[0] == 'r':\n            if _offset <= -width:\n                index += 1\n            if _offset >= width:\n                index -= 1\n        if direction[0] == 'l':\n            if _offset <= -width:\n                index -= 1\n            if _offset >= width:\n                index += 1\n        if direction[0] == 't':\n            if _offset <= - height:\n                index += 1\n            if _offset >= height:\n                index -= 1\n        if direction[0] == 'b':\n            if _offset <= -height:\n                index -= 1\n            if _offset >= height:\n                index += 1\n        self.index = index\n\n    def _start_animation(self, *args, **kwargs):\n        # compute target offset for ease back, next or prev\n        new_offset = 0\n        direction = kwargs.get('direction', self.direction)\n        is_horizontal = direction[0] in ['r', 'l']\n        extent = self.width if is_horizontal else self.height\n        min_move = kwargs.get('min_move', self.min_move)\n        _offset = kwargs.get('offset', self._offset)\n\n        if _offset < min_move * -extent:\n            new_offset = -extent\n        elif _offset > min_move * extent:\n            new_offset = extent\n\n        # if new_offset is 0, it wasnt enough to go next/prev\n        dur = self.anim_move_duration\n        if new_offset == 0:\n            dur = self.anim_cancel_duration\n\n        # detect edge cases if not looping\n        len_slides = len(self.slides)\n        index = self.index\n        if not self.loop or len_slides == 1:\n            is_first = (index == 0)\n            is_last = (index == len_slides - 1)\n            if direction[0] in ['r', 't']:\n                towards_prev = (new_offset > 0)\n                towards_next = (new_offset < 0)\n            else:\n                towards_prev = (new_offset < 0)\n                towards_next = (new_offset > 0)\n            if (is_first and towards_prev) or (is_last and towards_next):\n                new_offset = 0\n\n        anim = Animation(_offset=new_offset, d=dur, t=self.anim_type)\n        anim.cancel_all(self)\n\n        def _cmp(*l):\n            if self._skip_slide is not None:\n                self.index = self._skip_slide\n                self._skip_slide = None\n\n        anim.bind(on_complete=_cmp)\n        anim.start(self)\n\n    def _get_uid(self, prefix='sv'):\n        return '{0}.{1}'.format(prefix, self.uid)\n\n    def on_touch_down(self, touch):\n        if not self.collide_point(*touch.pos):\n            touch.ud[self._get_uid('cavoid')] = True\n            return\n        if self.disabled:\n            return True\n        if self._touch:\n            return super(Carousel, self).on_touch_down(touch)\n        Animation.cancel_all(self)\n        self._touch = touch\n        uid = self._get_uid()\n        touch.grab(self)\n        touch.ud[uid] = {\n            'mode': 'unknown',\n            'time': touch.time_start}\n        Clock.schedule_once(self._change_touch_mode,\n                            self.scroll_timeout / 1000.)\n        return True\n\n    def on_touch_move(self, touch):\n        if self._get_uid('cavoid') in touch.ud:\n            return\n        if self._touch is not touch:\n            super(Carousel, self).on_touch_move(touch)\n            return self._get_uid() in touch.ud\n        if touch.grab_current is not self:\n            return True\n        ud = touch.ud[self._get_uid()]\n        direction = self.direction\n        if ud['mode'] == 'unknown':\n            if direction[0] in ('r', 'l'):\n                distance = abs(touch.ox - touch.x)\n            else:\n                distance = abs(touch.oy - touch.y)\n            if distance > self.scroll_distance:\n                Clock.unschedule(self._change_touch_mode)\n                ud['mode'] = 'scroll'\n        else:\n            if direction[0] in ('r', 'l'):\n                self._offset += touch.dx\n            if direction[0] in ('t', 'b'):\n                self._offset += touch.dy\n        return True\n\n    def on_touch_up(self, touch):\n        if self._get_uid('cavoid') in touch.ud:\n            return\n        if self in [x() for x in touch.grab_list]:\n            touch.ungrab(self)\n            self._touch = None\n            ud = touch.ud[self._get_uid()]\n            if ud['mode'] == 'unknown':\n                Clock.unschedule(self._change_touch_mode)\n                super(Carousel, self).on_touch_down(touch)\n                Clock.schedule_once(partial(self._do_touch_up, touch), .1)\n            else:\n                self._start_animation()\n\n        else:\n            if self._touch is not touch and self.uid not in touch.ud:\n                super(Carousel, self).on_touch_up(touch)\n        return self._get_uid() in touch.ud\n\n    def _do_touch_up(self, touch, *largs):\n        super(Carousel, self).on_touch_up(touch)\n        # don't forget about grab event!\n        for x in touch.grab_list[:]:\n            touch.grab_list.remove(x)\n            x = x()\n            if not x:\n                continue\n            touch.grab_current = x\n            super(Carousel, self).on_touch_up(touch)\n        touch.grab_current = None\n\n    def _change_touch_mode(self, *largs):\n        if not self._touch:\n            return\n        self._start_animation()\n        uid = self._get_uid()\n        touch = self._touch\n        ud = touch.ud[uid]\n        if ud['mode'] == 'unknown':\n            touch.ungrab(self)\n            self._touch = None\n            super(Carousel, self).on_touch_down(touch)\n            return\n\n    def add_widget(self, widget, index=0):\n        slide = RelativeLayout(size=self.size, x=self.x - self.width, y=self.y)\n        slide.add_widget(widget)\n        super(Carousel, self).add_widget(slide, index)\n        if index != 0:\n            self.slides.insert(index, widget)\n        else:\n            self.slides.append(widget)\n\n    def remove_widget(self, widget, *args, **kwargs):\n        # XXX be careful, the widget.parent refer to the RelativeLayout\n        # added in add_widget(). But it will break if RelativeLayout\n        # implementation change.\n        # if we passed the real widget\n        if widget in self.slides:\n            slide = widget.parent\n            self.slides.remove(widget)\n            return slide.remove_widget(widget, *args, **kwargs)\n        return super(Carousel, self).remove_widget(widget, *args, **kwargs)\n\n    def clear_widgets(self):\n        for slide in self.slides[:]:\n            self.remove_widget(slide)\n        super(Carousel, self).clear_widgets()\n\n\nif __name__ == '__main__':\n    from kivy.app import App\n\n    class Example1(App):\n\n        def build(self):\n            carousel = Carousel(direction='left',\n                                loop=True)\n            for i in range(4):\n                src = \"http://placehold.it/480x270.png&text=slide-%d&.png\" % i\n                image = Factory.AsyncImage(source=src, allow_stretch=True)\n                carousel.add_widget(image)\n            return carousel\n\n    Example1().run()\n"
  },
  {
    "path": "tickeys/kivy/uix/checkbox.py",
    "content": "'''\nCheckBox\n========\n\n.. versionadded:: 1.4.0\n\n.. image:: images/checkbox.png\n    :align: right\n\n:class:`CheckBox` is a specific two-state button that can be either checked or\nunchecked. If the CheckBox is in a Group, it becomes a Radio button.\nAs with the :class:`~kivy.uix.togglebutton.ToggleButton`, only one Radio button\nat a time can be selected when the :attr:`CheckBox.group` is set.\n\nAn example usage::\n\n    from kivy.uix.checkbox import CheckBox\n\n    # ...\n\n    def on_checkbox_active(checkbox, value):\n        if value:\n            print('The checkbox', checkbox, 'is active')\n        else:\n            print('The checkbox', checkbox, 'is inactive')\n\n    checkbox = CheckBox()\n    checkbox.bind(active=on_checkbox_active)\n'''\n\n__all__ = ('CheckBox', )\n\nfrom kivy.uix.widget import Widget\nfrom kivy.properties import BooleanProperty, StringProperty\nfrom kivy.uix.behaviors import ToggleButtonBehavior\n\n\nclass CheckBox(ToggleButtonBehavior, Widget):\n    '''CheckBox class, see module documentation for more information.\n    '''\n\n    active = BooleanProperty(False)\n    '''Indicates if the switch is active or inactive.\n\n    :attr:`active` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    background_checkbox_normal = StringProperty(\n        'atlas://data/images/defaulttheme/checkbox_off')\n    '''Background image of the checkbox used for the default graphical\n    representation when the checkbox is not active.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`background_checkbox_normal` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/checkbox_off'.\n    '''\n\n    background_checkbox_down = StringProperty(\n        'atlas://data/images/defaulttheme/checkbox_on')\n    '''Background image of the checkbox used for the default graphical\n    representation when the checkbox is active.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`background_checkbox_down` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/checkbox_on'.\n    '''\n\n    background_checkbox_disabled_normal = StringProperty(\n        'atlas://data/images/defaulttheme/checkbox_disabled_off')\n    '''Background image of the checkbox used for the default graphical\n    representation when the checkbox is disabled and not active.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`background_checkbox_disabled_normal` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/checkbox_disabled_off'.\n    '''\n\n    background_checkbox_disabled_down = StringProperty(\n        'atlas://data/images/defaulttheme/checkbox_disabled_on')\n    '''Background image of the checkbox used for the default graphical\n    representation when the checkbox is disabled and active.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`background_checkbox_disabled_down` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/checkbox_disabled_on'.\n    '''\n\n    background_radio_normal = StringProperty(\n        'atlas://data/images/defaulttheme/checkbox_radio_off')\n    '''Background image of the radio button used for the default graphical\n    representation when the radio button is not active.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`background_radio_normal` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/checkbox_radio_off'.\n    '''\n\n    background_radio_down = StringProperty(\n        'atlas://data/images/defaulttheme/checkbox_radio_on')\n    '''Background image of the radio button used for the default graphical\n    representation when the radio button is active.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`background_radio_down` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/checkbox_radio_on'.\n    '''\n\n    background_radio_disabled_normal = StringProperty(\n        'atlas://data/images/defaulttheme/checkbox_radio_disabled_off')\n    '''Background image of the radio button used for the default graphical\n    representation when the radio button is disabled and not active.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`background_radio_disabled_normal` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/checkbox_radio_disabled_off'.\n    '''\n\n    background_radio_disabled_down = StringProperty(\n        'atlas://data/images/defaulttheme/checkbox_radio_disabled_on')\n    '''Background image of the radio button used for the default graphical\n    representation when the radio button is disabled and active.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`background_radio_disabled_down` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/checkbox_radio_disabled_on'.\n    '''\n\n    def on_state(self, instance, value):\n        if value == 'down':\n            self.active = True\n        else:\n            self.active = False\n\n    def _toggle_active(self):\n        self._do_press()\n\n    def on_active(self, instance, value):\n        self.state = 'down' if value else 'normal'\n"
  },
  {
    "path": "tickeys/kivy/uix/codeinput.py",
    "content": "'''\nCode Input\n==========\n\n.. versionadded:: 1.5.0\n\n.. image:: images/codeinput.jpg\n\n\nThe :class:`CodeInput` provides a box of editable highlighted text like the one\nshown in the image.\n\nIt supports all the features provided by the :class:`~kivy.uix.textinput` as\nwell as code highlighting for `languages supported by pygments\n<http://pygments.org/docs/lexers/>`_ along with `KivyLexer` for\n:mod:`kivy.lang` highlighting.\n\nUsage example\n-------------\n\nTo create a CodeInput with highlighting for `KV language`::\n\n    from kivy.uix.codeinput import CodeInput\n    from kivy.extras.highlight import KivyLexer\n    codeinput = CodeInput(lexer=KivyLexer())\n\nTo create a CodeInput with highlighting for `Cython`::\n\n    from kivy.uix.codeinput import CodeInput\n    from pygments.lexers import CythonLexer\n    codeinput = CodeInput(lexer=CythonLexer())\n\n'''\n\n__all__ = ('CodeInput', )\n\nfrom pygments import highlight\nfrom pygments import lexers\nfrom pygments import styles\nfrom pygments.formatters import BBCodeFormatter\n\nfrom kivy.uix.textinput import TextInput\nfrom kivy.core.text.markup import MarkupLabel as Label\nfrom kivy.cache import Cache\nfrom kivy.properties import ObjectProperty, OptionProperty\nfrom kivy.utils import get_hex_from_color\n\nCache_get = Cache.get\nCache_append = Cache.append\n\n# TODO: color chooser for keywords/strings/...\n\n\nclass CodeInput(TextInput):\n    '''CodeInput class, used for displaying highlighted code.\n    '''\n\n    lexer = ObjectProperty(None)\n    '''This holds the selected Lexer used by pygments to highlight the code.\n\n\n    :attr:`lexer` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to `PythonLexer`.\n    '''\n\n    style_name = OptionProperty(\n        'default', options=list(styles.get_all_styles())\n    )\n    '''Name of the pygments style to use for formatting.\n\n    :attr:`style_name` is an :class:`~kivy.properties.OptionProperty`\n    and defaults to ``'default'``.\n\n    '''\n\n    style = ObjectProperty(None)\n    '''The pygments style object to use for formatting.\n\n    When ``style_name`` is set, this will be changed to the\n    corresponding style object.\n\n    :attr:`style` is a :class:`~kivy.properties.ObjectProperty` and\n    defaults to ``None``\n\n    '''\n\n    def __init__(self, **kwargs):\n        stylename = kwargs.get('style_name', 'default')\n        style = kwargs['style'] if 'style' in kwargs \\\n            else styles.get_style_by_name(stylename)\n        self.formatter = BBCodeFormatter(style=style)\n        self.lexer = lexers.PythonLexer()\n        self.text_color = '#000000'\n        self._label_cached = Label()\n        self.use_text_color = True\n\n        super(CodeInput, self).__init__(**kwargs)\n\n        self._line_options = kw = self._get_line_options()\n        self._label_cached = Label(**kw)\n        # use text_color as foreground color\n        text_color = kwargs.get('foreground_color')\n        if text_color:\n            self.text_color = get_hex_from_color(text_color)\n        # set foreground to white to allow text colors to show\n        # use text_color as the default color in bbcodes\n        self.use_text_color = False\n        self.foreground_color = [1, 1, 1, .999]\n        if not kwargs.get('background_color'):\n            self.background_color = [.9, .92, .92, 1]\n\n    def on_style_name(self, *args):\n        self.style = styles.get_style_by_name(self.style_name)\n\n    def on_style(self, *args):\n        self.formatter = BBCodeFormatter(style=self.style)\n        self._trigger_update_graphics()\n\n    def _create_line_label(self, text, hint=False):\n        # Create a label from a text, using line options\n        ntext = text.replace(u'\\n', u'').replace(u'\\t', u' ' * self.tab_width)\n        if self.password and not hint:  # Don't replace hint_text with *\n            ntext = u'*' * len(ntext)\n        ntext = self._get_bbcode(ntext)\n        kw = self._get_line_options()\n        cid = u'{}\\0{}\\0{}'.format(ntext, self.password, kw)\n        texture = Cache_get('textinput.label', cid)\n\n        if texture is None:\n            # FIXME right now, we can't render very long line...\n            # if we move on \"VBO\" version as fallback, we won't need to\n            # do this.\n            # try to find the maximum text we can handle\n            label = Label(text=ntext, **kw)\n            if text.find(u'\\n') > 0:\n                label.text = u''\n            else:\n                label.text = ntext\n            label.refresh()\n\n            # ok, we found it.\n            texture = label.texture\n            Cache_append('textinput.label', cid, texture)\n            label.text = ''\n        return texture\n\n    def _get_line_options(self):\n        kw = super(CodeInput, self)._get_line_options()\n        kw['markup'] = True\n        kw['valign'] = 'top'\n        kw['codeinput'] = repr(self.lexer)\n        return kw\n\n    def _get_text_width(self, text, tab_width, _label_cached):\n        # Return the width of a text, according to the current line options.\n        cid = u'{}\\0{}\\0{}'.format(text, self.password,\n                                   self._get_line_options())\n        width = Cache_get('textinput.width', cid)\n        if width is not None:\n            return width\n        lbl = self._create_line_label(text)\n        width = lbl.width\n        Cache_append('textinput.width', cid, width)\n        return width\n\n    def _get_bbcode(self, ntext):\n        # get bbcoded text for python\n        try:\n            ntext[0]\n            # replace brackets with special chars that aren't highlighted\n            # by pygment. can't use &bl; ... cause & is highlighted\n            ntext = ntext.replace(u'[', u'\\x01;').replace(u']', u'\\x02;')\n            ntext = highlight(ntext, self.lexer, self.formatter)\n            ntext = ntext.replace(u'\\x01;', u'&bl;').replace(u'\\x02;', u'&br;')\n            # replace special chars with &bl; and &br;\n            ntext = ''.join((u'[color=', str(self.text_color), u']',\n                             ntext, u'[/color]'))\n            ntext = ntext.replace(u'\\n', u'')\n            return ntext\n        except IndexError:\n            return ''\n\n    # overriden to prevent cursor position off screen\n    def _cursor_offset(self):\n        '''Get the cursor x offset on the current line\n        '''\n        offset = 0\n        try:\n            if self.cursor_col:\n                offset = self._get_text_width(\n                    self._lines[self.cursor_row][:self.cursor_col])\n                return offset\n        except:\n            pass\n        finally:\n            return offset\n\n    def on_lexer(self, instance, value):\n        self._trigger_refresh_text()\n\n    def on_foreground_color(self, instance, text_color):\n        if not self.use_text_color:\n            self.use_text_color = True\n            return\n        self.text_color = get_hex_from_color(text_color)\n        self.use_text_color = False\n        self.foreground_color = (1, 1, 1, .999)\n        self._trigger_refresh_text()\n\n\nif __name__ == '__main__':\n    from kivy.extras.highlight import KivyLexer\n    from kivy.app import App\n\n    class CodeInputTest(App):\n        def build(self):\n            return CodeInput(lexer=KivyLexer(),\n                             font_name='data/fonts/DroidSansMono.ttf',\n                             font_size=12,\n                             text='''\n#:kivy 1.0\n\n<YourWidget>:\n    canvas:\n        Color:\n            rgb: .5, .5, .5\n        Rectangle:\n            pos: self.pos\n            size: self.size''')\n\n    CodeInputTest().run()\n"
  },
  {
    "path": "tickeys/kivy/uix/colorpicker.py",
    "content": "'''\nColor Picker\n============\n\n.. versionadded:: 1.7.0\n\n.. warning::\n\n    This widget is experimental. Its use and API can change at any time until\n    this warning is removed.\n\n\nThe ColorPicker widget allows a user to select a color from a chromatic\nwheel where pinch and zoom can be used to change the wheel's saturation.\nSliders and TextInputs are also provided for entering the RGBA/HSV/HEX values\ndirectly.\n\nUsage::\n\n    clr_picker = ColorPicker()\n    parent.add_widget(clr_picker)\n\n    # To monitor changes, we can bind to color property changes\n    def on_color(instance, value):\n        print \"RGBA = \", str(value)  #  or instance.color\n        print \"HSV = \", str(instance.hsv)\n        print \"HEX = \", str(instance.hex_color)\n\n    clr_picker.bind(color=on_color)\n\n'''\n\n__all__ = ('ColorPicker', 'ColorWheel')\n\nfrom kivy.uix.relativelayout import RelativeLayout\nfrom kivy.uix.widget import Widget\nfrom kivy.properties import (NumericProperty, BoundedNumericProperty,\n                             ListProperty, ObjectProperty,\n                             ReferenceListProperty, StringProperty,\n                             AliasProperty)\nfrom kivy.clock import Clock\nfrom kivy.graphics import Mesh, InstructionGroup, Color\nfrom kivy.utils import get_color_from_hex, get_hex_from_color\nfrom kivy.logger import Logger\nfrom math import cos, sin, pi, sqrt, atan\nfrom colorsys import rgb_to_hsv, hsv_to_rgb\n\n\ndef distance(pt1, pt2):\n    return sqrt((pt1[0] - pt2[0]) ** 2. + (pt1[1] - pt2[1]) ** 2.)\n\n\ndef polar_to_rect(origin, r, theta):\n    return origin[0] + r * cos(theta), origin[1] + r * sin(theta)\n\n\ndef rect_to_polar(origin, x, y):\n    if x == origin[0]:\n        if y == origin[1]:\n            return (0, 0)\n        elif y > origin[1]:\n            return (y - origin[1], pi / 2.)\n        else:\n            return (origin[1] - y, 3 * pi / 2.)\n    t = atan(float((y - origin[1])) / (x - origin[0]))\n    if x - origin[0] < 0:\n        t += pi\n\n    if t < 0:\n        t += 2 * pi\n\n    return (distance((x, y), origin), t)\n\n\nclass ColorWheel(Widget):\n    '''Chromatic wheel for the ColorPicker.\n\n    .. versionchanged:: 1.7.1\n        `font_size`, `font_name` and `foreground_color` have been removed. The\n        sizing is now the same as others widget, based on 'sp'. Orientation is\n        also automatically determined according to the width/height ratio.\n\n    '''\n\n    r = BoundedNumericProperty(0, min=0, max=1)\n    '''The Red value of the color currently selected.\n\n    :attr:`r` is a :class:`~kivy.properties.BoundedNumericProperty` and\n    can be a value from 0 to 1. It defaults to 0.\n    '''\n\n    g = BoundedNumericProperty(0, min=0, max=1)\n    '''The Green value of the color currently selected.\n\n    :attr:`g` is a :class:`~kivy.properties.BoundedNumericProperty`\n    and can be a value from 0 to 1.\n    '''\n\n    b = BoundedNumericProperty(0, min=0, max=1)\n    '''The Blue value of the color currently selected.\n\n    :attr:`b` is a :class:`~kivy.properties.BoundedNumericProperty` and\n    can be a value from 0 to 1.\n    '''\n\n    a = BoundedNumericProperty(0, min=0, max=1)\n    '''The Alpha value of the color currently selected.\n\n    :attr:`a` is a :class:`~kivy.properties.BoundedNumericProperty` and\n    can be a value from 0 to 1.\n    '''\n\n    color = ReferenceListProperty(r, g, b, a)\n    '''The holds the color currently selected.\n\n    :attr:`color` is a :class:`~kivy.properties.ReferenceListProperty` and\n    contains a list of `r`, `g`, `b`, `a` values.\n    '''\n\n    _origin = ListProperty((100, 100))\n    _radius = NumericProperty(100)\n\n    _piece_divisions = NumericProperty(10)\n    _pieces_of_pie = NumericProperty(16)\n\n    _inertia_slowdown = 1.25\n    _inertia_cutoff = .25\n\n    _num_touches = 0\n    _pinch_flag = False\n\n    _hsv = ListProperty([1, 1, 1, 0])\n\n    def __init__(self, **kwargs):\n        super(ColorWheel, self).__init__(**kwargs)\n\n        pdv = self._piece_divisions\n        self.sv_s = [(float(x) / pdv, 1) for x in range(pdv)] + [\n            (1, float(y) / pdv) for y in reversed(range(pdv))]\n\n    def on__origin(self, instance, value):\n        self.init_wheel(None)\n\n    def on__radius(self, instance, value):\n        self.init_wheel(None)\n\n    def init_wheel(self, dt):\n        # initialize list to hold all meshes\n        self.canvas.clear()\n        self.arcs = []\n        self.sv_idx = 0\n        pdv = self._piece_divisions\n        ppie = self._pieces_of_pie\n\n        for r in range(pdv):\n            for t in range(ppie):\n                self.arcs.append(\n                    _ColorArc(\n                        self._radius * (float(r) / float(pdv)),\n                        self._radius * (float(r + 1) / float(pdv)),\n                        2 * pi * (float(t) / float(ppie)),\n                        2 * pi * (float(t + 1) / float(ppie)),\n                        origin=self._origin,\n                        color=(float(t) / ppie,\n                               self.sv_s[self.sv_idx + r][0],\n                               self.sv_s[self.sv_idx + r][1],\n                               1)))\n\n                self.canvas.add(self.arcs[-1])\n\n    def recolor_wheel(self):\n        ppie = self._pieces_of_pie\n        for idx, segment in enumerate(self.arcs):\n            segment.change_color(\n                sv=self.sv_s[int(self.sv_idx + idx / ppie)])\n\n    def change_alpha(self, val):\n        for idx, segment in enumerate(self.arcs):\n            segment.change_color(a=val)\n\n    def inertial_incr_sv_idx(self, dt):\n        # if its already zoomed all the way out, cancel the inertial zoom\n        if self.sv_idx == len(self.sv_s) - self._piece_divisions:\n            return False\n\n        self.sv_idx += 1\n        self.recolor_wheel()\n        if dt * self._inertia_slowdown > self._inertia_cutoff:\n            return False\n        else:\n            Clock.schedule_once(self.inertial_incr_sv_idx,\n                                dt * self._inertia_slowdown)\n\n    def inertial_decr_sv_idx(self, dt):\n        # if its already zoomed all the way in, cancel the inertial zoom\n        if self.sv_idx == 0:\n            return False\n        self.sv_idx -= 1\n        self.recolor_wheel()\n        if dt * self._inertia_slowdown > self._inertia_cutoff:\n            return False\n        else:\n            Clock.schedule_once(self.inertial_decr_sv_idx,\n                                dt * self._inertia_slowdown)\n\n    def on_touch_down(self, touch):\n        r = self._get_touch_r(touch.pos)\n        if r > self._radius:\n            return False\n\n        # code is still set up to allow pinch to zoom, but this is\n        # disabled for now since it was fiddly with small wheels.\n        # Comment out these lines and  adjust on_touch_move to reenable\n        # this.\n        if self._num_touches != 0:\n            return False\n\n        touch.grab(self)\n        self._num_touches += 1\n        touch.ud['anchor_r'] = r\n        touch.ud['orig_sv_idx'] = self.sv_idx\n        touch.ud['orig_time'] = Clock.get_time()\n\n    def on_touch_move(self, touch):\n        if touch.grab_current is not self:\n            return\n        r = self._get_touch_r(touch.pos)\n        goal_sv_idx = (touch.ud['orig_sv_idx']\n                       - int((r - touch.ud['anchor_r'])\n                             / (float(self._radius) / self._piece_divisions)))\n\n        if (\n            goal_sv_idx != self.sv_idx and\n            goal_sv_idx >= 0 and\n            goal_sv_idx <= len(self.sv_s) - self._piece_divisions\n        ):\n            # this is a pinch to zoom\n            self._pinch_flag = True\n            self.sv_idx = goal_sv_idx\n            self.recolor_wheel()\n\n    def on_touch_up(self, touch):\n        if touch.grab_current is not self:\n            return\n        touch.ungrab(self)\n        self._num_touches -= 1\n        if self._pinch_flag:\n            if self._num_touches == 0:\n                # user was pinching, and now both fingers are up. Return\n                # to normal\n                if self.sv_idx > touch.ud['orig_sv_idx']:\n                    Clock.schedule_once(\n                        self.inertial_incr_sv_idx,\n                        (Clock.get_time() - touch.ud['orig_time'])\n                        / (self.sv_idx - touch.ud['orig_sv_idx']))\n\n                if self.sv_idx < touch.ud['orig_sv_idx']:\n                    Clock.schedule_once(\n                        self.inertial_decr_sv_idx,\n                        (Clock.get_time() - touch.ud['orig_time'])\n                        / (self.sv_idx - touch.ud['orig_sv_idx']))\n\n                self._pinch_flag = False\n                return\n            else:\n                # user was pinching, and at least one finger remains. We\n                # don't want to treat the remaining fingers as touches\n                return\n        else:\n            r, theta = rect_to_polar(self._origin, *touch.pos)\n            # if touch up is outside the wheel, ignore\n            if r >= self._radius:\n                return\n            # compute which ColorArc is being touched (they aren't\n            # widgets so we don't get collide_point) and set\n            # _hsv based on the selected ColorArc\n            piece = int((theta / (2 * pi)) * self._pieces_of_pie)\n            division = int((r / self._radius) * self._piece_divisions)\n            self._hsv = \\\n                self.arcs[self._pieces_of_pie * division + piece].color\n\n    def on__hsv(self, instance, value):\n        c_hsv = Color(*value, mode='hsv')\n        self.r = c_hsv.r\n        self.g = c_hsv.g\n        self.b = c_hsv.b\n        self.a = c_hsv.a\n        self.rgba = (self.r, self.g, self.b, self.a)\n\n    def _get_touch_r(self, pos):\n        return distance(pos, self._origin)\n\n\nclass _ColorArc(InstructionGroup):\n    def __init__(self, r_min, r_max, theta_min, theta_max,\n                 color=(0, 0, 1, 1), origin = (0, 0), **kwargs):\n        super(_ColorArc, self).__init__(**kwargs)\n        self.origin = origin\n        self.r_min = r_min\n        self.r_max = r_max\n        self.theta_min = theta_min\n        self.theta_max = theta_max\n        self.color = color\n        self.color_instr = Color(*color, mode='hsv')\n        self.add(self.color_instr)\n        self.mesh = self.get_mesh()\n        self.add(self.mesh)\n\n    def __str__(self):\n        return \"r_min: %s r_max: %s theta_min: %s theta_max: %s color: %s\" % (\n            self.r_min, self.r_max, self.theta_min, self.theta_max, self.color\n        )\n\n    def get_mesh(self):\n        v = []\n        # first calculate the distance between endpoints of the inner\n        # arc, so we know how many steps to use when calculating\n        # vertices\n        end_point_inner = polar_to_rect(\n            self.origin, self.r_min, self.theta_max)\n\n        d_inner = d_outer = 3.\n        theta_step_inner = (self.theta_max - self.theta_min) / d_inner\n\n        end_point_outer = polar_to_rect(\n            self.origin, self.r_max, self.theta_max)\n\n        if self.r_min == 0:\n            theta_step_outer = (self.theta_max - self.theta_min) / d_outer\n            for x in range(int(d_outer)):\n                v += (polar_to_rect(self.origin, 0, 0) * 2)\n                v += (polar_to_rect(\n                    self.origin, self.r_max,\n                    self.theta_min + x * theta_step_outer) * 2)\n        else:\n            for x in range(int(d_inner + 2)):\n                v += (polar_to_rect(\n                    self.origin, self.r_min - 1,\n                    self.theta_min + x * theta_step_inner) * 2)\n                v += (polar_to_rect(\n                    self.origin, self.r_max + 1,\n                    self.theta_min + x * theta_step_inner) * 2)\n\n        v += (end_point_inner * 2)\n        v += (end_point_outer * 2)\n\n        return Mesh(vertices=v, indices=range(int(len(v) / 4)),\n                    mode='triangle_strip')\n\n    def change_color(self, color=None, color_delta=None, sv=None, a=None):\n        self.remove(self.color_instr)\n        if color is not None:\n            self.color = color\n        elif color_delta is not None:\n            self.color = [self.color[i] + color_delta[i] for i in range(4)]\n        elif sv is not None:\n            self.color = (self.color[0], sv[0], sv[1], self.color[3])\n        elif a is not None:\n            self.color = (self.color[0], self.color[1], self.color[2], a)\n        self.color_instr = Color(*self.color, mode='hsv')\n        self.insert(0, self.color_instr)\n\n\nclass ColorPicker(RelativeLayout):\n    '''\n    See module documentation.\n    '''\n\n    font_name = StringProperty('data/fonts/DroidSansMono.ttf')\n    '''Specifies the font used on the ColorPicker.\n\n    :attr:`font_name` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'data/fonts/DroidSansMono.ttf'.\n    '''\n\n    color = ListProperty((1, 1, 1, 1))\n    '''The :attr:`color` holds the color currently selected in rgba format.\n\n    :attr:`color` is a :class:`~kivy.properties.ListProperty` and defaults to\n    (1, 1, 1, 1).\n    '''\n\n    hsv = ListProperty((1, 1, 1))\n    '''The :attr:`hsv` holds the color currently selected in hsv format.\n\n    :attr:`hsv` is a :class:`~kivy.properties.ListProperty` and defaults to\n    (1, 1, 1).\n    '''\n    def _get_hex(self):\n        return get_hex_from_color(self.color)\n\n    def _set_hex(self, value):\n        self.color = get_color_from_hex(value)[:4]\n\n    hex_color = AliasProperty(_get_hex, _set_hex, bind=('color', ))\n    '''The :attr:`hex_color` holds the currently selected color in hex.\n\n    :attr:`hex_color` is an :class:`~kivy.properties.AliasProperty` and\n    defaults to `#ffffffff`.\n    '''\n\n    wheel = ObjectProperty(None)\n    '''The :attr:`wheel` holds the color wheel.\n\n    :attr:`wheel` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    # now used only internally.\n    foreground_color = ListProperty((1, 1, 1, 1))\n\n    def on_color(self, instance, value):\n        if not self._updating_clr:\n            self._updating_clr = True\n            self.hsv = rgb_to_hsv(*value[:3])\n            self._updating_clr = False\n\n    def on_hsv(self, instance, value):\n        if not self._updating_clr:\n            self._updating_clr = True\n            self.color[:3] = hsv_to_rgb(*value)\n            self._updating_clr = False\n\n    def _trigger_update_clr(self, mode, clr_idx, text):\n        self._upd_clr_list = mode, clr_idx, text\n        Clock.unschedule(self._update_clr)\n        Clock.schedule_once(self._update_clr)\n\n    def _update_clr(self, dt):\n        mode, clr_idx, text = self._upd_clr_list\n        try:\n            text = min(255, max(0, float(text)))\n            if mode == 'rgb':\n                self.color[clr_idx] = float(text) / 255.\n            else:\n                self.hsv[clr_idx] = float(text) / 255.\n        except ValueError:\n            Logger.warning('ColorPicker: invalid value : {}'.format(text))\n\n    def _update_hex(self, dt):\n        if len(self._upd_hex_list) != 9:\n            return\n        self.hex_color = self._upd_hex_list\n\n    def _trigger_update_hex(self, text):\n        self._upd_hex_list = text\n        Clock.unschedule(self._update_hex)\n        Clock.schedule_once(self._update_hex)\n\n    def __init__(self, **kwargs):\n        self._updating_clr = False\n        super(ColorPicker, self).__init__(**kwargs)\n\n\nif __name__ in ('__android__', '__main__'):\n    from kivy.app import App\n\n    class ColorPickerApp(App):\n        def build(self):\n            cp = ColorPicker(pos_hint={'center_x': .5, 'center_y': .5},\n                             size_hint=(1, 1))\n            return cp\n    ColorPickerApp().run()\n"
  },
  {
    "path": "tickeys/kivy/uix/dropdown.py",
    "content": "'''\nDrop-Down List\n==============\n\n.. versionadded:: 1.4.0\n\nA versatile drop-down list that can be used with custom widgets. It allows you\nto display a list of widgets under a displayed widget. Unlike other toolkits,\nthe list of widgets can contain any type of widget: simple buttons,\nimages etc.\n\nThe positioning of the drop-down list is fully automatic: we will always try to\nplace the dropdown list in a way that the user can select an item in the list.\n\nBasic example\n-------------\n\nA button with a dropdown list of 10 possible values. All the buttons within the\ndropdown list will trigger the dropdown :meth:`DropDown.select` method. After\nbeing called, the main button text will display the selection of the\ndropdown. ::\n\n    from kivy.uix.dropdown import DropDown\n    from kivy.uix.button import Button\n    from kivy.base import runTouchApp\n\n    # create a dropdown with 10 buttons\n    dropdown = DropDown()\n    for index in range(10):\n        # when adding widgets, we need to specify the height manually (disabling\n        # the size_hint_y) so the dropdown can calculate the area it needs.\n        btn = Button(text='Value %d' % index, size_hint_y=None, height=44)\n\n        # for each button, attach a callback that will call the select() method\n        # on the dropdown. We'll pass the text of the button as the data of the\n        # selection.\n        btn.bind(on_release=lambda btn: dropdown.select(btn.text))\n\n        # then add the button inside the dropdown\n        dropdown.add_widget(btn)\n\n    # create a big main button\n    mainbutton = Button(text='Hello', size_hint=(None, None))\n\n    # show the dropdown menu when the main button is released\n    # note: all the bind() calls pass the instance of the caller (here, the\n    # mainbutton instance) as the first argument of the callback (here,\n    # dropdown.open.).\n    mainbutton.bind(on_release=dropdown.open)\n\n    # one last thing, listen for the selection in the dropdown list and\n    # assign the data to the button text.\n    dropdown.bind(on_select=lambda instance, x: setattr(mainbutton, 'text', x))\n\n    runTouchApp(mainbutton)\n\nExtending dropdown in Kv\n------------------------\n\nYou could create a dropdown directly from your kv::\n\n    #:kivy 1.4.0\n    <CustomDropDown>:\n        Button:\n            text: 'My first Item'\n            size_hint_y: None\n            height: 44\n            on_release: root.select('item1')\n        Label:\n            text: 'Unselectable item'\n            size_hint_y: None\n            height: 44\n        Button:\n            text: 'My second Item'\n            size_hint_y: None\n            height: 44\n            on_release: root.select('item2')\n\nAnd then, create the associated python class and use it::\n\n    class CustomDropDown(DropDown):\n        pass\n\n    dropdown = CustomDropDown()\n    mainbutton = Button(text='Hello', size_hint=(None, None))\n    mainbutton.bind(on_release=dropdown.open)\n    dropdown.bind(on_select=lambda instance, x: setattr(mainbutton, 'text', x))\n'''\n\n__all__ = ('DropDown', )\n\nfrom kivy.uix.scrollview import ScrollView\nfrom kivy.properties import ObjectProperty, NumericProperty, BooleanProperty\nfrom kivy.core.window import Window\nfrom kivy.lang import Builder\n\n_grid_kv = '''\nGridLayout:\n    size_hint_y: None\n    height: self.minimum_size[1]\n    cols: 1\n'''\n\n\nclass DropDownException(Exception):\n    '''DropDownException class.\n    '''\n    pass\n\n\nclass DropDown(ScrollView):\n    '''DropDown class. See module documentation for more information.\n\n    :Events:\n        `on_select`: data\n            Fired when a selection is done. The data of the selection is passed\n            in as the first argument and is what you pass in the :meth:`select`\n            method as the first argument.\n        `on_dismiss`:\n            .. versionadded:: 1.8.0\n\n            Fired when the DropDown is dismissed, either on selection or on\n            touching outside the widget.\n    '''\n\n    auto_width = BooleanProperty(True)\n    '''By default, the width of the dropdown will be the same as the width of\n    the attached widget. Set to False if you want to provide your own width.\n    '''\n\n    max_height = NumericProperty(None, allownone=True)\n    '''Indicate the maximum height that the dropdown can take. If None, it will\n    take the maximum height available until the top or bottom of the screen\n    is reached.\n\n    :attr:`max_height` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to None.\n    '''\n\n    dismiss_on_select = BooleanProperty(True)\n    '''By default, the dropdown will be automatically dismissed when a\n    selection has been done. Set to False to prevent the dismiss.\n\n    :attr:`dismiss_on_select` is a :class:`~kivy.properties.BooleanProperty`\n    and defaults to True.\n    '''\n\n    auto_dismiss = BooleanProperty(True)\n    '''By default, the dropdown will be automatically dismissed when a\n    touch happens outside of it, this option allow to disable this\n    feature\n\n    :attr:`auto_dismiss` is a :class:`~kivy.properties.BooleanProperty`\n    and defaults to True.\n\n    .. versionadded:: 1.8.0\n    '''\n\n    attach_to = ObjectProperty(allownone=True)\n    '''(internal) Property that will be set to the widget to which the\n    drop down list is attached.\n\n    The :meth:`open` method will automatically set this property whilst\n    :meth:`dismiss` will set it back to None.\n    '''\n\n    container = ObjectProperty()\n    '''(internal) Property that will be set to the container of the dropdown\n    list. It is a :class:`~kivy.uix.gridlayout.GridLayout` by default.\n    '''\n\n    __events__ = ('on_select', 'on_dismiss')\n\n    def __init__(self, **kwargs):\n        self._win = None\n        if 'container' not in kwargs:\n            c = self.container = Builder.load_string(_grid_kv)\n        else:\n            c = None\n        kwargs.setdefault('do_scroll_x', False)\n        if 'size_hint' not in kwargs:\n            kwargs.setdefault('size_hint_x', None)\n            kwargs.setdefault('size_hint_y', None)\n        super(DropDown, self).__init__(**kwargs)\n        if c is not None:\n            super(DropDown, self).add_widget(c)\n            self.on_container(self, c)\n        Window.bind(on_key_down=self.on_key_down)\n        self.bind(size=self._reposition)\n\n    def on_key_down(self, instance, key, scancode, codepoint, modifiers):\n        if key == 27 and self.get_parent_window():\n            self.dismiss()\n            return True\n\n    def on_container(self, instance, value):\n        if value is not None:\n            self.container.bind(minimum_size=self._container_minimum_size)\n\n    def open(self, widget):\n        '''Open the dropdown list and attach it to a specific widget.\n        Depending on the position of the widget within the window and\n        the height of the dropdown, the dropdown might be above or below\n        that widget.\n        '''\n        # ensure we are not already attached\n        if self.attach_to is not None:\n            self.dismiss()\n\n        # we will attach ourself to the main window, so ensure the\n        # widget we are looking for have a window\n        self._win = widget.get_parent_window()\n        if self._win is None:\n            raise DropDownException(\n                'Cannot open a dropdown list on a hidden widget')\n\n        self.attach_to = widget\n        widget.bind(pos=self._reposition, size=self._reposition)\n        self._reposition()\n\n        # attach ourself to the main window\n        self._win.add_widget(self)\n\n    def dismiss(self, *largs):\n        '''Remove the dropdown widget from the window and detach it from\n        the attached widget.\n        '''\n        if self.parent:\n            self.parent.remove_widget(self)\n        if self.attach_to:\n            self.attach_to.unbind(pos=self._reposition, size=self._reposition)\n            self.attach_to = None\n        self.dispatch('on_dismiss')\n\n    def on_dismiss(self):\n        pass\n\n    def select(self, data):\n        '''Call this method to trigger the `on_select` event with the `data`\n        selection. The `data` can be anything you want.\n        '''\n        self.dispatch('on_select', data)\n        if self.dismiss_on_select:\n            self.dismiss()\n\n    def on_select(self, data):\n        pass\n\n    def _container_minimum_size(self, instance, size):\n        if self.max_height:\n            self.height = min(size[1], self.max_height)\n            self.do_scroll_y = size[1] > self.max_height\n        else:\n            self.height = size[1]\n            self.do_scroll_y = True\n\n    def add_widget(self, *largs):\n        if self.container:\n            return self.container.add_widget(*largs)\n        return super(DropDown, self).add_widget(*largs)\n\n    def remove_widget(self, *largs):\n        if self.container:\n            return self.container.remove_widget(*largs)\n        return super(DropDown, self).remove_widget(*largs)\n\n    def clear_widgets(self):\n        if self.container:\n            return self.container.clear_widgets()\n        return super(DropDown, self).clear_widgets()\n\n    def on_touch_down(self, touch):\n        if super(DropDown, self).on_touch_down(touch):\n            return True\n        if self.collide_point(*touch.pos):\n            return True\n        if self.attach_to and self.attach_to.collide_point(*touch.pos):\n            return True\n        if self.auto_dismiss:\n            self.dismiss()\n\n    def on_touch_up(self, touch):\n        if super(DropDown, self).on_touch_up(touch):\n            return True\n        if 'button' in touch.profile and touch.button.startswith('scroll'):\n            return\n        if self.auto_dismiss:\n            self.dismiss()\n\n    def _reposition(self, *largs):\n        # calculate the coordinate of the attached widget in the window\n        # coordinate system\n        win = self._win\n        widget = self.attach_to\n        if not widget or not win:\n            return\n        wx, wy = widget.to_window(*widget.pos)\n        wright, wtop = widget.to_window(widget.right, widget.top)\n\n        # set width and x\n        if self.auto_width:\n            self.width = wright - wx\n\n        # ensure the dropdown list doesn't get out on the X axis, with a\n        # preference to 0 in case the list is too wide.\n        x = wx\n        if x + self.width > win.width:\n            x = win.width - self.width\n        if x < 0:\n            x = 0\n        self.x = x\n\n        # determine if we display the dropdown upper or lower to the widget\n        h_bottom = wy - self.height\n        h_top = win.height - (wtop + self.height)\n        if h_bottom > 0:\n            self.top = wy\n        elif h_top > 0:\n            self.y = wtop\n        else:\n            # none of both top/bottom have enough place to display the\n            # widget at the current size. Take the best side, and fit to\n            # it.\n            height = max(h_bottom, h_top)\n            if height == h_bottom:\n                self.top = wy\n                self.height = wy\n            else:\n                self.y = wtop\n                self.height = win.height - wtop\n\n\nif __name__ == '__main__':\n    from kivy.uix.button import Button\n    from kivy.base import runTouchApp\n\n    def show_dropdown(button, *largs):\n        dp = DropDown()\n        dp.bind(on_select=lambda instance, x: setattr(button, 'text', x))\n        for i in range(10):\n            item = Button(text='hello %d' % i, size_hint_y=None, height=44)\n            item.bind(on_release=lambda btn: dp.select(btn.text))\n            dp.add_widget(item)\n        dp.open(button)\n\n    def touch_move(instance, touch):\n        instance.center = touch.pos\n\n    btn = Button(text='SHOW', size_hint=(None, None), pos=(300, 200))\n    btn.bind(on_release=show_dropdown, on_touch_move=touch_move)\n\n    runTouchApp(btn)\n"
  },
  {
    "path": "tickeys/kivy/uix/effectwidget.py",
    "content": "'''\nEffectWidget\n============\n\n.. versionadded:: 1.9.0\n\n    This code is still experimental, and its API is subject to change in a\n    future version.\n\nThe :class:`EffectWidget` is able to apply a variety of fancy\ngraphical effects to\nits children. It works by rendering to a series of\n:class:`~kivy.graphics.Fbo` instances with custom opengl fragment shaders.\nAs such, effects can freely do almost anything, from inverting the\ncolors of the widget, to antialiasing, to emulating the appearance of a\ncrt monitor!\n\nThe basic usage is as follows::\n\n    w = EffectWidget()\n    w.add_widget(Button(text='Hello!')\n    w.effects = [InvertEffect(), HorizontalBlurEffect(size=2.0)]\n\nThe effects can be a list of effects of any length, and they will be\napplied sequentially.\n\nThe module comes with a range of prebuilt effects, but the interface\nis designed to make it easy to create your own. Instead of writing a\nfull glsl shader, you provide a single function that takes\nsome inputs based on the screen (current pixel color, current widget\ntexture etc.). See the sections below for more information.\n\n.. note:: It is not efficient to resize an :class:`EffectWidget`, as\n          each :class:`~kivy.graphics.Fbo` is recreated every time.\n          If you need to resize frequently, consider doing things a\n          different way.\n\n.. note:: Although some effects have adjustable parameters, it is\n          *not* efficient to animate these, as the entire\n          shader is reconstructed every time. You should use glsl\n          uniform variables instead. The :class:`AdvancedEffectBase`\n          may make this easier.\n\n.. note:: The :class:`EffectWidget` *cannot* draw outside its own\n          widget area (pos -> pos + size), any child widgets\n          overlapping the boundary will be cut off at this point.\n\nProvided Effects\n----------------\n\nThe module comes with several pre-written effects. Some have\nadjustable properties (e.g. blur radius), see the individual\neffect documentation for more details.\n\n- :class:`MonochromeEffect` - makes the widget grayscale.\n- :class:`InvertEffect` - inverts the widget colors.\n- :class:`ChannelMixEffect` - swaps around color channels.\n- :class:`ScanlinesEffect` - displays flickering scanlines.\n- :class:`PixelateEffect` - pixelates the image.\n- :class:`HorizontalBlurEffect` - Gaussuan blurs horizontally.\n- :class:`VerticalBlurEffect` - Gaussuan blurs vertically.\n- :class:`FXAAEffect` - applies a very basic AA.\n\nCreating Effects\n----------------\n\nEffects are designed to make it easy to create and use your own\ntransformations. You do this by creating and using an instance of\n:class:`EffectBase` with your own custom :attr:`EffectBase.glsl`\nproperty.\n\nThe glsl property is a string representing part of a glsl fragment\nshader. You can include as many functions as you like (the string\nis simply spliced into the whole shader), but it\nmust implement a function :code:`effect` as below::\n\n    vec4 effect(vec4 color, sampler2D texture, vec2 tex_coords, vec2 coords)\n    {\n        // ... your code here\n        return something;  // must be a vec4 representing the new color\n    }\n\nThe full shader will calculate the normal pixel color at each point,\nthen call your :code:`effect` function to transform it. The\nparameters are:\n\n- **color**: The normal color of the current pixel (i.e. texture\n  sampled at tex_coords).\n- **texture**: The texture containing the widget's normal background.\n- **tex_coords**: The normal texture_coords used to access texture.\n- **coords**: The pixel indices of the current pixel.\n\nThe shader code also has access to two useful uniform variables,\n:code:`time` containing the time (in seconds) since the program start,\nand :code:`resolution` containing the shape (x pixels, y pixels) of\nthe widget.\n\nFor instance, the following simple string (taken from the `InvertEffect`)\nwould invert the input color but set alpha to 1.0::\n\n    vec4 effect(vec4 color, sampler2D texture, vec2 tex_coords, vec2 coords)\n    {\n        return vec4(1.0 - color.xyz, 1.0);\n    }\n\nYou can also set the glsl by automatically loading the string from a\nfile, simply set the :attr:`EffectBase.source` property of an effect.\n\n'''\n\nfrom kivy.clock import Clock\nfrom kivy.uix.relativelayout import RelativeLayout\nfrom kivy.properties import (StringProperty, ObjectProperty, ListProperty,\n                             NumericProperty, DictProperty)\nfrom kivy.graphics import (RenderContext, Fbo, Color, Rectangle,\n                           Translate, PushMatrix, PopMatrix, ClearColor,\n                           ClearBuffers)\nfrom kivy.event import EventDispatcher\nfrom kivy.base import EventLoop\nfrom kivy.resources import resource_find\n\n__all__ = ('EffectWidget', 'EffectBase', 'AdvancedEffectBase',\n           'MonochromeEffect', 'InvertEffect', 'ChannelMixEffect',\n           'ScanlinesEffect', 'PixelateEffect',\n           'HorizontalBlurEffect', 'VerticalBlurEffect',\n           'FXAAEffect')\n\nshader_header = '''\n#ifdef GL_ES\nprecision highp float;\n#endif\n\n/* Outputs from the vertex shader */\nvarying vec4 frag_color;\nvarying vec2 tex_coord0;\n\n/* uniform texture samplers */\nuniform sampler2D texture0;\n'''\n\nshader_uniforms = '''\nuniform vec2 resolution;\nuniform float time;\n'''\n\nshader_footer_trivial = '''\nvoid main (void){\n     gl_FragColor = frag_color * texture2D(texture0, tex_coord0);\n}\n'''\n\nshader_footer_effect = '''\nvoid main (void){\n    vec4 normal_color = frag_color * texture2D(texture0, tex_coord0);\n    vec4 effect_color = effect(normal_color, texture0, tex_coord0,\n                               gl_FragCoord.xy);\n    gl_FragColor = effect_color;\n}\n'''\n\n\neffect_trivial = '''\nvec4 effect(vec4 color, sampler2D texture, vec2 tex_coords, vec2 coords)\n{\n    return color;\n}\n'''\n\neffect_monochrome = '''\nvec4 effect(vec4 color, sampler2D texture, vec2 tex_coords, vec2 coords)\n{\n    float mag = 1.0/3.0 * (color.x + color.y + color.z);\n    return vec4(mag, mag, mag, color.w);\n}\n'''\n\neffect_invert = '''\nvec4 effect(vec4 color, sampler2D texture, vec2 tex_coords, vec2 coords)\n{\n    return vec4(1.0 - color.xyz, color.w);\n}\n'''\n\neffect_mix = '''\nvec4 effect(vec4 color, sampler2D texture, vec2 tex_coords, vec2 coords)\n{{\n    return vec4(color.{}, color.{}, color.{}, color.w);\n}}\n'''\n\neffect_blur_h = '''\nvec4 effect(vec4 color, sampler2D texture, vec2 tex_coords, vec2 coords)\n{{\n    float dt = ({} / 4.0) * 1.0 / resolution.x;\n    vec4 sum = vec4(0.0);\n    sum += texture2D(texture, vec2(tex_coords.x - 4.0*dt, tex_coords.y))\n                     * 0.05;\n    sum += texture2D(texture, vec2(tex_coords.x - 3.0*dt, tex_coords.y))\n                     * 0.09;\n    sum += texture2D(texture, vec2(tex_coords.x - 2.0*dt, tex_coords.y))\n                     * 0.12;\n    sum += texture2D(texture, vec2(tex_coords.x - dt, tex_coords.y))\n                     * 0.15;\n    sum += texture2D(texture, vec2(tex_coords.x, tex_coords.y))\n                     * 0.16;\n    sum += texture2D(texture, vec2(tex_coords.x + dt, tex_coords.y))\n                     * 0.15;\n    sum += texture2D(texture, vec2(tex_coords.x + 2.0*dt, tex_coords.y))\n                     * 0.12;\n    sum += texture2D(texture, vec2(tex_coords.x + 3.0*dt, tex_coords.y))\n                     * 0.09;\n    sum += texture2D(texture, vec2(tex_coords.x + 4.0*dt, tex_coords.y))\n                     * 0.05;\n    return vec4(sum.xyz, color.w);\n}}\n'''\n\neffect_blur_v = '''\nvec4 effect(vec4 color, sampler2D texture, vec2 tex_coords, vec2 coords)\n{{\n    float dt = ({} / 4.0)\n                     * 1.0 / resolution.x;\n    vec4 sum = vec4(0.0);\n    sum += texture2D(texture, vec2(tex_coords.x, tex_coords.y - 4.0*dt))\n                     * 0.05;\n    sum += texture2D(texture, vec2(tex_coords.x, tex_coords.y - 3.0*dt))\n                     * 0.09;\n    sum += texture2D(texture, vec2(tex_coords.x, tex_coords.y - 2.0*dt))\n                     * 0.12;\n    sum += texture2D(texture, vec2(tex_coords.x, tex_coords.y - dt))\n                     * 0.15;\n    sum += texture2D(texture, vec2(tex_coords.x, tex_coords.y))\n                     * 0.16;\n    sum += texture2D(texture, vec2(tex_coords.x, tex_coords.y + dt))\n                     * 0.15;\n    sum += texture2D(texture, vec2(tex_coords.x, tex_coords.y + 2.0*dt))\n                     * 0.12;\n    sum += texture2D(texture, vec2(tex_coords.x, tex_coords.y + 3.0*dt))\n                     * 0.09;\n    sum += texture2D(texture, vec2(tex_coords.x, tex_coords.y + 4.0*dt))\n                     * 0.05;\n    return vec4(sum.xyz, color.w);\n}}\n'''\n\neffect_postprocessing = '''\nvec4 effect(vec4 color, sampler2D texture, vec2 tex_coords, vec2 coords)\n{\n    vec2 q = tex_coords * vec2(1, -1);\n    vec2 uv = 0.5 + (q-0.5);//*(0.9);// + 0.1*sin(0.2*time));\n\n    vec3 oricol = texture2D(texture,vec2(q.x,1.0-q.y)).xyz;\n    vec3 col;\n\n    col.r = texture2D(texture,vec2(uv.x+0.003,-uv.y)).x;\n    col.g = texture2D(texture,vec2(uv.x+0.000,-uv.y)).y;\n    col.b = texture2D(texture,vec2(uv.x-0.003,-uv.y)).z;\n\n    col = clamp(col*0.5+0.5*col*col*1.2,0.0,1.0);\n\n    //col *= 0.5 + 0.5*16.0*uv.x*uv.y*(1.0-uv.x)*(1.0-uv.y);\n\n    col *= vec3(0.8,1.0,0.7);\n\n    col *= 0.9+0.1*sin(10.0*time+uv.y*1000.0);\n\n    col *= 0.97+0.03*sin(110.0*time);\n\n    float comp = smoothstep( 0.2, 0.7, sin(time) );\n    //col = mix( col, oricol, clamp(-2.0+2.0*q.x+3.0*comp,0.0,1.0) );\n\n    return vec4(col, color.w);\n}\n'''\n\neffect_pixelate = '''\nvec4 effect(vec4 vcolor, sampler2D texture, vec2 texcoord, vec2 pixel_coords)\n{{\n    vec2 pixelSize = {} / resolution;\n\n    vec2 xy = floor(texcoord/pixelSize)*pixelSize + pixelSize/2.0;\n\n    return texture2D(texture, xy);\n}}\n'''\n\neffect_fxaa = '''\nvec4 effect( vec4 color, sampler2D buf0, vec2 texCoords, vec2 coords)\n{\n\n    vec2 frameBufSize = resolution;\n\n    float FXAA_SPAN_MAX = 8.0;\n    float FXAA_REDUCE_MUL = 1.0/8.0;\n    float FXAA_REDUCE_MIN = 1.0/128.0;\n\n    vec3 rgbNW=texture2D(buf0,texCoords+(vec2(-1.0,-1.0)/frameBufSize)).xyz;\n    vec3 rgbNE=texture2D(buf0,texCoords+(vec2(1.0,-1.0)/frameBufSize)).xyz;\n    vec3 rgbSW=texture2D(buf0,texCoords+(vec2(-1.0,1.0)/frameBufSize)).xyz;\n    vec3 rgbSE=texture2D(buf0,texCoords+(vec2(1.0,1.0)/frameBufSize)).xyz;\n    vec3 rgbM=texture2D(buf0,texCoords).xyz;\n\n    vec3 luma=vec3(0.299, 0.587, 0.114);\n    float lumaNW = dot(rgbNW, luma);\n    float lumaNE = dot(rgbNE, luma);\n    float lumaSW = dot(rgbSW, luma);\n    float lumaSE = dot(rgbSE, luma);\n    float lumaM  = dot(rgbM, luma);\n\n    float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));\n    float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));\n\n    vec2 dir;\n    dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));\n    dir.y =  ((lumaNW + lumaSW) - (lumaNE + lumaSE));\n\n    float dirReduce = max(\n        (lumaNW + lumaNE + lumaSW + lumaSE) * (0.25 * FXAA_REDUCE_MUL),\n        FXAA_REDUCE_MIN);\n\n    float rcpDirMin = 1.0/(min(abs(dir.x), abs(dir.y)) + dirReduce);\n\n    dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX),\n          max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),\n          dir * rcpDirMin)) / frameBufSize;\n\n    vec3 rgbA = (1.0/2.0) * (\n        texture2D(buf0, texCoords.xy + dir * (1.0/3.0 - 0.5)).xyz +\n        texture2D(buf0, texCoords.xy + dir * (2.0/3.0 - 0.5)).xyz);\n    vec3 rgbB = rgbA * (1.0/2.0) + (1.0/4.0) * (\n        texture2D(buf0, texCoords.xy + dir * (0.0/3.0 - 0.5)).xyz +\n        texture2D(buf0, texCoords.xy + dir * (3.0/3.0 - 0.5)).xyz);\n    float lumaB = dot(rgbB, luma);\n\n    vec4 return_color;\n    if((lumaB < lumaMin) || (lumaB > lumaMax)){\n        return_color = vec4(rgbA, color.w);\n    }else{\n        return_color = vec4(rgbB, color.w);\n    }\n\n    return return_color;\n}\n'''\n\n\nclass EffectBase(EventDispatcher):\n    '''The base class for GLSL effects. It simply returns its input.\n\n    See module documentation for more details.\n\n    '''\n\n    glsl = StringProperty(effect_trivial)\n    '''The glsl string defining your effect function, see module\n    documentation for more details.\n\n    :attr:`glsl` is a :class:`~kivy.properties.StringProperty` and\n    defaults to\n    a trivial effect that returns its input.\n    '''\n\n    source = StringProperty('')\n    '''The (optional) filename from which to load the :attr:`glsl`\n    string.\n\n    :attr:`source` is a :class:`~kivy.properties.StringProperty` and\n    defaults to ''.\n    '''\n\n    fbo = ObjectProperty(None, allownone=True)\n    '''The fbo currently using this effect. The :class:`EffectBase`\n    automatically handles this.\n\n    :attr:`fbo` is a :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    def __init__(self, *args, **kwargs):\n        super(EffectBase, self).__init__(*args, **kwargs)\n        self.bind(fbo=self.set_fbo_shader)\n        self.bind(glsl=self.set_fbo_shader)\n        self.bind(source=self._load_from_source)\n\n    def set_fbo_shader(self, *args):\n        '''Sets the :class:`~kivy.graphics.Fbo`'s shader by splicing\n        the :attr:`glsl` string into a full fragment shader.\n\n        The full shader is made up of :code:`shader_header +\n        shader_uniforms + self.glsl + shader_footer_effect`.\n        '''\n        if self.fbo is None:\n            return\n        self.fbo.set_fs(shader_header + shader_uniforms + self.glsl +\n                        shader_footer_effect)\n\n    def _load_from_source(self, *args):\n        '''(internal) Loads the glsl string from a source file.'''\n        source = self.source\n        if not source:\n            return\n        filename = resource_find(source)\n        if filename is None:\n            return Logger.error('Error reading file {filename}'.\n                                format(filename=source))\n        with open(filename) as fileh:\n            self.glsl = fileh.read()\n\n\nclass AdvancedEffectBase(EffectBase):\n    '''An :class:`EffectBase` with additional behavior to easily\n    set and update uniform variables in your shader.\n\n    This class is provided for convenience if implementing your own\n    effects, it is not used by any of those provided with Kivy.\n\n    In addition to your base glsl string that must be provided as\n    normal, the :class:`AdvancedEffectBase` has an extra property\n    :attr:`uniforms`, a dictionary of name-value pairs. Whenever\n    a value is changed, the new values for the uniform variable with\n    the given name are uploaded to the shader.\n\n    You must still manually declare your uniform variables at the top\n    of your glsl string.\n    '''\n\n    uniforms = DictProperty({})\n    '''A dictionary of uniform variable names and their values. These\n    are automatically uploaded to the :attr:`fbo` shader if appropriate.\n\n    uniforms is a :class:`~kivy.properties.DictProperty` and\n    defaults to {}.\n    '''\n\n    def __init__(self, *args, **kwargs):\n        super(AdvancedEffectBase, self).__init__(*args, **kwargs)\n        self.bind(uniforms=self._update_uniforms)\n\n    def _update_uniforms(self, *args):\n        if self.fbo is None:\n            return\n        for key, value in self.uniforms.items():\n            self.fbo[key] = value\n\n    def set_fbo_shader(self, *args):\n        super(AdvancedEffectBase, self).set_fbo_shader(*args)\n        self._update_uniforms()\n\n\nclass MonochromeEffect(EffectBase):\n    '''Returns its input colors in monochrome.'''\n    def __init__(self, *args, **kwargs):\n        super(MonochromeEffect, self).__init__(*args, **kwargs)\n        self.glsl = effect_monochrome\n\n\nclass InvertEffect(EffectBase):\n    '''Inverts the colors in the input.'''\n    def __init__(self, *args, **kwargs):\n        super(InvertEffect, self).__init__(*args, **kwargs)\n        self.glsl = effect_invert\n\n\nclass ScanlinesEffect(EffectBase):\n    '''Adds scanlines to the input.'''\n    def __init__(self, *args, **kwargs):\n        super(ScanlinesEffect, self).__init__(*args, **kwargs)\n        self.glsl = effect_postprocessing\n\n\nclass ChannelMixEffect(EffectBase):\n    '''Mixes the color channels of the input according to the order\n    property. Channels may be arbitrarily rearranged or repeated.'''\n\n    order = ListProperty([1, 2, 0])\n    '''The new sorted order of the rgb channels.\n\n    order is a :class:`~kivy.properties.ListProperty` and defaults to\n    [1, 2, 0], corresponding to (g, b, r).\n    '''\n\n    def __init__(self, *args, **kwargs):\n        super(ChannelMixEffect, self).__init__(*args, **kwargs)\n        self.do_glsl()\n\n    def on_order(self, *args):\n        self.do_glsl()\n\n    def do_glsl(self):\n        letters = [{0: 'x', 1: 'y', 2: 'z'}[i] for i in self.order]\n        self.glsl = effect_mix.format(*letters)\n\n\nclass PixelateEffect(EffectBase):\n    '''Pixelates the input according to its\n    :attr:`~PixelateEffect.pixel_size`'''\n\n    pixel_size = NumericProperty(10)\n    '''\n    Sets the size of a new 'pixel' in the effect, in terms of number of\n    'real' pixels.\n\n    pixel_size is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 10.\n    '''\n\n    def __init__(self, *args, **kwargs):\n        super(PixelateEffect, self).__init__(*args, **kwargs)\n        self.do_glsl()\n\n    def on_pixel_size(self, *args):\n        self.do_glsl()\n\n    def do_glsl(self):\n        self.glsl = effect_pixelate.format(float(self.pixel_size))\n\n\nclass HorizontalBlurEffect(EffectBase):\n    '''Blurs the input horizontally, with the width given by\n    :attr:`~HorizontalBlurEffect.size`.'''\n\n    size = NumericProperty(4.0)\n    '''The blur width in pixels.\n\n    size is a :class:`~kivy.properties.NumericProperty` and defaults to\n    4.0.\n    '''\n\n    def __init__(self, *args, **kwargs):\n        super(HorizontalBlurEffect, self).__init__(*args, **kwargs)\n        self.do_glsl()\n\n    def on_size(self, *args):\n        self.do_glsl()\n\n    def do_glsl(self):\n        self.glsl = effect_blur_h.format(float(self.size))\n\n\nclass VerticalBlurEffect(EffectBase):\n    '''Blurs the input vertically, with the width given by\n    :attr:`~VerticalBlurEffect.size`.'''\n\n    size = NumericProperty(4.0)\n    '''The blur width in pixels.\n\n    size is a :class:`~kivy.properties.NumericProperty` and defaults to\n    4.0.\n    '''\n\n    def __init__(self, *args, **kwargs):\n        super(VerticalBlurEffect, self).__init__(*args, **kwargs)\n        self.do_glsl()\n\n    def on_size(self, *args):\n        self.do_glsl()\n\n    def do_glsl(self):\n        self.glsl = effect_blur_v.format(float(self.size))\n\n\nclass FXAAEffect(EffectBase):\n    '''Applies very simple antialiasing via fxaa.'''\n    def __init__(self, *args, **kwargs):\n        super(FXAAEffect, self).__init__(*args, **kwargs)\n        self.glsl = effect_fxaa\n\n\nclass EffectFbo(Fbo):\n    '''An :class:`~kivy.graphics.Fbo` with extra facility to\n    attempt setting a new shader, see :meth:`set_fs`.\n    '''\n    def __init__(self, *args, **kwargs):\n        super(EffectFbo, self).__init__(*args, **kwargs)\n        self.texture_rectangle = None\n\n    def set_fs(self, value):\n        '''Attempt to set the fragment shader to the given value.\n        If setting the shader fails, resets the old one and raises an\n        exception.\n        '''\n        shader = self.shader\n        old_value = shader.fs\n        shader.fs = value\n        if not shader.success:\n            shader.fs = old_value\n            raise Exception('Setting new shader failed.')\n\n\nclass EffectWidget(RelativeLayout):\n    '''\n    Widget with the ability to apply a series of graphical effects to\n    its children. See module documentation for full information on\n    setting effects and creating your own.\n    '''\n\n    background_color = ListProperty((0, 0, 0, 1))\n    '''This defines the background color to be used for the fbo in the\n    EffectWidget.\n\n    :attr:`background_color` is a :class:`ListProperty` defaults to\n    (0, 0, 0, 1)\n    '''\n\n    texture = ObjectProperty(None)\n    '''The output texture of our final :class:`~kivy.graphics.Fbo` after\n    all effects have been applied.\n\n    texture is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    effects = ListProperty([])\n    '''List of all the effects to be applied. These should all be\n    instances of :class:`EffectBase`.\n\n    effects is a :class:`ListProperty` and defaults to [].\n    '''\n\n    fbo_list = ListProperty([])\n    '''(internal) list of all the fbos that are being used to apply\n    the effects.\n\n    fbo_list is a :class:`ListProperty` and defaults to [].\n    '''\n\n    _bound_effects = ListProperty([])\n    '''(internal) list of effect classes that have been given an fbo to\n    manage. This is necessary so that the fbo can be removed it the\n    effect is no longer in use.\n\n    _bound_effects is a :class:`ListProperty` and defaults to [].\n    '''\n\n    def __init__(self, **kwargs):\n        # Make sure opengl context exists\n        EventLoop.ensure_window()\n\n        self.canvas = RenderContext(use_parent_projection=True,\n                                    use_parent_modelview=True)\n\n        with self.canvas:\n            self.fbo = Fbo(size=self.size)\n\n        with self.fbo.before:\n            PushMatrix()\n        with self.fbo:\n            ClearColor(0, 0, 0, 0)\n            ClearBuffers()\n            self._background_color = Color(*self.background_color)\n            self.fbo_rectangle = Rectangle(size=self.size)\n        with self.fbo.after:\n            PopMatrix()\n\n        super(EffectWidget, self).__init__(**kwargs)\n\n        Clock.schedule_interval(self._update_glsl, 0)\n\n        self.bind(size=self.refresh_fbo_setup,\n                  effects=self.refresh_fbo_setup,\n                  background_color=self._refresh_background_color)\n\n        self.refresh_fbo_setup()\n        self._refresh_background_color()  # In case thi was changed in kwargs\n\n    def _refresh_background_color(self, *args):\n        self._background_color.rgba = self.background_color\n\n    def _update_glsl(self, *largs):\n        '''(internal) Passes new time and resolution uniform\n        variables to the shader.\n        '''\n        time = Clock.get_boottime()\n        resolution = [float(size) for size in self.size]\n        self.canvas['time'] = time\n        self.canvas['resolution'] = resolution\n        for fbo in self.fbo_list:\n            fbo['time'] = time\n            fbo['resolution'] = resolution\n\n    def refresh_fbo_setup(self, *args):\n        '''(internal) Creates and assigns one :class:`~kivy.graphics.Fbo`\n        per effect, and makes sure all sizes etc. are correct and\n        consistent.\n        '''\n        # Add/remove fbos until there is one per effect\n        while len(self.fbo_list) < len(self.effects):\n            with self.canvas:\n                new_fbo = EffectFbo(size=self.size)\n            with new_fbo:\n                ClearColor(0, 0, 0, 0)\n                ClearBuffers()\n                Color(1, 1, 1, 1)\n                new_fbo.texture_rectangle = Rectangle(size=self.size)\n\n                new_fbo.texture_rectangle.size = self.size\n            self.fbo_list.append(new_fbo)\n        while len(self.fbo_list) > len(self.effects):\n            old_fbo = self.fbo_list.pop()\n            self.canvas.remove(old_fbo)\n\n        # Remove fbos from unused effects\n        for effect in self._bound_effects:\n            if effect not in self.effects:\n                effect.fbo = None\n        self._bound_effects = self.effects\n\n        # Do resizing etc.\n        self.fbo.size = self.size\n        self.fbo_rectangle.size = self.size\n        for i in range(len(self.fbo_list)):\n            self.fbo_list[i].size = self.size\n            self.fbo_list[i].texture_rectangle.size = self.size\n\n        # If there are no effects, just draw our main fbo\n        if len(self.fbo_list) == 0:\n            self.texture = self.fbo.texture\n            return\n\n        for i in range(1, len(self.fbo_list)):\n            fbo = self.fbo_list[i]\n            fbo.texture_rectangle.texture = self.fbo_list[i - 1].texture\n\n        # Build effect shaders\n        for effect, fbo in zip(self.effects, self.fbo_list):\n            effect.fbo = fbo\n\n        self.fbo_list[0].texture_rectangle.texture = self.fbo.texture\n        self.texture = self.fbo_list[-1].texture\n\n    def add_widget(self, widget):\n        # Add the widget to our Fbo instead of the normal canvas\n        c = self.canvas\n        self.canvas = self.fbo\n        super(EffectWidget, self).add_widget(widget)\n        self.canvas = c\n\n    def remove_widget(self, widget):\n        # Remove the widget from our Fbo instead of the normal canvas\n        c = self.canvas\n        self.canvas = self.fbo\n        super(EffectWidget, self).remove_widget(widget)\n        self.canvas = c\n\n    def clear_widgets(self, children=None):\n        # Clear widgets from our Fbo instead of the normal canvas\n        c = self.canvas\n        self.canvas = self.fbo\n        super(EffectWidget, self).clear_widgets(children)\n        self.canvas = c\n"
  },
  {
    "path": "tickeys/kivy/uix/filechooser.py",
    "content": "'''\nFileChooser\n===========\n\n.. versionadded:: 1.0.5\n\n\n.. versionchanged:: 1.2.0\n    In the chooser template, the `controller` is not a direct reference anymore\n    but a weak-reference.\n    You must update all the notation `root.controller.xxx` to\n    `root.controller().xxx`.\n\nSimple example\n--------------\n\nmain.py\n\n.. include:: ../../examples/RST_Editor/main.py\n    :literal:\n\neditor.kv\n\n.. highlight:: kv\n\n.. include:: ../../examples/RST_Editor/editor.kv\n    :literal:\n\n'''\nfrom kivy.uix.screenmanager import ScreenManager, Screen\n\n__all__ = ('FileChooserListView', 'FileChooserIconView',\n           'FileChooserListLayout', 'FileChooserIconLayout',\n           'FileChooser', 'FileChooserController',\n           'FileChooserProgressBase', 'FileSystemAbstract',\n           'FileSystemLocal')\n\nfrom weakref import ref\nfrom time import time\nfrom kivy.compat import string_types\nfrom kivy.factory import Factory\nfrom kivy.clock import Clock\nfrom kivy.lang import Builder\nfrom kivy.logger import Logger\nfrom kivy.utils import platform as core_platform\nfrom kivy.uix.floatlayout import FloatLayout\nfrom kivy.properties import (\n    StringProperty, ListProperty, BooleanProperty, ObjectProperty,\n    NumericProperty, OptionProperty, AliasProperty)\nfrom os import listdir\nfrom os.path import (\n    basename, join, sep, normpath, expanduser, altsep,\n    splitdrive, realpath, getsize, isdir, abspath, pardir)\nfrom fnmatch import fnmatch\nimport collections\n\nplatform = core_platform\nfilesize_units = ('B', 'KB', 'MB', 'GB', 'TB')\n\n_have_win32file = False\nif platform == 'win':\n    # Import that module here as it's not available on non-windows machines.\n    # See http://bit.ly/i9klJE except that the attributes are defined in\n    # win32file not win32com (bug on page).\n    # Note: For some reason this doesn't work after a os.chdir(), no matter to\n    #       what directory you change from where. Windows weirdness.\n    try:\n        from win32file import FILE_ATTRIBUTE_HIDDEN, GetFileAttributesExW, error\n        _have_win32file = True\n    except ImportError:\n        Logger.error('filechooser: win32file module is missing')\n        Logger.error('filechooser: we cant check if a file is hidden or not')\n\n\ndef alphanumeric_folders_first(files, filesystem):\n    return (sorted(f for f in files if filesystem.is_dir(f)) +\n            sorted(f for f in files if not filesystem.is_dir(f)))\n\n\nclass FileSystemAbstract(object):\n    '''Class for implementing a File System view that can be used with the\n    :class:`FileChooser`.:attr:`~FileChooser.file_system`.\n\n    .. versionadded:: 1.8.0\n    '''\n\n    def listdir(self, fn):\n        '''Return the list of files in the directory `fn`\n        '''\n        pass\n\n    def getsize(self, fn):\n        '''Return the size in bytes of a file\n        '''\n        pass\n\n    def is_hidden(self, fn):\n        '''Return True if the file is hidden\n        '''\n        pass\n\n    def is_dir(self, fn):\n        '''Return True if the argument passed to this method is a directory\n        '''\n        pass\n\n\nclass FileSystemLocal(FileSystemAbstract):\n    '''Implementation of :class:`FileSystemAbstract` for local files\n\n    .. versionadded:: 1.8.0\n    '''\n\n    def listdir(self, fn):\n        return listdir(fn)\n\n    def getsize(self, fn):\n        return getsize(fn)\n\n    def is_hidden(self, fn):\n        if platform == 'win':\n            if not _have_win32file:\n                return False\n            try:\n                return GetFileAttributesExW(fn)[0] & FILE_ATTRIBUTE_HIDDEN\n            except error:\n                # This error can occured when a file is already accessed by\n                # someone else. So don't return to True, because we have lot\n                # of chances to not being able to do anything with it.\n                Logger.exception('unable to access to <%s>' % fn)\n                return True\n\n        return basename(fn).startswith('.')\n\n    def is_dir(self, fn):\n        return isdir(fn)\n\n\nclass FileChooserProgressBase(FloatLayout):\n    '''Base for implementing a progress view. This view is used when too many\n    entries need to be created and are delayed over multiple frames.\n\n    .. versionadded:: 1.2.0\n    '''\n\n    path = StringProperty('')\n    '''Current path of the FileChooser, read-only.\n    '''\n\n    index = NumericProperty(0)\n    '''Current index of :attr:`total` entries to be loaded.\n    '''\n\n    total = NumericProperty(1)\n    '''Total number of entries to load.\n    '''\n\n    def cancel(self, *largs):\n        '''Cancel any action from the FileChooserController.\n        '''\n        if self.parent:\n            self.parent.cancel()\n\n    def on_touch_down(self, touch):\n        if self.collide_point(*touch.pos):\n            super(FileChooserProgressBase, self).on_touch_down(touch)\n            return True\n\n    def on_touch_move(self, touch):\n        if self.collide_point(*touch.pos):\n            super(FileChooserProgressBase, self).on_touch_move(touch)\n            return True\n\n    def on_touch_up(self, touch):\n        if self.collide_point(*touch.pos):\n            super(FileChooserProgressBase, self).on_touch_up(touch)\n            return True\n\n\nclass FileChooserProgress(FileChooserProgressBase):\n    pass\n\n\nclass FileChooserLayout(FloatLayout):\n    '''Base class for file chooser layouts.\n\n    .. versionadded:: 1.9.0\n    '''\n\n    VIEWNAME = 'undefined'\n\n    __events__ = ('on_entry_added', 'on_entries_cleared',\n                  'on_subentry_to_entry', 'on_remove_subentry', 'on_submit')\n\n    controller = ObjectProperty()\n    '''\n    Reference to the controller handling this layout.\n\n    :class:`~kivy.properties.ObjectProperty`\n    '''\n\n    def on_entry_added(self, node, parent=None):\n        pass\n\n    def on_entries_cleared(self):\n        pass\n\n    def on_subentry_to_entry(self, subentry, entry):\n        pass\n\n    def on_remove_subentry(self, subentry, entry):\n        pass\n\n    def on_submit(self, selected, touch=None):\n        pass\n\n\nclass FileChooserListLayout(FileChooserLayout):\n    '''File chooser layout using a list view.\n\n    .. versionadded:: 1.9.0\n    '''\n    VIEWNAME = 'list'\n    _ENTRY_TEMPLATE = 'FileListEntry'\n\n    def __init__(self, **kwargs):\n        super(FileChooserListLayout, self).__init__(**kwargs)\n        self.bind(on_entries_cleared=self.scroll_to_top)\n\n    def scroll_to_top(self, *args):\n        self.ids.scrollview.scroll_y = 1.0\n\n\nclass FileChooserIconLayout(FileChooserLayout):\n    '''File chooser layout using an icon view.\n\n    .. versionadded:: 1.9.0\n    '''\n\n    VIEWNAME = 'icon'\n    _ENTRY_TEMPLATE = 'FileIconEntry'\n\n    def __init__(self, **kwargs):\n        super(FileChooserIconLayout, self).__init__(**kwargs)\n        self.bind(on_entries_cleared=self.scroll_to_top)\n\n    def scroll_to_top(self, *args):\n        self.ids.scrollview.scroll_y = 1.0\n\n\nclass FileChooserController(FloatLayout):\n    '''Base for implementing a FileChooser. Don't use this class directly, but\n    prefer using an implementation such as the :class:`FileChooser`,\n    :class:`FileChooserListView` or :class:`FileChooserIconView`.\n\n    .. versionchanged:: 1.9.0\n\n    :Events:\n        `on_entry_added`: entry, parent\n            Fired when a root-level entry is added to the file list.\n        `on_entries_cleared`\n            Fired when the the entries list is cleared, usually when the\n            root is refreshed.\n        `on_subentry_to_entry`: entry, parent\n            Fired when a sub-entry is added to an existing entry.\n            Fired when entries are removed from an entry, usually when\n            a node is closed.\n        `on_submit`: selection, touch\n            Fired when a file has been selected with a double-tap.\n    '''\n    _ENTRY_TEMPLATE = None\n\n    layout = ObjectProperty(baseclass=FileChooserLayout)\n    '''\n    Reference to the layout widget instance.\n\n    layout is an :class:`~kivy.properties.ObjectProperty`.\n\n    .. versionadded:: 1.9.0\n    '''\n\n    path = StringProperty(u'/')\n    '''\n    :class:`~kivy.properties.StringProperty`, defaults to the current working\n    directory as a unicode string. It specifies the path on the filesystem that\n    this controller should refer to.\n\n    .. warning::\n\n        If a unicode path is specified, all the files returned will be in\n        unicode allowing the display of unicode files and paths. If a bytes\n        path is specified, only files and paths with ascii names will be\n        displayed properly: non-ascii filenames will be displayed and listed\n        with questions marks (?) instead of their unicode characters.\n    '''\n\n    filters = ListProperty([])\n    ''':class:`~kivy.properties.ListProperty`, defaults to [], equal to '\\*'.\n    Specifies the filters to be applied to the files in the directory.\n\n    The filters are not reset when the path changes. You need to do that\n    yourself if desired.\n\n    There are two kinds of filters: patterns and callbacks.\n\n    #. Patterns\n\n        e.g. ['\\*.png'].\n        You can use the following patterns:\n\n            ========== =================================\n            Pattern     Meaning\n            ========== =================================\n            \\*         matches everything\n            ?          matches any single character\n            [seq]      matches any character in seq\n            [!seq]     matches any character not in seq\n            ========== =================================\n\n    #. Callbacks\n\n        You can specify a function that will be called for each file. The\n        callback will be passed the folder and file name as the first\n        and second parameters respectively. It should return True to\n        indicate a match and False otherwise.\n\n    .. versionchanged:: 1.4.0\n        If the filter is a callable (function or method), it will be called\n        with the path and the file name as arguments for each file in the\n        directory.\n        The callable should returns True to indicate a match and False\n        overwise.\n    '''\n\n    filter_dirs = BooleanProperty(False)\n    '''\n    :class:`~kivy.properties.BooleanProperty`, defaults to False.\n    Indicates whether filters should also apply to directories.\n    '''\n\n    sort_func = ObjectProperty(alphanumeric_folders_first)\n    '''\n    :class:`~kivy.properties.ObjectProperty`.\n    Provides a function to be called with a list of filenames, and the\n    filesystem implementation as the second argument.\n    Returns a list of filenames sorted for display in the view.\n\n    .. versionchanged:: 1.8.0\n\n        The signature needs now 2 arguments: first the list of files,\n        second the filesystem class to use.\n    '''\n\n    files = ListProperty([])\n    '''\n    Read-only :class:`~kivy.properties.ListProperty`.\n    The list of files in the directory specified by path after applying the\n    filters.\n    '''\n\n    show_hidden = BooleanProperty(False)\n    '''\n    :class:`~kivy.properties.BooleanProperty`, defaults to False.\n    Determines whether hidden files and folders should be shown.\n    '''\n\n    selection = ListProperty([])\n    '''\n    Read-only :class:`~kivy.properties.ListProperty`.\n    Contains the list of files that are currently selected.\n    '''\n\n    multiselect = BooleanProperty(False)\n    '''\n    :class:`~kivy.properties.BooleanProperty`, defaults to False.\n    Determines whether the user is able to select multiple files or not.\n    '''\n\n    dirselect = BooleanProperty(False)\n    '''\n    :class:`~kivy.properties.BooleanProperty`, defaults to False.\n    Determines whether directories are valid selections or not.\n\n    .. versionadded:: 1.1.0\n    '''\n\n    rootpath = StringProperty(None, allownone=True)\n    '''\n    Root path to use instead of the system root path. If set, it will not show\n    a \"..\" directory to go up to the root path. For example, if you set\n    rootpath to /users/foo, the user will be unable to go to /users or to any\n    other directory not starting with /users/foo.\n\n    .. versionadded:: 1.2.0\n\n    :class:`~kivy.properties.StringProperty`, defaults to None.\n\n    .. note::\n\n        Similar to :attr:`path`, if `rootpath` is specified, whether it's a\n        bytes or unicode string determines the type of the filenames and paths\n        read.\n    '''\n\n    progress_cls = ObjectProperty(FileChooserProgress)\n    '''Class to use for displaying a progress indicator for filechooser\n    loading.\n\n    .. versionadded:: 1.2.0\n\n    :class:`~kivy.properties.ObjectProperty`, defaults to\n    :class:`FileChooserProgress`.\n\n    .. versionchanged:: 1.8.0\n\n        If you set a string, the :class:`~kivy.factory.Factory` will be used to\n        resolve the class.\n\n    '''\n\n    file_encodings = ListProperty(['utf-8', 'latin1', 'cp1252'])\n    '''Possible encodings for decoding a filename to unicode. In the case that\n    the user has a weird filename, undecodable without knowing it's\n    initial encoding, we have no other choice than to guess it.\n\n    Please note that if you encounter an issue because of a missing encoding\n    here, we'll be glad to add it to this list.\n\n    .. versionadded:: 1.3.0\n\n    .. deprecated:: 1.8.0\n       This property is no longer used as the filechooser no longer decodes\n       the file names.\n\n    file_encodings is a :class:`~kivy.properties.ListProperty` and defaults to\n    ['utf-8', 'latin1', 'cp1252'],\n    '''\n\n    file_system = ObjectProperty(FileSystemLocal(),\n                                 baseclass=FileSystemAbstract)\n    '''Implementation to access the file system. Must be an instance of\n    FileSystemAbstract.\n\n    .. versionadded:: 1.8.0\n\n    :class:`~kivy.properties.ObjectProperty`, defaults to\n    :class:`FileSystemLocal()`\n    '''\n\n    __events__ = ('on_entry_added', 'on_entries_cleared',\n                  'on_subentry_to_entry', 'on_remove_subentry', 'on_submit')\n\n    def __init__(self, **kwargs):\n        self._progress = None\n        super(FileChooserController, self).__init__(**kwargs)\n\n        self._items = []\n        self.bind(selection=self._update_item_selection)\n\n        self._previous_path = [self.path]\n        self.bind(path=self._save_previous_path)\n        self.bind(path=self._trigger_update,\n                  filters=self._trigger_update,\n                  rootpath=self._trigger_update)\n        self._trigger_update()\n\n    def on_touch_down(self, touch):\n        # don't respond to touchs outside self\n        if not self.collide_point(*touch.pos):\n            return\n        if self.disabled:\n            return True\n        return super(FileChooserController, self).on_touch_down(touch)\n\n    def on_touch_up(self, touch):\n        # don't respond to touchs outside self\n        if not self.collide_point(*touch.pos):\n            return True\n        if self.disabled:\n            return True\n        return super(FileChooserController, self).on_touch_up(touch)\n\n    def _update_item_selection(self, *args):\n        for item in self._items:\n            item.selected = item.path in self.selection\n\n    def _save_previous_path(self, instance, value):\n        self._previous_path.append(value)\n        self._previous_path = self._previous_path[-2:]\n\n    def _trigger_update(self, *args):\n        Clock.unschedule(self._update_files)\n        Clock.schedule_once(self._update_files)\n\n    def on_entry_added(self, node, parent=None):\n        if self.layout:\n            self.layout.dispatch('on_entry_added', node, parent)\n\n    def on_entries_cleared(self):\n        if self.layout:\n            self.layout.dispatch('on_entries_cleared')\n\n    def on_subentry_to_entry(self, subentry, entry):\n        if self.layout:\n            self.layout.dispatch('on_subentry_to_entry', subentry, entry)\n\n    def on_remove_subentry(self, subentry, entry):\n        if self.layout:\n            self.layout.dispatch('on_remove_subentry', subentry, entry)\n\n    def on_submit(self, selected, touch=None):\n        if self.layout:\n            self.layout.dispatch('on_submit', selected, touch)\n\n    def entry_touched(self, entry, touch):\n        '''(internal) This method must be called by the template when an entry\n        is touched by the user.\n        '''\n        if (\n            'button' in touch.profile and touch.button in (\n                'scrollup', 'scrolldown', 'scrollleft', 'scrollright')):\n            return False\n\n        _dir = self.file_system.is_dir(entry.path)\n        dirselect = self.dirselect\n\n        if _dir and dirselect and touch.is_double_tap:\n            self.open_entry(entry)\n            return\n\n        if self.multiselect:\n            if entry.path in self.selection:\n                self.selection.remove(entry.path)\n            else:\n                if _dir and not self.dirselect:\n                    self.open_entry(entry)\n                    return\n                self.selection.append(entry.path)\n        else:\n            if _dir and not self.dirselect:\n                self.open_entry\n                return\n            self.selection = [entry.path, ]\n\n    def entry_released(self, entry, touch):\n        '''(internal) This method must be called by the template when an entry\n        is touched by the user.\n\n        .. versionadded:: 1.1.0\n        '''\n        if (\n            'button' in touch.profile and touch.button in (\n                'scrollup', 'scrolldown', 'scrollleft', 'scrollright')):\n            return False\n        if not self.multiselect:\n            if self.file_system.is_dir(entry.path) and not self.dirselect:\n                self.open_entry(entry)\n            elif touch.is_double_tap:\n                if self.dirselect and self.file_system.is_dir(entry.path):\n                    self.open_entry(entry)\n                else:\n                    self.dispatch('on_submit', self.selection, touch)\n\n    def open_entry(self, entry):\n        try:\n            # Just check if we can list the directory. This is also what\n            # _add_file does, so if it fails here, it would also fail later\n            # on. Do the check here to prevent setting path to an invalid\n            # directory that we cannot list.\n            self.file_system.listdir(entry.path)\n        except OSError:\n            entry.locked = True\n        else:\n            # If entry.path is to jump to previous directory, update path with\n            # parent directory\n            self.path = abspath(join(self.path, entry.path))\n            self.selection = []\n\n    def _apply_filters(self, files):\n        if not self.filters:\n            return files\n        filtered = []\n        for filt in self.filters:\n            if isinstance(filt, collections.Callable):\n                filtered.extend([fn for fn in files if filt(self.path, fn)])\n            else:\n                filtered.extend([fn for fn in files if fnmatch(fn, filt)])\n        if not self.filter_dirs:\n            dirs = [fn for fn in files if self.file_system.is_dir(fn)]\n            filtered.extend(dirs)\n        return list(set(filtered))\n\n    def get_nice_size(self, fn):\n        '''Pass the filepath. Returns the size in the best human readable\n        format or '' if it is a directory (Don't recursively calculate size.).\n        '''\n        if self.file_system.is_dir(fn):\n            return ''\n        try:\n            size = self.file_system.getsize(fn)\n        except OSError:\n            return '--'\n\n        for unit in filesize_units:\n            if size < 1024.0:\n                return '%1.0f %s' % (size, unit)\n            size /= 1024.0\n\n    def _update_files(self, *args, **kwargs):\n        # trigger to start gathering the files in the new directory\n        # we'll start a timer that will do the job, 10 times per frames\n        # (default)\n        self._gitems = []\n        self._gitems_parent = kwargs.get('parent', None)\n        self._gitems_gen = self._generate_file_entries(\n            path=kwargs.get('path', self.path),\n            parent=self._gitems_parent)\n\n        # cancel any previous clock if exist\n        Clock.unschedule(self._create_files_entries)\n\n        # show the progression screen\n        self._hide_progress()\n        if self._create_files_entries():\n            # not enough for creating all the entries, all a clock to continue\n            # start a timer for the next 100 ms\n            Clock.schedule_interval(self._create_files_entries, .1)\n\n    def _get_file_paths(self, items):\n        return [file.path for file in items]\n\n    def _create_files_entries(self, *args):\n        # create maximum entries during 50ms max, or 10 minimum (slow system)\n        # (on a \"fast system\" (core i7 2700K), we can create up to 40 entries\n        # in 50 ms. So 10 is fine for low system.\n        start = time()\n        finished = False\n        index = total = count = 1\n        while time() - start < 0.05 or count < 10:\n            try:\n                index, total, item = next(self._gitems_gen)\n                self._gitems.append(item)\n                count += 1\n            except StopIteration:\n                finished = True\n                break\n            except TypeError:  # in case _gitems_gen is None\n                finished = True\n                break\n\n        # if this wasn't enough for creating all the entries, show a progress\n        # bar, and report the activity to the user.\n        if not finished:\n            self._show_progress()\n            self._progress.total = total\n            self._progress.index = index\n            return True\n\n        # we created all the files, now push them on the view\n        self._items = items = self._gitems\n        parent = self._gitems_parent\n        if parent is None:\n            self.dispatch('on_entries_cleared')\n            for entry in items:\n                self.dispatch('on_entry_added', entry, parent)\n        else:\n            parent.entries[:] = items\n            for entry in items:\n                self.dispatch('on_subentry_to_entry', entry, parent)\n        self.files[:] = self._get_file_paths(items)\n\n        # stop the progression / creation\n        self._hide_progress()\n        self._gitems = None\n        self._gitems_gen = None\n        Clock.unschedule(self._create_files_entries)\n        return False\n\n    def cancel(self, *largs):\n        '''Cancel any background action started by filechooser, such as loading\n        a new directory.\n\n        .. versionadded:: 1.2.0\n        '''\n        Clock.unschedule(self._create_files_entries)\n        self._hide_progress()\n        if len(self._previous_path) > 1:\n            # if we cancel any action, the path will be set same as the\n            # previous one, so we can safely cancel the update of the previous\n            # path.\n            self.path = self._previous_path[-2]\n            Clock.unschedule(self._update_files)\n\n    def _show_progress(self):\n        if self._progress:\n            return\n        cls = self.progress_cls\n        if isinstance(cls, string_types):\n            cls = Factory.get(cls)\n        self._progress = cls(path=self.path)\n        self._progress.value = 0\n        self.add_widget(self._progress)\n\n    def _hide_progress(self):\n        if self._progress:\n            self.remove_widget(self._progress)\n            self._progress = None\n\n    def _generate_file_entries(self, *args, **kwargs):\n        # Generator that will create all the files entries.\n        # the generator is used via _update_files() and _create_files_entries()\n        # don't use it directly.\n        is_root = False\n        path = kwargs.get('path', self.path)\n        have_parent = kwargs.get('parent', None) is not None\n\n        # Add the components that are always needed\n        if self.rootpath:\n            rootpath = realpath(self.rootpath)\n            path = realpath(path)\n            if not path.startswith(rootpath):\n                self.path = rootpath\n                return\n            elif path == rootpath:\n                is_root = True\n        else:\n            if platform == 'win':\n                is_root = splitdrive(path)[1] in (sep, altsep)\n            elif platform in ('macosx', 'linux', 'android', 'ios'):\n                is_root = normpath(expanduser(path)) == sep\n            else:\n                # Unknown fs, just always add the .. entry but also log\n                Logger.warning('Filechooser: Unsupported OS: %r' % platform)\n        # generate an entries to go back to previous\n        if not is_root and not have_parent:\n            back = '..' + sep\n            pardir = self._create_entry_widget(dict(\n                name=back, size='', path=back, controller=ref(self),\n                isdir=True, parent=None, sep=sep, get_nice_size=lambda: ''))\n            yield 0, 1, pardir\n\n        # generate all the entries for files\n        try:\n            for index, total, item in self._add_files(path):\n                yield index, total, item\n        except OSError:\n            Logger.exception('Unable to open directory <%s>' % self.path)\n            self.files[:] = []\n\n    def _create_entry_widget(self, ctx):\n        template = self.layout._ENTRY_TEMPLATE\\\n            if self.layout else self._ENTRY_TEMPLATE\n        return Builder.template(template, **ctx)\n\n    def _add_files(self, path, parent=None):\n        path = expanduser(path)\n\n        files = []\n        fappend = files.append\n        for f in self.file_system.listdir(path):\n            try:\n                # In the following, use fully qualified filenames\n                fappend(normpath(join(path, f)))\n            except UnicodeDecodeError:\n                Logger.exception('unable to decode <{}>'.format(f))\n            except UnicodeEncodeError:\n                Logger.exception('unable to encode <{}>'.format(f))\n        # Apply filename filters\n        files = self._apply_filters(files)\n        # Sort the list of files\n        files = self.sort_func(files, self.file_system)\n        is_hidden = self.file_system.is_hidden\n        if not self.show_hidden:\n            files = [x for x in files if not is_hidden(x)]\n        self.files[:] = files\n        total = len(files)\n        wself = ref(self)\n        for index, fn in enumerate(files):\n\n            def get_nice_size():\n                # Use a closure for lazy-loading here\n                return self.get_nice_size(fn)\n\n            ctx = {'name': basename(fn),\n                   'get_nice_size': get_nice_size,\n                   'path': fn,\n                   'controller': wself,\n                   'isdir': self.file_system.is_dir(fn),\n                   'parent': parent,\n                   'sep': sep}\n            entry = self._create_entry_widget(ctx)\n            yield index, total, entry\n\n    def entry_subselect(self, entry):\n        if not self.file_system.is_dir(entry.path):\n            return\n        self._update_files(path=entry.path, parent=entry)\n\n    def close_subselection(self, entry):\n        for subentry in entry.entries:\n            self.dispatch('on_remove_subentry', subentry, entry)\n\n\nclass FileChooserListView(FileChooserController):\n    '''Implementation of :class:`FileChooserController` using a list view.\n\n    .. versionadded:: 1.9.0\n    '''\n    _ENTRY_TEMPLATE = 'FileListEntry'\n\n\nclass FileChooserIconView(FileChooserController):\n    '''Implementation of :class:`FileChooserController` using an icon view.\n\n    .. versionadded:: 1.9.0\n    '''\n    _ENTRY_TEMPLATE = 'FileIconEntry'\n\n\nclass FileChooser(FileChooserController):\n    '''Implementation of :class:`FileChooserController` which supports\n    switching between multiple, synced layout views.\n\n    .. versionadded:: 1.9.0\n    '''\n\n    manager = ObjectProperty()\n    '''\n    Reference to the :class:`~kivy.uix.screenmanager.ScreenManager` instance.\n\n    :class:`~kivy.properties.ObjectProperty`\n    '''\n\n    _view_list = ListProperty()\n\n    def get_view_list(self):\n        return self._view_list\n\n    view_list = AliasProperty(get_view_list, bind=('_view_list',))\n    '''\n    List of views added to this FileChooser.\n\n    :class:`~kivy.properties.AliasProperty` of type :class:`list`.\n    '''\n\n    _view_mode = StringProperty()\n\n    def get_view_mode(self):\n        return self._view_mode\n\n    def set_view_mode(self, mode):\n        if mode not in self._view_list:\n            raise ValueError('unknown view mode %r' % mode)\n        self._view_mode = mode\n\n    view_mode = AliasProperty(\n        get_view_mode, set_view_mode, bind=('_view_mode',))\n    '''\n    Current layout view mode.\n\n    :class:`~kivy.properties.AliasProperty` of type :class:`str`.\n    '''\n\n    @property\n    def _views(self):\n        return [screen.children[0] for screen in self.manager.screens]\n\n    def __init__(self, **kwargs):\n        super(FileChooser, self).__init__(**kwargs)\n\n        self.manager = ScreenManager()\n        super(FileChooser, self).add_widget(self.manager)\n\n        self.trigger_update_view = Clock.create_trigger(self.update_view)\n\n        self.bind(view_mode=self.trigger_update_view)\n\n    def add_widget(self, widget, **kwargs):\n        if widget is self._progress:\n            super(FileChooser, self).add_widget(widget, **kwargs)\n        elif hasattr(widget, 'VIEWNAME'):\n            name = widget.VIEWNAME + 'view'\n            screen = Screen(name=name)\n            widget.controller = self\n            screen.add_widget(widget)\n            self.manager.add_widget(screen)\n\n            self.trigger_update_view()\n        else:\n            raise ValueError(\n                'widget must be a FileChooserLayout,'\n                ' not %s' % type(widget).__name__)\n\n    def rebuild_views(self):\n        views = [view.VIEWNAME for view in self._views]\n        if views != self._view_list:\n            self._view_list = views\n            if self._view_mode not in self._view_list:\n                self._view_mode = self._view_list[0]\n            self._trigger_update()\n\n    def update_view(self, *args):\n        self.rebuild_views()\n\n        sm = self.manager\n        viewlist = self._view_list\n        view = self.view_mode\n        current = sm.current[:-4]\n\n        viewindex = viewlist.index(view) if view in viewlist else 0\n        currentindex = viewlist.index(current) if current in viewlist else 0\n\n        direction = 'left' if currentindex < viewindex else 'right'\n\n        sm.transition.direction = direction\n        sm.current = view + 'view'\n\n    def _create_entry_widget(self, ctx):\n        return [Builder.template(view._ENTRY_TEMPLATE, **ctx)\n                for view in self._views]\n\n    def _get_file_paths(self, items):\n        if self._views:\n            return [file[0].path for file in items]\n        return []\n\n    def _update_item_selection(self, *args):\n        for viewitem in self._items:\n            selected = viewitem[0].path in self.selection\n            for item in viewitem:\n                item.selected = selected\n\n    def on_entry_added(self, node, parent=None):\n        for index, view in enumerate(self._views):\n            view.dispatch(\n                'on_entry_added',\n                node[index], parent[index] if parent else None)\n\n    def on_entries_cleared(self):\n        for view in self._views:\n            view.dispatch('on_entries_cleared')\n\n    def on_subentry_to_entry(self, subentry, entry):\n        for index, view in enumerate(self._views):\n            view.dispatch('on_subentry_to_entry', subentry[index], entry)\n\n    def on_remove_subentry(self, subentry, entry):\n        for index, view in enumerate(self._views):\n            view.dispatch('on_remove_subentry', subentry[index], entry)\n\n    def on_submit(self, selected, touch=None):\n        view_mode = self.view_mode\n        for view in self._views:\n            if view_mode == view.VIEWNAME:\n                view.dispatch('on_submit', selected, touch)\n                return\n\n\nif __name__ == '__main__':\n    from kivy.app import App\n    from kivy.lang import Builder\n    from pprint import pprint\n    import textwrap\n    import sys\n\n    root = Builder.load_string(textwrap.dedent('''\\\n    BoxLayout:\n        orientation: 'vertical'\n\n        BoxLayout:\n            size_hint_y: None\n            height: sp(52)\n\n            Button:\n                text: 'Icon View'\n                on_press: fc.view_mode = 'icon'\n            Button:\n                text: 'List View'\n                on_press: fc.view_mode = 'list'\n\n        FileChooser:\n            id: fc\n\n            FileChooserIconLayout\n            FileChooserListLayout\n    '''))\n\n    class FileChooserApp(App):\n\n        def build(self):\n            v = root.ids.fc\n            if len(sys.argv) > 1:\n                v.path = sys.argv[1]\n\n            v.bind(selection=lambda *x: pprint(\"selection: %s\" % x[1:]))\n            v.bind(path=lambda *x: pprint(\"path: %s\" % x[1:]))\n\n            return root\n\n    FileChooserApp().run()\n"
  },
  {
    "path": "tickeys/kivy/uix/floatlayout.py",
    "content": "'''\nFloat Layout\n============\n\nThe :class:`FloatLayout` class honors only the :attr:`Widget.pos_hint` and\n:attr:`Widget.size_hint` attributes.\n\n.. only:: html\n\n    .. image:: images/floatlayout.gif\n        :align: right\n\n.. only:: latex\n\n    .. image:: images/floatlayout.png\n        :align: right\n\nFor example, a FloatLayout with a size of (300, 300) is created::\n\n    layout = FloatLayout(size=(300, 300))\n\nBy default, all widgets have their size_hint=(1, 1), so this button will adopt\nthe same size as the layout::\n\n    button = Button(text='Hello world')\n    layout.add_widget(button)\n\nTo create a button 50% of the width and 25% of the height of the layout and\npositioned at (20, 20), you can do::\n\n    button = Button(\n        text='Hello world',\n        size_hint=(.5, .25),\n        pos=(20, 20))\n\nIf you want to create a button that will always be the size of layout minus\n20% on each side::\n\n    button = Button(text='Hello world', size_hint=(.6, .6),\n                    pos_hint={'x':.2, 'y':.2})\n\n.. note::\n\n    This layout can be used for an application. Most of the time, you will\n    use the size of Window.\n\n.. warning::\n\n    If you are not using pos_hint, you must handle the positioning of the\n    children: if the float layout is moving, you must handle moving the\n    children too.\n\n'''\n\n__all__ = ('FloatLayout', )\n\nfrom kivy.uix.layout import Layout\n\n\nclass FloatLayout(Layout):\n    '''Float layout class. See module documentation for more information.\n    '''\n\n    def __init__(self, **kwargs):\n        kwargs.setdefault('size', (1, 1))\n        super(FloatLayout, self).__init__(**kwargs)\n        self.bind(\n            children=self._trigger_layout,\n            pos=self._trigger_layout,\n            pos_hint=self._trigger_layout,\n            size_hint=self._trigger_layout,\n            size=self._trigger_layout)\n\n    def do_layout(self, *largs, **kwargs):\n        # optimization, until the size is 1, 1, don't do layout\n        if self.size == [1, 1]:\n            return\n        # optimize layout by preventing looking at the same attribute in a loop\n        w, h = kwargs.get('size', self.size)\n        x, y = kwargs.get('pos', self.pos)\n        for c in self.children:\n            # size\n            shw, shh = c.size_hint\n            if shw and shh:\n                c.size = w * shw, h * shh\n            elif shw:\n                c.width = w * shw\n            elif shh:\n                c.height = h * shh\n\n            # pos\n            for key, value in c.pos_hint.items():\n                if key == 'x':\n                    c.x = x + value * w\n                elif key == 'right':\n                    c.right = x + value * w\n                elif key == 'pos':\n                    c.pos = x + value[0] * w, y + value[1] * h\n                elif key == 'y':\n                    c.y = y + value * h\n                elif key == 'top':\n                    c.top = y + value * h\n                elif key == 'center':\n                    c.center = x + value[0] * w, y + value[1] * h\n                elif key == 'center_x':\n                    c.center_x = x + value * w\n                elif key == 'center_y':\n                    c.center_y = y + value * h\n\n    def add_widget(self, widget, index=0):\n        widget.bind(\n            #size=self._trigger_layout,\n            #size_hint=self._trigger_layout,\n            pos=self._trigger_layout,\n            pos_hint=self._trigger_layout)\n        return super(FloatLayout, self).add_widget(widget, index)\n\n    def remove_widget(self, widget):\n        widget.unbind(\n            #size=self._trigger_layout,\n            #size_hint=self._trigger_layout,\n            pos=self._trigger_layout,\n            pos_hint=self._trigger_layout)\n        return super(FloatLayout, self).remove_widget(widget)\n"
  },
  {
    "path": "tickeys/kivy/uix/gesturesurface.py",
    "content": "'''\nGesture Surface\n===============\n\n.. versionadded::\n    1.9.0\n\n.. warning::\n\n    This is experimental and subject to change as long as this warning notice\n    is present.\n\nSee :file:`kivy/examples/demo/multistroke/main.py` for a complete application\nexample.\n'''\n__all__ = ('GestureSurface', 'GestureContainer')\n\nfrom random import random\nfrom kivy.event import EventDispatcher\nfrom kivy.clock import Clock\nfrom kivy.vector import Vector\nfrom kivy.uix.floatlayout import FloatLayout\nfrom kivy.graphics import Color, Line, Rectangle\nfrom kivy.properties import (NumericProperty, BooleanProperty,\n                             DictProperty, ListProperty)\nfrom colorsys import hsv_to_rgb\n\n# Clock undershoot margin, FIXME: this is probably too high?\nUNDERSHOOT_MARGIN = 0.1\n\n\nclass GestureContainer(EventDispatcher):\n    '''Container object that stores information about a gesture. It has\n    various properties that are updated by `GestureSurface` as drawing\n    progresses.\n\n    :Arguments:\n        `touch`\n            Touch object (as received by on_touch_down) used to initialize\n            the gesture container. Required.\n\n    :Properties:\n        `active`\n            Set to False once the gesture is complete (meets\n            `max_stroke` setting or `GestureSurface.temporal_window`)\n\n            :attr:`active` is a\n            :class:`~kivy.properties.BooleanProperty`\n\n        `active_strokes`\n            Number of strokes currently active in the gesture, ie\n            concurrent touches associated with this gesture.\n\n            :attr:`active_strokes` is a\n            :class:`~kivy.properties.NumericProperty`\n\n        `max_strokes`\n            Max number of strokes allowed in the gesture. This\n            is set by `GestureSurface.max_strokes` but can\n            be overridden for example from `on_gesture_start`.\n\n            :attr:`max_strokes` is a\n            :class:`~kivy.properties.NumericProperty`\n\n        `was_merged`\n            Indicates that this gesture has been merged with another\n            gesture and should be considered discarded.\n\n            :attr:`was_merged` is a\n            :class:`~kivy.properties.BooleanProperty`\n\n        `bbox`\n            Dictionary with keys minx, miny, maxx, maxy. Represents the size\n            of the gesture bounding box.\n\n            :attr:`bbox` is a\n            :class:`~kivy.properties.DictProperty`\n\n        `width`\n            Represents the width of the gesture.\n\n            :attr:`width` is a\n            :class:`~kivy.properties.NumericProperty`\n\n        `height`\n            Represents the height of the gesture.\n\n            :attr:`height` is a\n            :class:`~kivy.properties.NumericProperty`\n    '''\n    active = BooleanProperty(True)\n    active_strokes = NumericProperty(0)\n    max_strokes = NumericProperty(0)\n    was_merged = BooleanProperty(False)\n    bbox = DictProperty({'minx': float('inf'), 'miny': float('inf'),\n                         'maxx': float('-inf'), 'maxy': float('-inf')})\n    width = NumericProperty(0)\n    height = NumericProperty(0)\n\n    def __init__(self, touch, **kwargs):\n        super(GestureContainer, self).__init__(**kwargs)\n\n        # This is the touch.uid of the oldest touch represented\n        self.id = str(touch.uid)\n\n        # Store various timestamps for decision making\n        self._create_time = Clock.get_time()\n        self._update_time = None\n        self._cleanup_time = None\n        self._cache_time = 0\n\n        # We can cache the candidate here to save zip()/Vector instantiation\n        self._vectors = None\n\n        # The color is applied to all canvas items of this gesture\n        col = kwargs.get('color', None)\n        if col is not None:\n            self.color = col\n        else:\n            self.color = [1.0, 1.0, 1.0]\n\n        # Key is touch.uid; value is a kivy.graphics.Line(); it's used even\n        # if line_width is 0 (ie not actually drawn anywhere)\n        self._strokes = {}\n\n        # Make sure the bbox is up to date with the first touch position\n        self.update_bbox(touch)\n\n    def get_vectors(self, **kwargs):\n        '''Return strokes in a format that is acceptable for\n        `kivy.multistroke.Recognizer` as a gesture candidate or template. The\n        result is cached automatically; the cache is invalidated at the start\n        and end of a stroke and if `update_bbox` is called. If you are going\n        to analyze a gesture mid-stroke, you may need to set the `no_cache`\n        argument to True.'''\n        if self._cache_time == self._update_time and not kwargs.get('no_cache'):\n            return self._vectors\n\n        vecs = []\n        append = vecs.append\n        for tuid, l in self._strokes.items():\n            lpts = l.points\n            append([Vector(*pts) for pts in zip(lpts[::2], lpts[1::2])])\n\n        self._vectors = vecs\n        self._cache_time = self._update_time\n        return vecs\n\n    def handles(self, touch):\n        '''Returns True if this container handles the given touch'''\n        if not self.active:\n            return False\n        return str(touch.uid) in self._strokes\n\n    def accept_stroke(self, count=1):\n        '''Returns True if this container can accept `count` new strokes'''\n        if not self.max_strokes:\n            return True\n        return len(self._strokes) + count <= self.max_strokes\n\n    def update_bbox(self, touch):\n        '''Update gesture bbox from a touch coordinate'''\n        x, y = touch.x, touch.y\n        bb = self.bbox\n        if x < bb['minx']:\n            bb['minx'] = x\n        if y < bb['miny']:\n            bb['miny'] = y\n        if x > bb['maxx']:\n            bb['maxx'] = x\n        if y > bb['maxy']:\n            bb['maxy'] = y\n        self.width = bb['maxx'] - bb['minx']\n        self.height = bb['maxy'] - bb['miny']\n        self._update_time = Clock.get_time()\n\n    def add_stroke(self, touch, line):\n        '''Associate a list of points with a touch.uid; the line itself is\n        created by the caller, but subsequent move/up events look it\n        up via us. This is done to avoid problems during merge.'''\n        self._update_time = Clock.get_time()\n        self._strokes[str(touch.uid)] = line\n        self.active_strokes += 1\n\n    def complete_stroke(self):\n        '''Called on touch up events to keep track of how many strokes\n        are active in the gesture (we only want to dispatch event when\n        the *last* stroke in the gesture is released)'''\n        self._update_time = Clock.get_time()\n        self.active_strokes -= 1\n\n    def single_points_test(self):\n        '''Returns True if the gesture consists only of single-point strokes,\n        we must discard it in this case, or an exception will be raised'''\n        for tuid, l in self._strokes.items():\n            if len(l.points) > 2:\n                return False\n        return True\n\n\nclass GestureSurface(FloatLayout):\n    '''Simple gesture surface to track/draw touch movements. Typically used\n    to gather user input suitable for :class:`kivy.multistroke.Recognizer`.\n\n    :Properties:\n        `temporal_window`\n            Time to wait from the last touch_up event before attempting\n            to recognize the gesture. If you set this to 0, the\n            `on_gesture_complete` event is not fired unless the\n            :attr:`max_strokes` condition is met.\n\n            :attr:`temporal_window` is a\n            :class:`~kivy.properties.NumericProperty` and defaults to 2.0\n\n        `max_strokes`\n            Max number of strokes in a single gesture; if this is reached,\n            recognition will start immediately on the final touch_up event.\n            If this is set to 0, the `on_gesture_complete` event is not\n            fired unless the :attr:`temporal_window` expires.\n\n            :attr:`max_strokes` is a\n            :class:`~kivy.properties.NumericProperty` and defaults to 2.0\n\n        `bbox_margin`\n            Bounding box margin for detecting gesture collisions, in\n            pixels.\n\n            :attr:`bbox_margin` is a\n            :class:`~kivy.properties.NumericProperty` and defaults to 30\n\n        `draw_timeout`\n            Number of seconds to keep lines/bbox on canvas after the\n            `on_gesture_complete` event is fired. If this is set to 0,\n            gestures are immediately removed from the surface when\n            complete.\n\n            :attr:`draw_timeout` is a\n            :class:`~kivy.properties.NumericProperty` and defaults to 3.0\n\n        `color`\n            Color used to draw the gesture, in RGB. This option does not\n            have an effect if :attr:`use_random_color` is True.\n\n            :attr:`draw_timeout` is a\n            :class:`~kivy.properties.ListProperty` and defaults to\n            [1, 1, 1] (white)\n\n        `use_random_color`\n            Set to True to pick a random color for each gesture, if you do\n            this then `color` is ignored. Defaults to False.\n\n            :attr:`use_random_color` is a\n            :class:`~kivy.properties.BooleanProperty` and defaults to False\n\n        `line_width`\n            Line width used for tracing touches on the surface. Set to 0\n            if you only want to detect gestures without drawing anything.\n            If you use 1.0, OpenGL GL_LINE is used for drawing; values > 1\n            will use an internal drawing method based on triangles (less\n            efficient), see :mod:`kivy.graphics`.\n\n            :attr:`line_width` is a\n            :class:`~kivy.properties.NumericProperty` and defaults to 2\n\n        `draw_bbox`\n            Set to True if you want to draw bounding box behind gestures.\n            This only works if `line_width` >= 1. Default is False.\n\n            :attr:`draw_bbox` is a\n            :class:`~kivy.properties.BooleanProperty` and defaults to True\n\n        `bbox_alpha`\n            Opacity for bounding box if `draw_bbox` is True. Default 0.1\n\n            :attr:`bbox_alpha` is a\n            :class:`~kivy.properties.NumericProperty` and defaults to 0.1\n\n    :Events:\n        `on_gesture_start` :class:`GestureContainer`\n            Fired when a new gesture is initiated on the surface, ie the\n            first on_touch_down that does not collide with an existing\n            gesture on the surface.\n\n        `on_gesture_extend` :class:`GestureContainer`\n            Fired when a touch_down event occurs within an existing gesture.\n\n        `on_gesture_merge` :class:`GestureContainer`, :class:`GestureContainer`\n            Fired when two gestures collide and get merged to one gesture.\n            The first argument is the gesture that has been merged (no longer\n            valid); the second is the combined (resulting) gesture.\n\n        `on_gesture_complete` :class:`GestureContainer`\n            Fired when a set of strokes is considered a complete gesture,\n            this happens when `temporal_window` expires or `max_strokes`\n            is reached. Typically you will bind to this event and use\n            the provided `GestureContainer` get_vectors() method to\n            match against your gesture database.\n\n        `on_gesture_cleanup` :class:`GestureContainer`\n            Fired `draw_timeout` seconds after `on_gesture_complete`,\n            The gesture will be removed from the canvas (if line_width > 0 or\n            draw_bbox is True) and the internal gesture list before this.\n\n        `on_gesture_discard` :class:`GestureContainer`\n            Fired when a gesture does not meet the minimum size requirements\n            for recognition (width/height < 5, or consists only of single-\n            point strokes).\n    '''\n\n    temporal_window = NumericProperty(2.0)\n    draw_timeout = NumericProperty(3.0)\n    max_strokes = NumericProperty(4)\n    bbox_margin = NumericProperty(30)\n\n    line_width = NumericProperty(2)\n    color = ListProperty([1., 1., 1.])\n    use_random_color = BooleanProperty(False)\n    draw_bbox = BooleanProperty(False)\n    bbox_alpha = NumericProperty(0.1)\n\n    def __init__(self, **kwargs):\n        super(GestureSurface, self).__init__(**kwargs)\n        # A list of GestureContainer objects (all gestures on the surface)\n        self._gestures = []\n        self.register_event_type('on_gesture_start')\n        self.register_event_type('on_gesture_extend')\n        self.register_event_type('on_gesture_merge')\n        self.register_event_type('on_gesture_complete')\n        self.register_event_type('on_gesture_cleanup')\n        self.register_event_type('on_gesture_discard')\n\n# -----------------------------------------------------------------------------\n# Touch Events\n# -----------------------------------------------------------------------------\n    def on_touch_down(self, touch):\n        '''When a new touch is registered, the first thing we do is to test if\n        it collides with the bounding box of another known gesture. If so, it\n        is assumed to be part of that gesture.\n        '''\n        # If the touch originates outside the surface, ignore it.\n        if not self.collide_point(touch.x, touch.y):\n            return\n\n        touch.grab(self)\n\n        # Add the stroke to existing gesture, or make a new one\n        g = self.find_colliding_gesture(touch)\n        new = False\n        if g is None:\n            g = self.init_gesture(touch)\n            new = True\n\n        # We now belong to a gesture (new or old); start a new stroke.\n        self.init_stroke(g, touch)\n\n        if new:\n            self.dispatch('on_gesture_start', g, touch)\n        else:\n            self.dispatch('on_gesture_extend', g, touch)\n\n        return True\n\n    def on_touch_move(self, touch):\n        '''When a touch moves, we add a point to the line on the canvas so the\n        path is updated. We must also check if the new point collides with the\n        bouonding box of another gesture - if so, they should be merged.'''\n        if touch.grab_current is not self:\n            return\n        if not self.collide_point(touch.y, touch.y):\n            return\n\n        # Retrieve the GestureContainer object that handles this touch, and\n        # test for colliding gestures. If found, merge them to one.\n        g = self.get_gesture(touch)\n        collision = self.find_colliding_gesture(touch)\n        if collision is not None and g.accept_stroke(len(collision._strokes)):\n            merge = self.merge_gestures(g, collision)\n            if g.was_merged:\n                self.dispatch('on_gesture_merge', g, collision)\n            else:\n                self.dispatch('on_gesture_merge', collision, g)\n            g = merge\n        else:\n            g.update_bbox(touch)\n\n        # Add the new point to gesture stroke list and update the canvas line\n        g._strokes[str(touch.uid)].points += (touch.x, touch.y)\n\n        # Draw the gesture bounding box; if it is a single press that\n        # does not trigger a move event, we would miss it otherwise.\n        if self.draw_bbox:\n            self._update_canvas_bbox(g)\n        return True\n\n    def on_touch_up(self, touch):\n        if touch.grab_current is not self:\n            return\n        touch.ungrab(self)\n\n        g = self.get_gesture(touch)\n        g.complete_stroke()\n\n        # If this stroke hit the maximum limit, dispatch immediately\n        if not g.accept_stroke():\n            self._complete_dispatcher(0)\n\n        # dispatch later only if we have a window\n        elif self.temporal_window > 0:\n            Clock.schedule_once(self._complete_dispatcher, self.temporal_window)\n\n# -----------------------------------------------------------------------------\n# Gesture related methods\n# -----------------------------------------------------------------------------\n    def init_gesture(self, touch):\n        '''Create a new gesture from touch, ie it's the first on\n        surface, or was not close enough to any existing gesture (yet)'''\n        col = self.color\n        if self.use_random_color is True:\n            col = hsv_to_rgb(random(), 1., 1.)\n\n        g = GestureContainer(touch, max_strokes=self.max_strokes,\n                             line_width=self.line_width, color=col)\n\n        # Create the bounding box Rectangle for the gesture\n        if self.draw_bbox:\n            bb = g.bbox\n            with self.canvas:\n                Color(col[0], col[1], col[2], self.bbox_alpha, mode='rgba',\n                      group=g.id)\n\n                g._bbrect = Rectangle(\n                    group=g.id,\n                    pos=(bb['minx'], bb['miny']),\n                    size=(bb['maxx'] - bb['minx'],\n                          bb['maxy'] - bb['miny']))\n\n        self._gestures.append(g)\n        return g\n\n    def init_stroke(self, g, touch):\n        l = [touch.x, touch.y]\n        col = g.color\n\n        new_line = Line(\n            points=l,\n            width=self.line_width,\n            group=g.id)\n        g._strokes[str(touch.uid)] = new_line\n\n        if self.line_width:\n            canvas_add = self.canvas.add\n            canvas_add(Color(col[0], col[1], col[2], mode='rgb', group=g.id))\n            canvas_add(new_line)\n\n        # Update the bbox in case; this will normally be done in on_touch_move,\n        # but we want to update it also for a single press, force that here:\n        g.update_bbox(touch)\n        if self.draw_bbox:\n            self._update_canvas_bbox(g)\n\n        # Register the stroke in GestureContainer so we can look it up later\n        g.add_stroke(touch, new_line)\n\n    def get_gesture(self, touch):\n        '''Returns GestureContainer associated with given touch'''\n        for g in self._gestures:\n            if g.active and g.handles(touch):\n                return g\n        raise Exception('get_gesture() failed to identify ' + str(touch.uid))\n\n    def find_colliding_gesture(self, touch):\n        '''Checks if a touch x/y collides with the bounding box of an existing\n        gesture. If so, return it (otherwise returns None)\n        '''\n        touch_x, touch_y = touch.pos\n        for g in self._gestures:\n            if g.active and not g.handles(touch) and g.accept_stroke():\n                bb = g.bbox\n                margin = self.bbox_margin\n                minx = bb['minx'] - margin\n                miny = bb['miny'] - margin\n                maxx = bb['maxx'] + margin\n                maxy = bb['maxy'] + margin\n                if minx <= touch_x <= maxx and miny <= touch_y <= maxy:\n                    return g\n        return None\n\n    def merge_gestures(self, g, other):\n        '''Merges two gestures together, the oldest one is retained and the\n        newer one gets the `GestureContainer.was_merged` flag raised.'''\n        # Swap order depending on gesture age (the merged gesture gets\n        # the color from the oldest one of the two).\n        swap = other._create_time < g._create_time\n        a = swap and other or g\n        b = swap and g or other\n\n        # Apply the outer limits of bbox to the merged gesture\n        abbox = a.bbox\n        bbbox = b.bbox\n        if bbbox['minx'] < abbox['minx']:\n            abbox['minx'] = bbbox['minx']\n        if bbbox['miny'] < abbox['miny']:\n            abbox['miny'] = bbbox['miny']\n        if bbbox['maxx'] > abbox['maxx']:\n            abbox['maxx'] = bbbox['maxx']\n        if bbbox['maxy'] > abbox['maxy']:\n            abbox['maxy'] = bbbox['maxy']\n\n        # Now transfer the coordinates from old to new gesture;\n        # FIXME: This can probably be copied more efficiently?\n        astrokes = a._strokes\n        lw = self.line_width\n        a_id = a.id\n        col = a.color\n\n        self.canvas.remove_group(b.id)\n        canv_add = self.canvas.add\n        for uid, old in b._strokes.items():\n            # FIXME: Can't figure out how to change group= for existing Line()\n            new_line = Line(\n                points=old.points,\n                width=old.width,\n                group=a_id)\n            astrokes[uid] = new_line\n            if lw:\n                canv_add(Color(col[0], col[1], col[2], mode='rgb', group=a_id))\n                canv_add(new_line)\n\n        b.active = False\n        b.was_merged = True\n        a.active_strokes += b.active_strokes\n        a._update_time = Clock.get_time()\n        return a\n\n    def _update_canvas_bbox(self, g):\n        # If draw_bbox is changed while two gestures are active,\n        # we might not have a bbrect member\n        if not hasattr(g, '_bbrect'):\n            return\n\n        bb = g.bbox\n        g._bbrect.pos = (bb['minx'], bb['miny'])\n        g._bbrect.size = (bb['maxx'] - bb['minx'],\n                          bb['maxy'] - bb['miny'])\n\n# -----------------------------------------------------------------------------\n# Timeout callbacks\n# -----------------------------------------------------------------------------\n    def _complete_dispatcher(self, dt):\n        '''This method is scheduled on all touch up events. It will dispatch\n        the `on_gesture_complete` event for all completed gestures, and remove\n        merged gestures from the internal gesture list.'''\n        need_cleanup = False\n        gest = self._gestures\n        timeout = self.draw_timeout\n        twin = self.temporal_window\n        get_time = Clock.get_time\n\n        for idx, g in enumerate(gest):\n            # Gesture is part of another gesture, just delete it\n            if g.was_merged:\n                del gest[idx]\n                continue\n\n            # Not active == already handled, or has active strokes (it cannot\n            # possibly be complete). Proceed to next gesture on surface.\n            if not g.active or g.active_strokes != 0:\n                continue\n\n            t1 = g._update_time + twin\n            t2 = get_time() + UNDERSHOOT_MARGIN\n\n            # max_strokes reached, or temporal window has expired. The gesture\n            # is complete; need to dispatch _complete or _discard event.\n            if not g.accept_stroke() or t1 <= t2:\n                discard = False\n                if g.width < 5 and g.height < 5:\n                    discard = True\n                elif g.single_points_test():\n                    discard = True\n\n                need_cleanup = True\n                g.active = False\n                g._cleanup_time = get_time() + timeout\n\n                if discard:\n                    self.dispatch('on_gesture_discard', g)\n                else:\n                    self.dispatch('on_gesture_complete', g)\n\n        if need_cleanup:\n            Clock.schedule_once(self._cleanup, timeout)\n\n    def _cleanup(self, dt):\n        '''This method is scheduled from _complete_dispatcher to clean up the\n        canvas and internal gesture list after a gesture is completed.'''\n        m = UNDERSHOOT_MARGIN\n        rg = self.canvas.remove_group\n        gestures = self._gestures\n        for idx, g in enumerate(gestures):\n            if g._cleanup_time is None:\n                continue\n            if g._cleanup_time <= Clock.get_time() + m:\n                rg(g.id)\n                del gestures[idx]\n                self.dispatch('on_gesture_cleanup', g)\n\n    def on_gesture_start(self, *l):\n        pass\n\n    def on_gesture_extend(self, *l):\n        pass\n\n    def on_gesture_merge(self, *l):\n        pass\n\n    def on_gesture_complete(self, *l):\n        pass\n\n    def on_gesture_discard(self, *l):\n        pass\n\n    def on_gesture_cleanup(self, *l):\n        pass\n"
  },
  {
    "path": "tickeys/kivy/uix/gridlayout.py",
    "content": "'''\nGrid Layout\n===========\n\n.. only:: html\n\n    .. image:: images/gridlayout.gif\n        :align: right\n\n.. only:: latex\n\n    .. image:: images/gridlayout.png\n        :align: right\n\n.. versionadded:: 1.0.4\n\nThe :class:`GridLayout` arranges children in a matrix. It takes the available\nspace and divides it into columns and rows, then adds widgets to the resulting\n\"cells\".\n\n.. versionchanged:: 1.0.7\n    The implementation has changed to use the widget size_hint for calculating\n    column/row sizes. `uniform_width` and `uniform_height` have been removed\n    and other properties have added to give you more control.\n\nBackground\n----------\n\nUnlike many other toolkits, you cannot explicitly place a widget in a specific\ncolumn/row. Each child is automatically assigned a position determined by the\nlayout configuration and the child's index in the children list.\n\nA GridLayout must always have at least one input constraint:\n:attr:`GridLayout.cols` or :attr:`GridLayout.rows`. If you do not specify cols\nor rows, the Layout will throw an exception.\n\nColumn Width and Row Height\n---------------------------\n\nThe column width/row height are determined in 3 steps:\n\n    - The initial size is given by the :attr:`col_default_width` and\n      :attr:`row_default_height` properties. To customize the size of a single\n      column or row, use :attr:`cols_minimum` or :attr:`rows_minimum`.\n    - The `size_hint_x`/`size_hint_y` of the children are taken into account.\n      If no widgets have a size hint, the maximum size is used for all\n      children.\n    - You can force the default size by setting the :attr:`col_force_default`\n      or :attr:`row_force_default` property. This will force the layout to\n      ignore the `width` and `size_hint` properties of children and use the\n      default size.\n\nUsing a GridLayout\n------------------\n\nIn the example below, all widgets will have an equal size. By default, the\n`size_hint` is (1, 1), so a Widget will take the full size of the parent::\n\n    layout = GridLayout(cols=2)\n    layout.add_widget(Button(text='Hello 1'))\n    layout.add_widget(Button(text='World 1'))\n    layout.add_widget(Button(text='Hello 2'))\n    layout.add_widget(Button(text='World 2'))\n\n.. image:: images/gridlayout_1.jpg\n\nNow, let's fix the size of Hello buttons to 100px instead of using\nsize_hint_x=1::\n\n    layout = GridLayout(cols=2)\n    layout.add_widget(Button(text='Hello 1', size_hint_x=None, width=100))\n    layout.add_widget(Button(text='World 1'))\n    layout.add_widget(Button(text='Hello 2', size_hint_x=None, width=100))\n    layout.add_widget(Button(text='World 2'))\n\n.. image:: images/gridlayout_2.jpg\n\nNext, let's fix the row height to a specific size::\n\n    layout = GridLayout(cols=2, row_force_default=True, row_default_height=40)\n    layout.add_widget(Button(text='Hello 1', size_hint_x=None, width=100))\n    layout.add_widget(Button(text='World 1'))\n    layout.add_widget(Button(text='Hello 2', size_hint_x=None, width=100))\n    layout.add_widget(Button(text='World 2'))\n\n.. image:: images/gridlayout_3.jpg\n\n'''\n\n__all__ = ('GridLayout', 'GridLayoutException')\n\nfrom kivy.logger import Logger\nfrom kivy.uix.layout import Layout\nfrom kivy.properties import NumericProperty, BooleanProperty, DictProperty, \\\n    BoundedNumericProperty, ReferenceListProperty, VariableListProperty\nfrom math import ceil\n\n\ndef nmax(*args):\n    '''(internal) Implementation of a max() function that supports None.\n    '''\n    # merge into one list\n    args = [x for x in args if x is not None]\n    return max(args)\n\n\nclass GridLayoutException(Exception):\n    '''Exception for errors if the grid layout manipulation fails.\n    '''\n    pass\n\n\nclass GridLayout(Layout):\n    '''Grid layout class. See module documentation for more information.\n    '''\n\n    spacing = VariableListProperty([0, 0], length=2)\n    '''Spacing between children: [spacing_horizontal, spacing_vertical].\n\n    spacing also accepts a one argument form [spacing].\n\n    :attr:`spacing` is a\n    :class:`~kivy.properties.VariableListProperty` and defaults to [0, 0].\n    '''\n\n    padding = VariableListProperty([0, 0, 0, 0])\n    '''Padding between the layout box and it's children: [padding_left,\n    padding_top, padding_right, padding_bottom].\n\n    padding also accepts a two argument form [padding_horizontal,\n    padding_vertical] and a one argument form [padding].\n\n    .. versionchanged:: 1.7.0\n        Replaced NumericProperty with VariableListProperty.\n\n    :attr:`padding` is a :class:`~kivy.properties.VariableListProperty` and\n    defaults to [0, 0, 0, 0].\n    '''\n\n    cols = BoundedNumericProperty(None, min=0, allownone=True)\n    '''Number of columns in the grid.\n\n    .. versionchanged:: 1.0.8\n        Changed from a NumericProperty to BoundedNumericProperty. You can no\n        longer set this to a negative value.\n\n    :attr:`cols` is a :class:`~kivy.properties.NumericProperty` and defaults to\n    0.\n    '''\n\n    rows = BoundedNumericProperty(None, min=0, allownone=True)\n    '''Number of rows in the grid.\n\n    .. versionchanged:: 1.0.8\n        Changed from a NumericProperty to a BoundedNumericProperty. You can no\n        longer set this to a negative value.\n\n    :attr:`rows` is a :class:`~kivy.properties.NumericProperty` and defaults to\n    0.\n    '''\n\n    col_default_width = NumericProperty(0)\n    '''Default minimum size to use for a column.\n\n    .. versionadded:: 1.0.7\n\n    :attr:`col_default_width` is a :class:`~kivy.properties.NumericProperty`\n    and defaults to 0.\n    '''\n\n    row_default_height = NumericProperty(0)\n    '''Default minimum size to use for row.\n\n    .. versionadded:: 1.0.7\n\n    :attr:`row_default_height` is a :class:`~kivy.properties.NumericProperty`\n    and defaults to 0.\n    '''\n\n    col_force_default = BooleanProperty(False)\n    '''If True, ignore the width and size_hint_x of the child and use the\n    default column width.\n\n    .. versionadded:: 1.0.7\n\n    :attr:`col_force_default` is a :class:`~kivy.properties.BooleanProperty`\n    and defaults to False.\n    '''\n\n    row_force_default = BooleanProperty(False)\n    '''If True, ignore the height and size_hint_y of the child and use the\n    default row height.\n\n    .. versionadded:: 1.0.7\n\n    :attr:`row_force_default` is a :class:`~kivy.properties.BooleanProperty`\n    and defaults to False.\n    '''\n\n    cols_minimum = DictProperty({})\n    '''List of minimum sizes for each column.\n\n    .. versionadded:: 1.0.7\n\n    :attr:`cols_minimum` is a :class:`~kivy.properties.DictProperty` and\n    defaults to {}.\n    '''\n\n    rows_minimum = DictProperty({})\n    '''List of minimum sizes for each row.\n\n    .. versionadded:: 1.0.7\n\n    :attr:`rows_minimum` is a :class:`~kivy.properties.DictProperty` and\n    defaults to {}.\n    '''\n\n    minimum_width = NumericProperty(0)\n    '''Minimum width needed to contain all children.\n\n    .. versionadded:: 1.0.8\n\n    :attr:`minimum_width` is a :class:`kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    minimum_height = NumericProperty(0)\n    '''Minimum height needed to contain all children.\n\n    .. versionadded:: 1.0.8\n\n    :attr:`minimum_height` is a :class:`kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    minimum_size = ReferenceListProperty(minimum_width, minimum_height)\n    '''Minimum size needed to contain all children.\n\n    .. versionadded:: 1.0.8\n\n    :attr:`minimum_size` is a\n    :class:`~kivy.properties.ReferenceListProperty` of\n    (:attr:`minimum_width`, :attr:`minimum_height`) properties.\n    '''\n\n    def __init__(self, **kwargs):\n        self._cols = self._rows = None\n        super(GridLayout, self).__init__(**kwargs)\n\n        self.bind(\n            col_default_width=self._trigger_layout,\n            row_default_height=self._trigger_layout,\n            col_force_default=self._trigger_layout,\n            row_force_default=self._trigger_layout,\n            cols=self._trigger_layout,\n            rows=self._trigger_layout,\n            parent=self._trigger_layout,\n            spacing=self._trigger_layout,\n            padding=self._trigger_layout,\n            children=self._trigger_layout,\n            size=self._trigger_layout,\n            pos=self._trigger_layout)\n\n    def get_max_widgets(self):\n        if self.cols and not self.rows:\n            return None\n        if self.rows and not self.cols:\n            return None\n        if not self.cols and not self.rows:\n            return None\n        return self.rows * self.cols\n\n    def on_children(self, instance, value):\n        # if that makes impossible to construct things with deffered method,\n        # migrate this test in do_layout, and/or issue a warning.\n        smax = self.get_max_widgets()\n        if smax and len(value) > smax:\n            raise GridLayoutException(\n                'Too many children in GridLayout. Increase rows/cols!')\n\n    def update_minimum_size(self, *largs):\n        # the goal here is to calculate the minimum size of every cols/rows\n        # and determine if they have stretch or not\n        current_cols = self.cols\n        current_rows = self.rows\n        children = self.children\n        len_children = len(children)\n\n        # if no cols or rows are set, we can't calculate minimum size.\n        # the grid must be contrained at least on one side\n        if not current_cols and not current_rows:\n            Logger.warning('%r have no cols or rows set, '\n                           'layout is not triggered.' % self)\n            return None\n        if current_cols is None:\n            current_cols = int(ceil(len_children / float(current_rows)))\n        elif current_rows is None:\n            current_rows = int(ceil(len_children / float(current_cols)))\n\n        current_cols = max(1, current_cols)\n        current_rows = max(1, current_rows)\n\n        cols = [self.col_default_width] * current_cols\n        cols_sh = [None] * current_cols\n        rows = [self.row_default_height] * current_rows\n        rows_sh = [None] * current_rows\n\n        # update minimum size from the dicts\n        # FIXME index might be outside the bounds ?\n        for index, value in self.cols_minimum.items():\n            cols[index] = value\n        for index, value in self.rows_minimum.items():\n            rows[index] = value\n\n        # calculate minimum size for each columns and rows\n        i = len_children - 1\n        for row in range(current_rows):\n            for col in range(current_cols):\n\n                # don't go further is we don't have child left\n                if i < 0:\n                    break\n\n                # get initial information from the child\n                c = children[i]\n                shw = c.size_hint_x\n                shh = c.size_hint_y\n                w = c.width\n                h = c.height\n\n                # compute minimum size / maximum stretch needed\n                if shw is None:\n                    cols[col] = nmax(cols[col], w)\n                else:\n                    cols_sh[col] = nmax(cols_sh[col], shw)\n                if shh is None:\n                    rows[row] = nmax(rows[row], h)\n                else:\n                    rows_sh[row] = nmax(rows_sh[row], shh)\n\n                # next child\n                i = i - 1\n\n        # calculate minimum width/height needed, starting from padding +\n        # spacing\n        padding_x = self.padding[0] + self.padding[2]\n        padding_y = self.padding[1] + self.padding[3]\n        spacing_x, spacing_y = self.spacing\n        width = padding_x + spacing_x * (current_cols - 1)\n        height = padding_y + spacing_y * (current_rows - 1)\n        # then add the cell size\n        width += sum(cols)\n        height += sum(rows)\n\n        # remember for layout\n        self._cols = cols\n        self._rows = rows\n        self._cols_sh = cols_sh\n        self._rows_sh = rows_sh\n\n        # finally, set the minimum size\n        self.minimum_size = (width, height)\n\n    def do_layout(self, *largs):\n        self.update_minimum_size()\n        if self._cols is None:\n            return\n        if self.cols is None and self.rows is None:\n            raise GridLayoutException('Need at least cols or rows constraint.')\n\n        children = self.children\n        len_children = len(children)\n        if len_children == 0:\n            return\n\n        # speedup\n        padding_left = self.padding[0]\n        padding_top = self.padding[1]\n        spacing_x, spacing_y = self.spacing\n        selfx = self.x\n        selfw = self.width\n        selfh = self.height\n\n        # resolve size for each column\n        if self.col_force_default:\n            cols = [self.col_default_width] * len(self._cols)\n            for index, value in self.cols_minimum.items():\n                cols[index] = value\n        else:\n            cols = self._cols[:]\n            cols_sh = self._cols_sh\n            cols_weigth = sum([x for x in cols_sh if x])\n            strech_w = max(0, selfw - self.minimum_width)\n            for index in range(len(cols)):\n                # if the col don't have strech information, nothing to do\n                col_stretch = cols_sh[index]\n                if col_stretch is None:\n                    continue\n                # calculate the column stretch, and take the maximum from\n                # minimum size and the calculated stretch\n                col_width = cols[index]\n                col_width = max(col_width,\n                                strech_w * col_stretch / cols_weigth)\n                cols[index] = col_width\n\n        # same algo for rows\n        if self.row_force_default:\n            rows = [self.row_default_height] * len(self._rows)\n            for index, value in self.rows_minimum.items():\n                rows[index] = value\n        else:\n            rows = self._rows[:]\n            rows_sh = self._rows_sh\n            rows_weigth = sum([x for x in rows_sh if x])\n            strech_h = max(0, selfh - self.minimum_height)\n            for index in range(len(rows)):\n                # if the row don't have strech information, nothing to do\n                row_stretch = rows_sh[index]\n                if row_stretch is None:\n                    continue\n                # calculate the row stretch, and take the maximum from minimum\n                # size and the calculated stretch\n                row_height = rows[index]\n                row_height = max(row_height,\n                                 strech_h * row_stretch / rows_weigth)\n                rows[index] = row_height\n\n        # reposition every child\n        i = len_children - 1\n        y = self.top - padding_top\n        for row_height in rows:\n            x = selfx + padding_left\n            for col_width in cols:\n                if i < 0:\n                    break\n                c = children[i]\n                c.x = x\n                c.y = y - row_height\n                c.width = col_width\n                c.height = row_height\n                i = i - 1\n                x = x + col_width + spacing_x\n            y -= row_height + spacing_y\n"
  },
  {
    "path": "tickeys/kivy/uix/image.py",
    "content": "'''\nImage\n=====\n\nThe :class:`Image` widget is used to display an image::\n\n    wimg = Image(source='mylogo.png')\n\nAsynchronous Loading\n--------------------\n\nTo load an image asynchronously (for example from an external webserver), use\nthe :class:`AsyncImage` subclass::\n\n    aimg = AsyncImage(source='http://mywebsite.com/logo.png')\n\nThis can be useful as it prevents your application from waiting until the image\nis loaded. If you want to display large images or retrieve them from URL's,\nusing :class:`AsyncImage` will allow these resources to be retrieved on a\nbackground thread without blocking your application.\n\nAlignment\n---------\n\nBy default, the image is centered and fits inside the widget bounding box.\nIf you don't want that, you can set `allow_stretch` to True and `keep_ratio`\nto False.\n\nYou can also inherit from Image and create your own style.\n\n\nFor example, if you want your image to be greater than,the size of your widget,\nyou could do::\n\n    class FullImage(Image):\n        pass\n\nAnd in your kivy language file::\n\n    <-FullImage>:\n        canvas:\n            Color:\n                rgb: (1, 1, 1)\n            Rectangle:\n                texture: self.texture\n                size: self.width + 20, self.height + 20\n                pos: self.x - 10, self.y - 10\n\n'''\n\n__all__ = ('Image', 'AsyncImage')\n\nfrom kivy.uix.widget import Widget\nfrom kivy.core.image import Image as CoreImage\nfrom kivy.resources import resource_find\nfrom kivy.properties import StringProperty, ObjectProperty, ListProperty, \\\n    AliasProperty, BooleanProperty, NumericProperty\nfrom kivy.logger import Logger\n\n# delayed imports\nLoader = None\n\n\nclass Image(Widget):\n    '''Image class, see module documentation for more information.\n    '''\n\n    source = StringProperty(None)\n    '''Filename / source of your image.\n\n    :attr:`source` is a :class:`~kivy.properties.StringProperty` and\n    defaults to None.\n    '''\n\n    texture = ObjectProperty(None, allownone=True)\n    '''Texture object of the image.\n\n    Depending of the texture creation, the value will be a\n    :class:`~kivy.graphics.texture.Texture` or a\n    :class:`~kivy.graphics.texture.TextureRegion` object.\n\n    :attr:`texture` is a :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    texture_size = ListProperty([0, 0])\n    '''Texture size of the image.\n\n    .. warning::\n\n        The texture size is set after the texture property. So if you listen to\n        the change on :attr:`texture`, the property texture_size will not be\n        up-to-date. Use self.texture.size instead.\n    '''\n\n    def get_image_ratio(self):\n        if self.texture:\n            return self.texture.width / float(self.texture.height)\n        return 1.\n\n    mipmap = BooleanProperty(False)\n    '''Indicate if you want OpenGL mipmapping to be applied to the texture.\n    Read :ref:`mipmap` for more information.\n\n    .. versionadded:: 1.0.7\n\n    :attr:`mipmap` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    image_ratio = AliasProperty(get_image_ratio, None, bind=('texture', ))\n    '''Ratio of the image (width / float(height).\n\n    :attr:`image_ratio` is a :class:`~kivy.properties.AliasProperty` and is\n    read-only.\n    '''\n\n    color = ListProperty([1, 1, 1, 1])\n    '''Image color, in the format (r, g, b, a). This attribute can be used to\n    'tint' an image. Be careful: if the source image is not gray/white, the\n    color will not really work as expected.\n\n    .. versionadded:: 1.0.6\n\n    :attr:`color` is a :class:`~kivy.properties.ListProperty` and defaults to\n    [1, 1, 1, 1].\n    '''\n\n    allow_stretch = BooleanProperty(False)\n    '''If True, the normalized image size will be maximized to fit in the image\n    box. Otherwise, if the box is too tall, the image will not be\n    stretched more than 1:1 pixels.\n\n    .. versionadded:: 1.0.7\n\n    :attr:`allow_stretch` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    keep_ratio = BooleanProperty(True)\n    '''If False along with allow_stretch being True, the normalized image\n    size will be maximized to fit in the image box and ignores the aspect\n    ratio of the image.\n    Otherwise, if the box is too tall, the image will not be stretched more\n    than 1:1 pixels.\n\n    .. versionadded:: 1.0.8\n\n    :attr:`keep_ratio` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n\n    keep_data = BooleanProperty(False)\n    '''If True, the underlaying _coreimage will store the raw image data.\n    This is useful when performing pixel based collision detection.\n\n    .. versionadded:: 1.3.0\n\n    :attr:`keep_data` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    anim_delay = NumericProperty(.25)\n    '''Delay the animation if the image is sequenced (like an animated gif).\n    If anim_delay is set to -1, the animation will be stopped.\n\n    .. versionadded:: 1.0.8\n\n    :attr:`anim_delay` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.25 (4 FPS).\n    '''\n\n    anim_loop = NumericProperty(0)\n    '''Number of loops to play then stop animating. 0 means keep animating.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`anim_loop` is a :class:`~kivy.properties.NumericProperty` defaults\n    to 0.\n    '''\n\n    nocache = BooleanProperty(False)\n    '''If this property is set True, the image will not be added to the\n    internal cache. The cache will simply ignore any calls trying to\n    append the core image.\n\n    .. versionadded:: 1.6.0\n\n    :attr:`nocache` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    def get_norm_image_size(self):\n        if not self.texture:\n            return self.size\n        ratio = self.image_ratio\n        w, h = self.size\n        tw, th = self.texture.size\n\n        # ensure that the width is always maximized to the containter width\n        if self.allow_stretch:\n            if not self.keep_ratio:\n                return w, h\n            iw = w\n        else:\n            iw = min(w, tw)\n        # calculate the appropriate height\n        ih = iw / ratio\n        # if the height is too higher, take the height of the container\n        # and calculate appropriate width. no need to test further. :)\n        if ih > h:\n            if self.allow_stretch:\n                ih = h\n            else:\n                ih = min(h, th)\n            iw = ih * ratio\n\n        return iw, ih\n\n    norm_image_size = AliasProperty(get_norm_image_size, None, bind=(\n        'texture', 'size', 'image_ratio', 'allow_stretch'))\n    '''Normalized image size within the widget box.\n\n    This size will always fit the widget size and will preserve the image\n    ratio.\n\n    :attr:`norm_image_size` is a :class:`~kivy.properties.AliasProperty` and is\n    read-only.\n    '''\n\n    def __init__(self, **kwargs):\n        self._coreimage = None\n        self._loops = 0\n        super(Image, self).__init__(**kwargs)\n        self.bind(source=self.texture_update,\n                  mipmap=self.texture_update)\n        if self.source:\n            self.texture_update()\n\n    def texture_update(self, *largs):\n        if not self.source:\n            self.texture = None\n        else:\n            filename = resource_find(self.source)\n            self._loops = 0\n            if filename is None:\n                return Logger.error('Image: Error reading file {filename}'.\n                                    format(filename=self.source))\n            mipmap = self.mipmap\n            if self._coreimage is not None:\n                self._coreimage.unbind(on_texture=self._on_tex_change)\n            try:\n                self._coreimage = ci = CoreImage(filename, mipmap=mipmap,\n                                                 anim_delay=self.anim_delay,\n                                                 keep_data=self.keep_data,\n                                                 nocache=self.nocache)\n            except:\n                self._coreimage = ci = None\n\n            if ci:\n                ci.bind(on_texture=self._on_tex_change)\n                self.texture = ci.texture\n\n    def on_anim_delay(self, instance, value):\n        self._loop = 0\n        if self._coreimage is None:\n            return\n        self._coreimage.anim_delay = value\n        if value < 0:\n            self._coreimage.anim_reset(False)\n\n    def on_texture(self, instance, value):\n        if value is not None:\n            self.texture_size = list(value.size)\n\n    def _on_tex_change(self, *largs):\n        # update texture from core image\n        self.texture = self._coreimage.texture\n        ci = self._coreimage\n        if self.anim_loop and ci._anim_index == len(ci._image.textures) - 1:\n            self._loops += 1\n            if self.anim_loop == self._loops:\n                ci.anim_reset(False)\n                self._loops = 0\n\n    def reload(self):\n        '''Reload image from disk. This facilitates re-loading of\n        images from disk in case the image content changes.\n\n        .. versionadded:: 1.3.0\n\n        Usage::\n\n            im = Image(source = '1.jpg')\n            # -- do something --\n            im.reload()\n            # image will be re-loaded from disk\n\n        '''\n        self._coreimage.remove_from_cache()\n        olsource = self.source\n        self.source = ''\n        self.source = olsource\n\n    def on_nocache(self, *args):\n        if self.nocache and self._coreimage:\n            self._coreimage.remove_from_cache()\n            self._coreimage._nocache = True\n\n\nclass AsyncImage(Image):\n    '''Asynchronous Image class. See the module documentation for more\n    information.\n\n    .. note::\n\n        The AsyncImage is a specialized form of the Image class. You may\n        want to refer to the :mod:`~kivy.loader` documentation and in\n        particular, the :class:`~kivy.loader.ProxyImage` for more detail\n        on how to handle events around asynchronous image loading.\n    '''\n\n    def __init__(self, **kwargs):\n        self._coreimage = None\n        super(AsyncImage, self).__init__(**kwargs)\n        global Loader\n        if not Loader:\n            from kivy.loader import Loader\n        self.bind(source=self._load_source)\n        if self.source:\n            self._load_source()\n\n    def _load_source(self, *args):\n        source = self.source\n        if not source:\n            if self._coreimage is not None:\n                self._coreimage.unbind(on_texture=self._on_tex_change)\n            self.texture = None\n            self._coreimage = None\n        else:\n            if not self.is_uri(source):\n                source = resource_find(source)\n            self._coreimage = image = Loader.image(source,\n                nocache=self.nocache, mipmap=self.mipmap,\n                anim_delay=self.anim_delay)\n            image.bind(on_load=self._on_source_load)\n            image.bind(on_texture=self._on_tex_change)\n            self.texture = image.texture\n\n    def _on_source_load(self, value):\n        image = self._coreimage.image\n        if not image:\n            return\n        self.texture = image.texture\n\n    def is_uri(self, filename):\n        proto = filename.split('://', 1)[0]\n        return proto in ('http', 'https', 'ftp', 'smb')\n\n    def _on_tex_change(self, *largs):\n        if self._coreimage:\n            self.texture = self._coreimage.texture\n\n    def texture_update(self, *largs):\n        pass\n"
  },
  {
    "path": "tickeys/kivy/uix/label.py",
    "content": "'''\nLabel\n=====\n\nThe :class:`Label` widget is for rendering text. It supports ascii and unicode\nstrings::\n\n    # hello world text\n    l = Label(text='Hello world')\n\n    # unicode text; can only display glyphs that are available in the font\n    l = Label(text=u'Hello world ' + unichr(2764))\n\n    # multiline text\n    l = Label(text='Multi\\\\nLine')\n\n    # size\n    l = Label(text='Hello world', font_size='20sp')\n\nMarkup text\n-----------\n\n.. versionadded:: 1.1.0\n\nYou can change the style of the text using :doc:`api-kivy.core.text.markup`.\nThe syntax is similar to the bbcode syntax but only the inline styling is\nallowed::\n\n    # hello world with world in bold\n    l = Label(text='Hello [b]World[/b]', markup=True)\n\n    # hello in red, world in blue\n    l = Label(text='[color=ff3333]Hello[/color][color=3333ff]World[/color]',\n        markup = True)\n\nIf you need to escape the markup from the current text, use\n:func:`kivy.utils.escape_markup`::\n\n    text = 'This is an important message [1]'\n    l = Label(text='[b]' + escape_markup(text) + '[/b]', markup=True)\n\nThe following tags are available:\n\n``[b][/b]``\n    Activate bold text\n``[i][/i]``\n    Activate italic text\n``[font=<str>][/font]``\n    Change the font\n``[size=<integer>][/size]``\n    Change the font size\n``[color=#<color>][/color]``\n    Change the text color\n``[ref=<str>][/ref]``\n    Add an interactive zone. The reference + bounding box inside the\n    reference will be available in :attr:`Label.refs`\n``[anchor=<str>]``\n    Put an anchor in the text. You can get the position of your anchor within\n    the text with :attr:`Label.anchors`\n``[sub][/sub]``\n    Display the text at a subscript position relative to the text before it.\n``[sup][/sup]``\n    Display the text at a superscript position relative to the text before it.\n\nIf you want to render the markup text with a [ or ] or & character, you need to\nescape them. We created a simple syntax::\n\n    [   -> &bl;\n    ]   -> &br;\n    &   -> &amp;\n\nThen you can write::\n\n    \"[size=24]Hello &bl;World&bt;[/size]\"\n\nInteractive Zone in Text\n------------------------\n\n.. versionadded:: 1.1.0\n\nYou can now have definable \"links\" using text markup. The idea is to be able\nto detect when the user clicks on part of the text and to react.\nThe tag ``[ref=xxx]`` is used for that.\n\nIn this example, we are creating a reference on the word \"World\". When\nthis word is clicked, the function ``print_it`` will be called with the\nname of the reference::\n\n    def print_it(instance, value):\n        print('User clicked on', value)\n    widget = Label(text='Hello [ref=world]World[/ref]', markup=True)\n    widget.bind(on_ref_press=print_it)\n\nFor prettier rendering, you could add a color for the reference. Replace the\n``text=`` in the previous example with::\n\n    'Hello [ref=world][color=0000ff]World[/color][/ref]'\n\nUsage example\n-------------\n\nThe following example marks the anchors and references contained in a label::\n\n    from kivy.app import App\n    from kivy.uix.label import Label\n    from kivy.clock import Clock\n    from kivy.graphics import Color, Rectangle\n\n\n    class TestApp(App):\n\n        @staticmethod\n        def get_x(label, ref_x):\n            \"\"\" Return the x value of the ref/anchor relative to the canvas \"\"\"\n            return label.center_x - label.texture_size[0] * 0.5 + ref_x\n\n        @staticmethod\n        def get_y(label, ref_y):\n            \"\"\" Return the y value of the ref/anchor relative to the canvas \"\"\"\n            # Note the inversion of direction, as y values start at the top of\n            # the texture and increase downwards\n            return label.center_y + label.texture_size[1] * 0.5 - ref_y\n\n        def show_marks(self, label):\n\n            # Indicate the position of the anchors with a red top marker\n            for name, anc in label.anchors.items():\n                with label.canvas:\n                    Color(1, 0, 0)\n                    Rectangle(pos=(self.get_x(label, anc[0]),\n                                   self.get_y(label, anc[1])),\n                              size=(3, 3))\n\n            # Draw a green surround around the refs. Note the sizes y inversion\n            for name, boxes in label.refs.items():\n                for box in boxes:\n                    with label.canvas:\n                        Color(0, 1, 0, 0.25)\n                        Rectangle(pos=(self.get_x(label, box[0]),\n                                       self.get_y(label, box[1])),\n                                  size=(box[2] - box[0],\n                                        box[1] - box[3]))\n\n        def build(self):\n            label = Label(\n                text='[anchor=a]a\\\\nChars [anchor=b]b\\\\n[ref=myref]ref[/ref]',\n                markup=True)\n            Clock.schedule_once(lambda dt: self.show_marks(label), 1)\n            return label\n\n    TestApp().run()\n\n'''\n\n__all__ = ('Label', )\n\nfrom functools import partial\nfrom kivy.clock import Clock\nfrom kivy.uix.widget import Widget\nfrom kivy.core.text import Label as CoreLabel\nfrom kivy.core.text.markup import MarkupLabel as CoreMarkupLabel\nfrom kivy.properties import StringProperty, OptionProperty, \\\n    NumericProperty, BooleanProperty, ReferenceListProperty, \\\n    ListProperty, ObjectProperty, DictProperty\nfrom kivy.utils import get_hex_from_color\n\n\nclass Label(Widget):\n    '''Label class, see module documentation for more information.\n\n    :Events:\n        `on_ref_press`\n            Fired when the user clicks on a word referenced with a\n            ``[ref]`` tag in a text markup.\n    '''\n\n    __events__ = ['on_ref_press']\n\n    _font_properties = ('text', 'font_size', 'font_name', 'bold', 'italic',\n                        'halign', 'valign', 'padding_x', 'padding_y',\n                        'text_size', 'shorten', 'mipmap', 'markup',\n                        'line_height', 'max_lines', 'strip', 'shorten_from',\n                        'split_str', 'unicode_errors')\n\n    def __init__(self, **kwargs):\n        self._trigger_texture = Clock.create_trigger(self.texture_update, -1)\n        super(Label, self).__init__(**kwargs)\n\n        # bind all the property for recreating the texture\n        d = Label._font_properties\n        dkw = {}\n        for x in d:\n            dkw[x] = partial(self._trigger_texture_update, x)\n        self.bind(**dkw)\n\n        self._label = None\n        self._create_label()\n\n        # force the texture creation\n        self._trigger_texture()\n\n    def _create_label(self):\n        # create the core label class according to markup value\n        if self._label is not None:\n            cls = self._label.__class__\n        else:\n            cls = None\n        markup = self.markup\n        if (markup and cls is not CoreMarkupLabel) or \\\n           (not markup and cls is not CoreLabel):\n            # markup have change, we need to change our rendering method.\n            d = Label._font_properties\n            dkw = dict(list(zip(d, [getattr(self, x) for x in d])))\n            if markup:\n                self._label = CoreMarkupLabel(**dkw)\n            else:\n                self._label = CoreLabel(**dkw)\n\n    def _trigger_texture_update(self, name=None, source=None, value=None):\n        # check if the label core class need to be switch to a new one\n        if name == 'markup':\n            self._create_label()\n        if source:\n            if name == 'text':\n                self._label.text = value\n            elif name == 'text_size':\n                self._label.usersize = value\n            elif name == 'font_size':\n                self._label.options[name] = value\n            else:\n                self._label.options[name] = value\n        self._trigger_texture()\n\n    def texture_update(self, *largs):\n        '''Force texture recreation with the current Label properties.\n\n        After this function call, the :attr:`texture` and :attr:`texture_size`\n        will be updated in this order.\n        '''\n        mrkup = self._label.__class__ is CoreMarkupLabel\n        self.texture = None\n\n        if (not self._label.text or (self.halign[-1] == 'y' or self.strip) and\n            not self._label.text.strip()):\n            self.texture_size = (0, 0)\n            if mrkup:\n                self.refs, self._label._refs = {}, {}\n                self.anchors, self._label._anchors = {}, {}\n        else:\n            if mrkup:\n                text = self._label.text\n                # we must strip here, otherwise, if the last line is empty,\n                # markup will retain the last empty line since it only strips\n                # line by line within markup\n                if self.halign[-1] == 'y' or self.strip:\n                    text = text.strip()\n                self._label.text = ''.join(('[color=',\n                                            get_hex_from_color(self.color),\n                                            ']', text, '[/color]'))\n                self._label.refresh()\n                # force the rendering to get the references\n                if self._label.texture:\n                    self._label.texture.bind()\n                self.refs = self._label.refs\n                self.anchors = self._label.anchors\n            else:\n                self._label.refresh()\n            texture = self._label.texture\n            if texture is not None:\n                self.texture = self._label.texture\n                self.texture_size = list(self.texture.size)\n\n    def on_touch_down(self, touch):\n        if super(Label, self).on_touch_down(touch):\n            return True\n        if not len(self.refs):\n            return False\n        tx, ty = touch.pos\n        tx -= self.center_x - self.texture_size[0] / 2.\n        ty -= self.center_y - self.texture_size[1] / 2.\n        ty = self.texture_size[1] - ty\n        for uid, zones in self.refs.items():\n            for zone in zones:\n                x, y, w, h = zone\n                if x <= tx <= w and y <= ty <= h:\n                    self.dispatch('on_ref_press', uid)\n                    return True\n        return False\n\n    def on_ref_press(self, ref):\n        pass\n\n    #\n    # Properties\n    #\n\n    disabled_color = ListProperty([1, 1, 1, .3])\n    '''Text color, in the format (r, g, b, a)\n\n    .. versionadded:: 1.8.0\n\n    :attr:`disabled_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [1, 1, 1, .5].\n    '''\n\n    text = StringProperty('')\n    '''Text of the label.\n\n    Creation of a simple hello world::\n\n        widget = Label(text='Hello world')\n\n    If you want to create the widget with an unicode string, use::\n\n        widget = Label(text=u'My unicode string')\n\n    :attr:`text` is a :class:`~kivy.properties.StringProperty` and defaults to\n    ''.\n    '''\n\n    text_size = ListProperty([None, None])\n    '''By default, the label is not constrained to any bounding box.\n    You can set the size constraint of the label with this property.\n    The text will autoflow into the constrains. So although the font size\n    will not be reduced, the text will be arranged to fit into the box as best\n    as possible, with any text still outside the box clipped.\n\n    This sets and clips :attr:`texture_size` to text_size if not None.\n\n    .. versionadded:: 1.0.4\n\n    For example, whatever your current widget size is, if you want the label to\n    be created in a box with width=200 and unlimited height::\n\n        Label(text='Very big big line', text_size=(200, None))\n\n    .. note::\n\n        This text_size property is the same as the\n        :attr:`~kivy.core.text.Label.usersize` property in the\n        :class:`~kivy.core.text.Label` class. (It is named size= in the\n        constructor.)\n\n    :attr:`text_size` is a :class:`~kivy.properties.ListProperty` and\n    defaults to (None, None), meaning no size restriction by default.\n    '''\n\n    font_name = StringProperty('DroidSans')\n    '''Filename of the font to use. The path can be absolute or relative.\n    Relative paths are resolved by the :func:`~kivy.resources.resource_find`\n    function.\n\n    .. warning::\n\n        Depending of your text provider, the font file can be ignored. However,\n        you can mostly use this without problems.\n\n        If the font used lacks the glyphs for the particular language/symbols\n        you are using, you will see '[]' blank box characters instead of the\n        actual glyphs. The solution is to use a font that has the glyphs you\n        need to display. For example, to display |unicodechar|, use a font such\n        as freesans.ttf that has the glyph.\n\n        .. |unicodechar| image:: images/unicode-char.png\n\n    :attr:`font_name` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'DroidSans'.\n    '''\n\n    font_size = NumericProperty('15sp')\n    '''Font size of the text, in pixels.\n\n    :attr:`font_size` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 15sp.\n    '''\n\n    line_height = NumericProperty(1.0)\n    '''Line Height for the text. e.g. line_height = 2 will cause the spacing\n    between lines to be twice the size.\n\n    :attr:`line_height` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 1.0.\n\n    .. versionadded:: 1.5.0\n    '''\n\n    bold = BooleanProperty(False)\n    '''Indicates use of the bold version of your font.\n\n    .. note::\n\n        Depending of your font, the bold attribute may have no impact on your\n        text rendering.\n\n    :attr:`bold` is a :class:`~kivy.properties.BooleanProperty` and defaults to\n    False.\n    '''\n\n    italic = BooleanProperty(False)\n    '''Indicates use of the italic version of your font.\n\n    .. note::\n\n        Depending of your font, the italic attribute may have no impact on your\n        text rendering.\n\n    :attr:`italic` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    padding_x = NumericProperty(0)\n    '''Horizontal padding of the text inside the widget box.\n\n    :attr:`padding_x` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n\n    .. versionchanged:: 1.9.0\n        `padding_x` has been fixed to work as expected.\n        In the past, the text was padded by the negative of its values.\n    '''\n\n    padding_y = NumericProperty(0)\n    '''Vertical padding of the text inside the widget box.\n\n    :attr:`padding_y` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n\n    .. versionchanged:: 1.9.0\n        `padding_y` has been fixed to work as expected.\n        In the past, the text was padded by the negative of its values.\n    '''\n\n    padding = ReferenceListProperty(padding_x, padding_y)\n    '''Padding of the text in the format (padding_x, padding_y)\n\n    :attr:`padding` is a :class:`~kivy.properties.ReferenceListProperty` of\n    (:attr:`padding_x`, :attr:`padding_y`) properties.\n    '''\n\n    halign = OptionProperty('left', options=['left', 'center', 'right',\n                            'justify'])\n    '''Horizontal alignment of the text.\n\n    :attr:`halign` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to 'left'. Available options are : left, center, right and\n    justify.\n\n    .. warning::\n\n        This doesn't change the position of the text texture of the Label\n        (centered), only the position of the text in this texture. You probably\n        want to bind the size of the Label to the :attr:`texture_size` or set a\n        :attr:`text_size`.\n\n    .. versionchanged:: 1.6.0\n        A new option was added to :attr:`halign`, namely `justify`.\n    '''\n\n    valign = OptionProperty('bottom', options=['bottom', 'middle', 'top'])\n    '''Vertical alignment of the text.\n\n    :attr:`valign` is an :class:`~kivy.properties.OptionProperty` and defaults\n    to 'bottom'. Available options are : bottom, middle and top.\n\n    .. warning::\n\n        This doesn't change the position of the text texture of the Label\n        (centered), only the position of the text within this texture. You\n        probably want to bind the size of the Label to the :attr:`texture_size`\n        or set a :attr:`text_size` to change this behavior.\n    '''\n\n    color = ListProperty([1, 1, 1, 1])\n    '''Text color, in the format (r, g, b, a)\n\n    :attr:`color` is a :class:`~kivy.properties.ListProperty` and defaults to\n    [1, 1, 1, 1].\n    '''\n\n    texture = ObjectProperty(None, allownone=True)\n    '''Texture object of the text.\n    The text is rendered automatically when a property changes. The OpenGL\n    texture created in this operation is stored in this property. You can use\n    this :attr:`texture` for any graphics elements.\n\n    Depending on the texture creation, the value will be a\n    :class:`~kivy.graphics.texture.Texture` or\n    :class:`~kivy.graphics.texture.TextureRegion` object.\n\n    .. warning::\n\n        The :attr:`texture` update is scheduled for the next frame. If you need\n        the texture immediately after changing a property, you have to call\n        the :meth:`texture_update` method before accessing :attr:`texture`::\n\n            l = Label(text='Hello world')\n            # l.texture is good\n            l.font_size = '50sp'\n            # l.texture is not updated yet\n            l.texture_update()\n            # l.texture is good now.\n\n    :attr:`texture` is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    texture_size = ListProperty([0, 0])\n    '''Texture size of the text. The size is determined by the font size and\n    text. If :attr:`text_size` is [None, None], the texture will be the size\n    required to fit the text, otherwise it's clipped to fit :attr:`text_size`.\n\n    When :attr:`text_size` is [None, None], one can bind to texture_size\n    and rescale it proportionally to fit the size of the label in order to\n    make the text fit maximally in the label.\n\n    .. warning::\n\n        The :attr:`texture_size` is set after the :attr:`texture`\n        property. If you listen for changes to :attr:`texture`,\n        :attr:`texture_size` will not be up-to-date in your callback.\n        Bind to :attr:`texture_size` instead.\n    '''\n\n    mipmap = BooleanProperty(False)\n    '''Indicates whether OpenGL mipmapping is applied to the texture or not.\n    Read :ref:`mipmap` for more information.\n\n    .. versionadded:: 1.0.7\n\n    :attr:`mipmap` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    shorten = BooleanProperty(False)\n    '''\n    Indicates whether the label should attempt to shorten its textual contents\n    as much as possible if a :attr:`text_size` is given. Setting this to True\n    without an appropriately set :attr:`text_size` will lead to unexpected\n    results.\n\n    :attr:`shorten_from` and :attr:`split_str` control the direction from\n    which the :attr:`text` is split, as well as where in the :attr:`text` we\n    are allowed to split.\n\n    :attr:`shorten` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    shorten_from = OptionProperty('center', options=['left', 'center',\n                                                     'right'])\n    '''The side from which we should shorten the text from, can be left,\n    right, or center.\n\n    For example, if left, the ellipsis will appear towards the left side and we\n    will display as much text starting from the right as possible. Similar to\n    :attr:`shorten`, this option only applies when :attr:`text_size` [0] is\n    not None, In this case, the string is shortened to fit within the specified\n    width.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`shorten_from` is a :class:`~kivy.properties.OptionProperty` and\n    defaults to `center`.\n    '''\n\n    split_str = StringProperty('')\n    '''The string used to split the :attr:`text` while shortening the string\n    when :attr:`shorten` is True.\n\n    For example, if it's a space, the string will be broken into words and as\n    many whole words that can fit into a single line will be displayed. If\n    :attr:`shorten_from` is the empty string, `''`, we split on every character\n    fitting as much text as possible into the line.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`split_str` is a :class:`~kivy.properties.StringProperty` and\n    defaults to `''` (the empty string).\n    '''\n\n    unicode_errors = OptionProperty(\n        'replace', options=('strict', 'replace', 'ignore'))\n    '''How to handle unicode decode errors. Can be `'strict'`, `'replace'` or\n    `'ignore'`.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`unicode_errors` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to `'replace'`.\n    '''\n\n    markup = BooleanProperty(False)\n    '''\n    .. versionadded:: 1.1.0\n\n    If True, the text will be rendered using the\n    :class:`~kivy.core.text.markup.MarkupLabel`: you can change the\n    style of the text using tags. Check the\n    :doc:`api-kivy.core.text.markup` documentation for more information.\n\n    :attr:`markup` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    refs = DictProperty({})\n    '''\n    .. versionadded:: 1.1.0\n\n    List of ``[ref=xxx]`` markup items in the text with the bounding box of\n    all the words contained in a ref, available only after rendering.\n\n    For example, if you wrote::\n\n        Check out my [ref=hello]link[/ref]\n\n    The refs will be set with::\n\n        {'hello': ((64, 0, 78, 16), )}\n\n    The references marked \"hello\" have a bounding box at (x1, y1, x2, y2).\n    These co-ordinates are relative to the top left corner of the text, with\n    the y value increasing downwards. You can define multiple refs with the same\n    name: each occurence will be added as another (x1, y1, x2, y2) tuple to\n    this list.\n\n    The current Label implementation uses these references if they exist in\n    your markup text, automatically doing the collision with the touch and\n    dispatching an `on_ref_press` event.\n\n    You can bind a ref event like this::\n\n        def print_it(instance, value):\n            print('User click on', value)\n        widget = Label(text='Hello [ref=world]World[/ref]', markup=True)\n        widget.on_ref_press(print_it)\n\n    .. note::\n\n        This works only with markup text. You need :attr:`markup` set to\n        True.\n    '''\n\n    anchors = DictProperty({})\n    '''\n    .. versionadded:: 1.1.0\n\n    Position of all the ``[anchor=xxx]`` markup in the text.\n    These co-ordinates are relative to the top left corner of the text, with\n    the y value increasing downwards. Anchors names should be unique and only\n    the first occurence of any duplicate anchors will be recorded.\n\n\n    You can place anchors in your markup text as follows::\n\n        text = \"\"\"\n            [anchor=title1][size=24]This is my Big title.[/size]\n            [anchor=content]Hello world\n        \"\"\"\n\n    Then, all the ``[anchor=]`` references will be removed and you'll get all\n    the anchor positions in this property (only after rendering)::\n\n        >>> widget = Label(text=text, markup=True)\n        >>> widget.texture_update()\n        >>> widget.anchors\n        {\"content\": (20, 32), \"title1\": (20, 16)}\n\n    .. note::\n\n        This works only with markup text. You need :attr:`markup` set to\n        True.\n\n    '''\n\n    max_lines = NumericProperty(0)\n    '''Maximum number of lines to use, defaults to 0, which means unlimited.\n    Please note that :attr:`shorten` take over this property. (with\n    shorten, the text is always one line.)\n\n    .. versionadded:: 1.8.0\n\n    :attr:`max_lines` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    strip = BooleanProperty(False)\n    '''Whether leading and trailing spaces and newlines should be stripped from\n    each displayed line. If True, every line will start at the right or left\n    edge, depending on :attr:`halign`. If :attr:`halign` is `justify` it is\n    implicitly True.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`strip` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n"
  },
  {
    "path": "tickeys/kivy/uix/layout.py",
    "content": "'''\nLayout\n======\n\nLayouts are used to calculate and assign widget positions.\n\nThe :class:`Layout` class itself cannot be used directly.\nYou should use one of the following layout classes:\n\n- Anchor layout: :class:`kivy.uix.anchorlayout.AnchorLayout`\n- Box layout: :class:`kivy.uix.boxlayout.BoxLayout`\n- Float layout: :class:`kivy.uix.floatlayout.FloatLayout`\n- Grid layout: :class:`kivy.uix.gridlayout.GridLayout`\n- Page Layout: :class:`kivy.uix.pagelayout.PageLayout`\n- Relative layout: :class:`kivy.uix.relativelayout.RelativeLayout`\n- Scatter layout: :class:`kivy.uix.scatterlayout.ScatterLayout`\n- Stack layout: :class:`kivy.uix.stacklayout.StackLayout`\n\n\nUnderstanding the `size_hint` Property in `Widget`\n--------------------------------------------------\n\nThe :attr:`~kivy.uix.Widget.size_hint` is a tuple of values used by\nlayouts to manage the sizes of their children. It indicates the size\nrelative to the layout's size instead of an absolute size (in\npixels/points/cm/etc). The format is::\n\n    widget.size_hint = (width_percent, height_percent)\n\nThe percent is specified as a floating point number in the range 0-1. For\nexample, 0.5 is 50%, 1 is 100%.\n\nIf you want a widget's width to be half of the parent's width and the\nheight to be identical to the parent's height, you would do::\n\n    widget.size_hint = (0.5, 1.0)\n\nIf you don't want to use a size_hint for either the width or height, set the\nvalue to None. For example, to make a widget that is 250px wide and 30%\nof the parent's height, do::\n\n    widget.size_hint = (None, 0.3)\n    widget.width = 250\n\n.. versionchanged:: 1.4.1\n    The `reposition_child` internal method (made public by mistake) has\n    been removed.\n\n'''\n\n__all__ = ('Layout', )\n\nfrom kivy.clock import Clock\nfrom kivy.uix.widget import Widget\n\n\nclass Layout(Widget):\n    '''Layout interface class, used to implement every layout. See module\n    documentation for more information.\n    '''\n\n    def __init__(self, **kwargs):\n        if self.__class__ == Layout:\n            raise Exception('The Layout class cannot be used.')\n        self._trigger_layout = Clock.create_trigger(self.do_layout, -1)\n        super(Layout, self).__init__(**kwargs)\n\n    def do_layout(self, *largs):\n        '''This function is called when a layout is needed by a trigger.\n        If you are writing a new Layout subclass, don't call this function\n        directly but use :meth:`_trigger_layout` instead.\n\n        .. versionadded:: 1.0.8\n        '''\n        pass\n\n    def add_widget(self, widget, index=0):\n        widget.bind(\n            size=self._trigger_layout,\n            size_hint=self._trigger_layout)\n        return super(Layout, self).add_widget(widget, index)\n\n    def remove_widget(self, widget):\n        widget.unbind(\n            size=self._trigger_layout,\n            size_hint=self._trigger_layout)\n        return super(Layout, self).remove_widget(widget)\n"
  },
  {
    "path": "tickeys/kivy/uix/listview.py",
    "content": "'''\nList View\n===========\n\n.. versionadded:: 1.5\n\n.. warning::\n\n    This code is still experimental, and its API is subject to change in a\n    future version.\n\nThe :class:`~kivy.uix.listview.ListView` implements an\n:class:`~kivy.uix.abstractview.AbstractView` as\na vertical, scrollable,pannable list clipped to the scrollview's bounding box\nand contains list item view instances.\n\nThe :class:`AbstractView` has one property: :class:`~kivy.adapters.adapter`.\nThe adapter can be one of the following: a\n:class:`~kivy.adapters.simplelistadapter.SimpleListAdapter`, a\n:class:`~kivy.adapters.listadapter.ListAdapter` or a\n:class:`~kivy.adapters.dictadapter.DictAdapter`. The :class:`Adapter` can make\nuse of :mod:`~kivy.adapters.args_converters` to prepare you data for passing\ninto the constructor for each item view instantiation.\n\nFor an overview of how all these components fit together, please see the\n:mod:`~kivy.adapters` module documentation.\n\nIntroduction\n------------\n\nLists are central parts of many software projects. Kivy's approach to lists\nincludes providing solutions for simple lists, along with a substantial\nframework for building lists of moderate to advanced complexity. For a new\nuser, it can be difficult to ramp up from simple to advanced. For\nthis reason, Kivy provides an extensive set of examples (with the Kivy package)\nthat you may wish to run first, to get a taste of the range of functionality\noffered. You can tell from the names of the examples that they illustrate the\n\"ramping up\" from simple to advanced:\n\n\n    * `kivy/examples/widgets/lists/list_simple.py <https://github.com/\\\nkivy/kivy/tree/master/examples/widgets/lists/list_simple.py>`_\n    * `kivy/examples/widgets/lists/list_simple_in_kv.py <https://github.com/\\\nkivy/kivy/tree/master/examples/widgets/lists/list_simple_in_kv.py>`_\n    * `kivy/examples/widgets/lists/list_simple_in_kv_2.py <https://github.com/\\\nkivy/kivy/tree/master/examples/widgets/lists/list_simple_in_kv_2.py>`_\n    * `kivy/examples/widgets/lists/list_master_detail.py <https://github.com/\\\nkivy/kivy/tree/master/examples/widgets/lists/list_master_detail.py>`_\n    * `kivy/examples/widgets/lists/list_two_up.py <https://github.com/\\\nkivy/kivy/tree/master/examples/widgets/lists/list_two_up.py>`_\n    * `kivy/examples/widgets/lists/list_kv.py <https://github.com/\\\nkivy/kivy/tree/master/examples/widgets/lists/list_kv.py>`_\n    * `kivy/examples/widgets/lists/list_composite.py <https://github.com/\\\nkivy/kivy/tree/master/examples/widgets/lists/list_composite.py>`_\n    * `kivy/examples/widgets/lists/list_cascade.py <https://github.com/\\\nkivy/kivy/tree/master/examples/widgets/lists/list_cascade.py>`_\n    * `kivy/examples/widgets/lists/list_cascade_dict.py <https://github.com/\\\nkivy/kivy/tree/master/examples/widgets/lists/list_cascade_dict.py>`_\n    * `kivy/examples/widgets/lists/list_cascade_images.py <https://github.com/\\\nkivy/kivy/tree/master/examples/widgets/lists/list_cascade_images.py>`_\n    * `kivy/examples/widgets/lists/list_ops.py <https://github.com/\\\nkivy/kivy/tree/master/examples/widgets/lists/list_ops.py>`_\n\nMany of the examples feature selection, some restricting selection to single\nselection, where only one item at at time can be selected, and others allowing\nmultiple item selection. Many of the examples illustrate how selection in one\nlist can be connected to actions and selections in another view or another list.\n\nFind your own way of reading the documentation here, examining the source code\nfor the example apps and running the examples. Some may prefer to read the\ndocumentation through first, others may want to run the examples and view their\ncode. No matter what you do, going back and forth will likely be needed.\n\nBasic Example\n-------------\n\nIn its simplest form, we make a listview with 100 items::\n\n    from kivy.uix.listview import ListView\n    from kivy.base import runTouchApp\n\n\n    class MainView(ListView):\n        def __init__(self, **kwargs):\n            super(MainView, self).__init__(\n                item_strings=[str(index) for index in range(100)])\n\n    if __name__ == '__main__':\n        runTouchApp(MainView())\n\nOr, we could declare the listview using the kv language::\n\n    from kivy.uix.boxlayout import BoxLayout\n    from kivy.lang import Builder\n    from kivy.base import runTouchApp\n\n    Builder.load_string(\"\"\"\n    <MyListView>:\n        ListView:\n            item_strings: [str(index) for index in range(100)]\n    \"\"\")\n\n\n    class MyListView(BoxLayout):\n        pass\n\n    if __name__ == '__main__':\n        runTouchApp(MyListView())\n\nUsing an Adapter\n-------------------\n\nBehind the scenes, the basic example above uses the\n:class:`~kivy.adapters.simplelistadapter.SimpleListAdapter`. When the\nconstructor for the :class:`~kivy.uix.listview.ListView` sees that only a list\nof\nstrings is provided as an argument (called item_strings), it creates a\n:class:`~kivy.adapters.simplelistadapter.SimpleListAdapter` using the\nlist of strings.\n\n\"Simple\" in :class:`~kivy.adapters.simplelistadapter.SimpleListAdapter` means\n*without selection support*. It is a scrollable list of items that does not\nrespond to touch events.\n\nTo use a :class:`SimpleListAdaper` explicitly when creating a ListView instance,\ndo::\n\n    simple_list_adapter = SimpleListAdapter(\n            data=[\"Item #{0}\".format(i) for i in range(100)],\n            cls=Label)\n\n    list_view = ListView(adapter=simple_list_adapter)\n\nThe instance of :class:`~kivy.adapters.simplelistadapter.SimpleListAdapter` has\na required data argument which contains data items to use for instantiating\n:class:`~kivy.uix.label.Label` views for the list view (note the cls=Label\nargument). The data items are strings. Each item string is set by the\n:class:`~kivy.adapters.simplelistadapter.SimpleListAdapter` as the *text*\nargument for each Label instantiation.\n\nYou can declare a ListView with an adapter in a kv file with special attention\ngiven to the way longer python blocks are indented::\n\n    from kivy.uix.boxlayout import BoxLayout\n    from kivy.base import runTouchApp\n    from kivy.lang import Builder\n\n    # Note the special nature of indentation in the adapter declaration, where\n    # the adapter: is on one line, then the value side must be given at one\n    # level of indentation.\n\n    Builder.load_string(\"\"\"\n    #:import label kivy.uix.label\n    #:import sla kivy.adapters.simplelistadapter\n\n    <MyListView>:\n        ListView:\n            adapter:\n                sla.SimpleListAdapter(\n                data=[\"Item #{0}\".format(i) for i in range(100)],\n                cls=label.Label)\n    \"\"\")\n\n\n    class MyListView(BoxLayout):\n        pass\n\n    if __name__ == '__main__':\n        runTouchApp(MyListView())\n\nListAdapter and DictAdapter\n---------------------------\n\nFor most use cases, your data is more complex than a simple list of strings.\nSelection functionality is also often needed.\nThe :class:`~kivy.adapters.listadapter.ListAdapter` and\n:class:`~kivy.adapters.dictadapter.DictAdapter` cover these more elaborate\nneeds.\n\nThe :class:`~kivy.adapters.listadapter.ListAdapter` is the base class for\n:class:`~kivy.adapters.dictadapter.DictAdapter`, so we can start with it.\n\nRefer to the :class:`~kivy.adapters.listadapter.ListAdapter` docs for details,\nbut here is a synopses of its arguments:\n\n* :attr:`~kivy.adapters.adapter.Adapter.data`:\n  strings, class instances, dicts, etc. that form the base data\n  for instantiating views.\n\n* :attr:`~kivy.adapters.adapter.Adapter.cls`:\n  a Kivy view that is to be instantiated for each list item. There\n  are several built-in types available, including ListItemLabel and\n  ListItemButton, or you can make your own class that mixes in the\n  required :class:`~kivy.uix.listview.SelectableView`.\n\n* :attr:`~kivy.adapters.adapter.Adapter.template`:\n  the name of a Kivy language (kv) template that defines the\n  Kivy view for each list item.\n\n.. note::\n\n    Pick only one, cls or template, to provide as an argument.\n\n* :attr:`~kivy.adapters.args_converters`: a function that takes a data item\n  object as input and\n  uses it to build and return an args dict, ready\n  to be used in a call to instantiate item views using the item view cls\n  or template. In the case of cls, the args dict becomes a kwargs constructor\n  argument. For a template, it is treated as a context\n  (ctx) but is essentially similar in form to the kwargs usage.\n\n* :attr:`~kivy.adapters.listadapter.ListAdapter.selection_mode`:\n  a string with the value 'single',\n  'multiple' or other.\n\n* :attr:`~kivy.adapters.listadapter.ListAdapter.allow_empty_selection`:\n  a boolean, which if False (the default), forces\n  there to always be a selection if there is data\n  available. If True, selection happens only as a\n  result of user action.\n\nIn narrative, we can summarize as follows:\n\n    A listview's adapter takes data items and uses an args_converter\n    function to transform them into arguments for creating list item view\n    instances, using either a cls or a kv template.\n\nIn a graphic, a summary of the relationship between a listview and its\ncomponents can be summarized as follows:\n\n.. image:: images/adapters.png\n\nPlease refer to the :mod:`~kivy.adapters` documentation for more details.\n\nA :class:`~kivy.adapters.dictadapter.DictAdapter` has the same arguments and\nrequirements as a :class:`~kivy.adapters.listadapter.ListAdapter` except for two\nthings:\n\n1) There is an additional argument, sorted_keys, which must meet the\n   requirements of normal python dictionary keys.\n\n2) The data argument is, as you would expect, a dict. Keys in the dict\n   must include the keys in the sorted_keys argument, but they may form a\n   superset of the keys in sorted_keys. Values may be strings, class\n   instances, dicts, etc. (The args_converter uses it accordingly).\n\nUsing an Args Converter\n-----------------------\n\nA :class:`~kivy.uix.listview.ListView` allows use of built-in list item views,\nsuch as :class:`~kivy.uix.listview.ListItemButton`, your own custom item view\nclass or a custom kv template. Whichever type of list item view is used, an\n:doc:`args_converter <api-kivy.adapters.args_converters>` function is needed to\nprepare, per list data item, kwargs for the cls or the ctx for the template.\n\n.. note::\n\n    Only the ListItemLabel, ListItemButton or custom classes like them (and\n    not the simple Label or Button classes) are to be used in the listview\n    system.\n\n.. warning::\n\n    ListItemButton inherits the `background_normal` and `background_down`\n    properties from the Button widget, so the `selected_color` and\n    `deselected_color` are not represented faithfully by default.\n\nHere is an args_converter for use with the built-in\n:class:`~kivy.uix.listview.ListItemButton` specified as a normal Python\nfunction::\n\n    def args_converter(row_index, an_obj):\n        return {'text': an_obj.text,\n                'size_hint_y': None,\n                'height': 25}\n\nand as a lambda::\n\n    args_converter = lambda row_index, an_obj: {'text': an_obj.text,\n                                                'size_hint_y': None,\n                                                'height': 25}\n\nIn the args converter example above, the data item is assumed to be an object\n(class instance), hence the reference an_obj.text.\n\nHere is an example of an args converter that works with list data items that\nare dicts::\n\n    args_converter = lambda row_index, obj: {'text': obj['text'],\n                                             'size_hint_y': None,\n                                             'height': 25}\n\nSo, it is the responsibility of the developer to code the args_converter\naccording to the data at hand. The row_index argument can be useful in some\ncases, such as when custom labels are needed.\n\nAn Example ListView\n-------------------\n\nNow, to some example code::\n\n    from kivy.adapters.listadapter import ListAdapter\n    from kivy.uix.listview import ListItemButton, ListView\n\n    data = [{'text': str(i), 'is_selected': False} for i in range(100)]\n\n    args_converter = lambda row_index, rec: {'text': rec['text'],\n                                             'size_hint_y': None,\n                                             'height': 25}\n\n    list_adapter = ListAdapter(data=data,\n                               args_converter=args_converter,\n                               cls=ListItemButton,\n                               selection_mode='single',\n                               allow_empty_selection=False)\n\n    list_view = ListView(adapter=list_adapter)\n\nThis listview will show 100 buttons with text of 0 to 100. The args_converter\nfunction converts the dict items in the data and instantiates ListItemButton\nviews by passing these converted items into it's constructor. The\nlistview will only allow single selection and the first item will already be\nselected as allow_empty_selection is False. For a complete discussion on these\narguments, please see the :class:`~kivy.adapters.listadapter.ListAdapter`\ndocumentation.\n\nThe :class:`~kivy.uix.listview.ListItemLabel` works in much the same way as the\n:class:`~kivy.uix.listview.ListItemButton`.\n\nUsing a Custom Item View Class\n------------------------------\n\nThe data used in an adapter can be any of the normal Python types or custom\nclasses, as shown below. It is up to the programmer to assure that the\nargs_converter performs the appropriate conversions.\n\nHere we make a simple DataItem class that has the required text and\nis_selected properties::\n\n    from kivy.uix.listview import ListItemButton\n    from kivy.adapters.listadapter import ListAdapter\n\n\n    class DataItem(object):\n        def __init__(self, text='', is_selected=False):\n            self.text = text\n            self.is_selected = is_selected\n\n    data_items = [DataItem(text='cat'),\n                  DataItem(text='dog'),\n                  DataItem(text='frog')]\n\n    list_item_args_converter = lambda row_index, obj: {'text': obj.text,\n                                                       'size_hint_y': None,\n                                                       'height': 25}\n\n    list_adapter = ListAdapter(data=data_items,\n                               args_converter=list_item_args_converter,\n                               propagate_selection_to_data=True,\n                               cls=ListItemButton)\n\n    list_view = ListView(adapter=list_adapter)\n\nThe data is passed to the :class:`~kivy.adapters.listadapter.ListAdapter` along\nwith an args_converter function. The propagation setting means that\nthe is_selected property for each data item will be set and kept in sync with\nthe list item views. This setting should be set to True if you wish to\ninitialize the view with item views already selected.\n\nYou may also use the provided :class:`~kivy.adapters.models.SelectableDataItem`\nmixin to make a custom class. Instead of the \"manually-constructed\" DataItem\nclass above, we could do::\n\n    from kivy.adapters.models import SelectableDataItem\n\n    class DataItem(SelectableDataItem):\n        # Add properties here.\n        pass\n\n:class:`~kivy.adapters.models.SelectableDataItem` is a simple mixin class that\nhas an is_selected property.\n\nUsing an Item View Template\n---------------------------\n\n:class:`~kivy.uix.listview.SelectableView` is another simple mixin class that\nhas required properties for a list item: text, and is_selected. To make your\nown template, mix it in as follows::\n\n    from kivy.lang import Builder\n\n    Builder.load_string(\"\"\"\n    [CustomListItem@SelectableView+BoxLayout]:\n        size_hint_y: ctx.size_hint_y\n        height: ctx.height\n        ListItemButton:\n            text: ctx.text\n            is_selected: ctx.is_selected\n    \"\"\")\n\nA class called CustomListItem can then be instantiated for each list item. Note\nthat it subclasses a :class:`~kivy.uix.boxlayout.BoxLayout` and is thus a type\nof :mod:`~kivy.uix.layout`. It contains a\n:class:`~kivy.uix.listview.ListItemButton` instance.\n\nUsing the power of the Kivy language (kv), you can easily build composite list\nitems: in addition to ListItemButton, you could have a ListItemLabel or a\ncustom class you have defined and registered via the\n:class:`~kivy.factory.Factory`.\n\nAn args_converter needs to be constructed that goes along with such a kv\ntemplate. For example, to use the kv template above::\n\n    list_item_args_converter = \\\\\n            lambda row_index, rec: {'text': rec['text'],\n                                    'is_selected': rec['is_selected'],\n                                    'size_hint_y': None,\n                                    'height': 25}\n    integers_dict = \\\\\n        { str(i): {'text': str(i), 'is_selected': False} for i in range(100)}\n\n    dict_adapter = DictAdapter(sorted_keys=[str(i) for i in range(100)],\n                               data=integers_dict,\n                               args_converter=list_item_args_converter,\n                               template='CustomListItem')\n\n    list_view = ListView(adapter=dict_adapter)\n\nA dict adapter is created with 1..100 integer strings as sorted_keys, and an\nintegers_dict as data. integers_dict has the integer strings as keys and dicts\nwith text and is_selected properties. The CustomListItem defined above in the\nBuilder.load_string() call is set as the kv template for the list item views.\nThe list_item_args_converter lambda function will take each dict in\nintegers_dict and will return an args dict, ready for passing as the context\n(ctx) for the template.\n\nUsing CompositeListItem\n-----------------------\n\nThe class :class:`~kivy.uix.listview.CompositeListItem` is another option for\nbuilding advanced composite list items. The kv language approach has its\nadvantages, but here we build a composite list view using a plain Python::\n\n    args_converter = lambda row_index, rec: \\\\\n        {'text': rec['text'],\n        'size_hint_y': None,\n        'height': 25,\n        'cls_dicts': [{'cls': ListItemButton,\n                        'kwargs': {'text': rec['text']}},\n                    {'cls': ListItemLabel,\n                        'kwargs': {'text': \"Middle-{0}\".format(rec['text']),\n                                'is_representing_cls': True}},\n                    {'cls': ListItemButton,\n                        'kwargs': {'text': rec['text']}}]}\n\n    item_strings = [\"{0}\".format(index) for index in range(100)]\n\n    integers_dict = \\\\\n        {str(i): {'text': str(i), 'is_selected': False} for i in range(100)}\n\n    dict_adapter = DictAdapter(sorted_keys=item_strings,\n                               data=integers_dict,\n                               args_converter=args_converter,\n                               selection_mode='single',\n                               allow_empty_selection=False,\n                               cls=CompositeListItem)\n\n    list_view = ListView(adapter=dict_adapter)\n\nThe args_converter is somewhat complicated, so we should go through the\ndetails. Observe in the :class:`~kivy.adapters.dictadapter.DictAdapter`\ninstantiation that :class:`~kivy.uix.listview.CompositeListItem` instance is\nset as the cls to be instantiated for each list item component. The\nargs_converter will\nmake args dicts for this cls. In the args_converter, the first three items,\ntext, size_hint_y, and height, are arguments for the CompositeListItem itself.\nAfter that you see a cls_dicts list that contains argument sets for each of the\nmember widgets for this composite: 2\n:class:`ListItemButtons <kivy.uix.listview.ListItemButton>` and a\n:class:`~kivy.uix.listview.ListItemLabel`. This is a similar approach to\nusing a kv template described above.\n\nFor details on how :class:`~kivy.uix.listview.CompositeListItem` works,\nexamine the code, looking for how parsing of the cls_dicts list and kwargs\nprocessing is done.\n\nUses for Selection\n------------------\n\nWhat can we do with selection? Combining selection with the system of bindings\nin Kivy, we can build a wide range of user interface designs.\n\nWe could make data items that contain the names of dog breeds, and connect\nthe selection of dog breed to the display of details in another view, which\nwould update automatically on selection. This is done via a binding to the\n:attr:`~kivy.adapters.listadapter.ListAdapter.on_selection_change` event::\n\n    list_adapter.bind(on_selection_change=callback_function)\n\nwhere callback_function() gets passed the adapter as an argument and does\nwhatever is needed for the update. See the\nexample called list_master_detail.py, and imagine that the list on the left\ncould be a list of dog breeds, and the detail view on the right could show\ndetails for a selected dog breed.\n\nIn another example, we could set the selection_mode of a listview to\n'multiple', and load it with a list of answers to a multiple-choice question.\nThe question could have several correct answers. A color swatch view could be\nbound to selection change, as above, so that it turns green as soon as the\ncorrect choices are made, unless the number of touches exeeds a limit, then the\nanswer session could be terminated. See the examples that feature thumbnail\nimages to get some ideas, e.g., list_cascade_dict.py.\n\nIn a more involved example, we could chain together three listviews, where\nselection in the first controls the items shown in the second, and selection in\nthe second controls the items shown in the third. If allow_empty_selection were\nset to False for these listviews, a dynamic system of selection \"cascading\"\nfrom one list to the next, would result.\n\nThere are so many ways that listviews and Kivy bindings functionality can be\nused, that we have only scratched the surface here. For on-disk examples, see::\n\n    kivy/examples/widgets/lists/list_*.py\n\nSeveral examples show the \"cascading\" behavior described above. Others\ndemonstrate the use of kv templates and composite list views.\n\n'''\n\n__all__ = ('SelectableView', 'ListItemButton', 'ListItemLabel',\n           'CompositeListItem', 'ListView', )\n\nfrom kivy.event import EventDispatcher\nfrom kivy.clock import Clock\nfrom kivy.compat import PY2\nfrom kivy.uix.widget import Widget\nfrom kivy.uix.button import Button\nfrom kivy.uix.label import Label\nfrom kivy.uix.boxlayout import BoxLayout\nfrom kivy.adapters.simplelistadapter import SimpleListAdapter\nfrom kivy.uix.abstractview import AbstractView\nfrom kivy.properties import ObjectProperty, DictProperty, \\\n        NumericProperty, ListProperty, BooleanProperty\nfrom kivy.lang import Builder\nfrom math import ceil, floor\n\n\nclass SelectableView(object):\n    '''The :class:`~kivy.uix.listview.SelectableView` mixin is used to design\n    list items and other classes that are to be instantiated by an adapter for\n    use in a listview. The :class:`~kivy.adapters.listadapter.ListAdapter`\n    and :class:`~kivy.adapters.dictadapter.DictAdapter` adapters are\n    selection-enabled. select() and deselect() are to be overridden with\n    display code to mark items as selected or not, if desired.\n    '''\n\n    index = NumericProperty(-1)\n    '''The index into the underlying data list or the data item this view\n    represents.\n\n    :attr:`index` is a :class:`~kivy.properties.NumericProperty`, default\n    to -1.\n    '''\n\n    is_selected = BooleanProperty(False)\n    '''A SelectableView instance carries this property, which should be kept\n    in sync with the equivalent property in the data item it represents.\n\n    :attr:`is_selected` is a :class:`~kivy.properties.BooleanProperty`, default\n    to False.\n    '''\n\n    def __init__(self, **kwargs):\n        super(SelectableView, self).__init__(**kwargs)\n\n    def select(self, *args):\n        '''The list item is responsible for updating the display for\n        being selected, if desired.\n        '''\n        self.is_selected = True\n\n    def deselect(self, *args):\n        '''The list item is responsible for updating the display for\n        being unselected, if desired.\n        '''\n        self.is_selected = False\n\n\nclass ListItemReprMixin(Label):\n    if PY2:\n        def __repr__(self):\n            text = self.text.encode('utf-8') if isinstance(self.text, unicode) \\\n                else self.text\n            return '<%s text=%s>' % (self.__class__.__name__, text)\n    else:\n        def __repr__(self):\n            return '<%s text=%s>' % (self.__class__.__name__, self.text)\n\n\nclass ListItemButton(ListItemReprMixin, SelectableView, Button):\n    ''':class:`~kivy.uix.listview.ListItemButton` mixes\n    :class:`~kivy.uix.listview.SelectableView` with\n    :class:`~kivy.uix.button.Button` to produce a button suitable for use in\n    :class:`~kivy.uix.listview.ListView`.\n    '''\n\n    selected_color = ListProperty([1., 0., 0., 1])\n    '''\n    :attr:`selected_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [1., 0., 0., 1].\n    '''\n\n    deselected_color = ListProperty([0., 1., 0., 1])\n    '''\n    :attr:`deselected_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [0., 1., 0., 1].\n    '''\n\n    def __init__(self, **kwargs):\n        super(ListItemButton, self).__init__(**kwargs)\n\n        # Set Button bg color to be deselected_color.\n        self.background_color = self.deselected_color\n\n    def select(self, *args):\n        self.background_color = self.selected_color\n        if isinstance(self.parent, CompositeListItem):\n            self.parent.select_from_child(self, *args)\n\n    def deselect(self, *args):\n        self.background_color = self.deselected_color\n        if isinstance(self.parent, CompositeListItem):\n            self.parent.deselect_from_child(self, *args)\n\n    def select_from_composite(self, *args):\n        self.background_color = self.selected_color\n\n    def deselect_from_composite(self, *args):\n        self.background_color = self.deselected_color\n\n\n# [TODO] Why does this mix in SelectableView -- that makes it work like\n#        button, which is redundant.\n\nclass ListItemLabel(ListItemReprMixin, SelectableView, Label):\n    ''':class:`~kivy.uix.listview.ListItemLabel` mixes\n    :class:`~kivy.uix.listview.SelectableView` with\n    :class:`~kivy.uix.label.Label` to produce a label suitable for use in\n    :class:`~kivy.uix.listview.ListView`.\n    '''\n\n    def __init__(self, **kwargs):\n        super(ListItemLabel, self).__init__(**kwargs)\n\n    def select(self, *args):\n        self.bold = True\n        if isinstance(self.parent, CompositeListItem):\n            self.parent.select_from_child(self, *args)\n\n    def deselect(self, *args):\n        self.bold = False\n        if isinstance(self.parent, CompositeListItem):\n            self.parent.deselect_from_child(self, *args)\n\n    def select_from_composite(self, *args):\n        self.bold = True\n\n    def deselect_from_composite(self, *args):\n        self.bold = False\n\n\nclass CompositeListItem(SelectableView, BoxLayout):\n    ''':class:`~kivy.uix.listview.CompositeListItem` mixes\n    :class:`~kivy.uix.listview.SelectableView` with :class:`BoxLayout` for a\n    generic container-style list item, to be used in\n    :class:`~kivy.uix.listview.ListView`.\n    '''\n\n    background_color = ListProperty([1, 1, 1, 1])\n    '''ListItem sublasses Button, which has background_color, but\n    for a composite list item, we must add this property.\n\n    :attr:`background_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [1, 1, 1, 1].\n    '''\n\n    selected_color = ListProperty([1., 0., 0., 1])\n    '''\n    :attr:`selected_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [1., 0., 0., 1].\n    '''\n\n    deselected_color = ListProperty([.33, .33, .33, 1])\n    '''\n    :attr:`deselected_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [.33, .33, .33, 1].\n    '''\n\n    representing_cls = ObjectProperty(None)\n    '''Which component view class, if any, should represent for the\n    composite list item in __repr__()?\n\n    :attr:`representing_cls` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    def __init__(self, **kwargs):\n        super(CompositeListItem, self).__init__(**kwargs)\n\n        # Example data:\n        #\n        #    'cls_dicts': [{'cls': ListItemButton,\n        #                   'kwargs': {'text': \"Left\"}},\n        #                   'cls': ListItemLabel,\n        #                   'kwargs': {'text': \"Middle\",\n        #                              'is_representing_cls': True}},\n        #                   'cls': ListItemButton,\n        #                   'kwargs': {'text': \"Right\"}]\n\n        # There is an index to the data item this composite list item view\n        # represents. Get it from kwargs and pass it along to children in the\n        # loop below.\n        index = kwargs['index']\n\n        for cls_dict in kwargs['cls_dicts']:\n            cls = cls_dict['cls']\n            cls_kwargs = cls_dict.get('kwargs', None)\n\n            if cls_kwargs:\n                cls_kwargs['index'] = index\n\n                if 'selection_target' not in cls_kwargs:\n                    cls_kwargs['selection_target'] = self\n\n                if 'text' not in cls_kwargs:\n                    cls_kwargs['text'] = kwargs['text']\n\n                if 'is_representing_cls' in cls_kwargs:\n                    self.representing_cls = cls\n\n                self.add_widget(cls(**cls_kwargs))\n            else:\n                cls_kwargs = {}\n                cls_kwargs['index'] = index\n                if 'text' in kwargs:\n                    cls_kwargs['text'] = kwargs['text']\n                self.add_widget(cls(**cls_kwargs))\n\n    def select(self, *args):\n        self.background_color = self.selected_color\n\n    def deselect(self, *args):\n        self.background_color = self.deselected_color\n\n    def select_from_child(self, child, *args):\n        for c in self.children:\n            if c is not child:\n                c.select_from_composite(*args)\n\n    def deselect_from_child(self, child, *args):\n        for c in self.children:\n            if c is not child:\n                c.deselect_from_composite(*args)\n\n    def __repr__(self):\n        if self.representing_cls is not None:\n            return '<%r>, representing <%s>' % (\n                self.representing_cls, self.__class__.__name__)\n        else:\n            return '<%s>' % (self.__class__.__name__)\n\n\nBuilder.load_string('''\n<ListView>:\n    container: container\n    ScrollView:\n        pos: root.pos\n        on_scroll_y: root._scroll(args[1])\n        do_scroll_x: False\n        GridLayout:\n            cols: 1\n            id: container\n            size_hint_y: None\n''')\n\n\nclass ListView(AbstractView, EventDispatcher):\n    ''':class:`~kivy.uix.listview.ListView` is a primary high-level widget,\n    handling the common task of presenting items in a scrolling list.\n    Flexibility is afforded by use of a variety of adapters to interface with\n    data.\n\n    The adapter property comes via the mixed in\n    :class:`~kivy.uix.abstractview.AbstractView` class.\n\n    :class:`~kivy.uix.listview.ListView` also subclasses\n    :class:`EventDispatcher` for scrolling. The event *on_scroll_complete* is\n    used in refreshing the main view.\n\n    For a simple list of string items, without selection, use\n    :class:`~kivy.adapters.simplelistadapter.SimpleListAdapter`. For list items\n    that respond to selection, ranging from simple items to advanced\n    composites, use :class:`~kivy.adapters.listadapter.ListAdapter`. For an\n    alternate powerful adapter, use\n    :class:`~kivy.adapters.dictadapter.DictAdapter`, rounding out the choice\n    for designing highly interactive lists.\n\n    :Events:\n        `on_scroll_complete`: (boolean, )\n            Fired when scrolling completes.\n    '''\n\n    divider = ObjectProperty(None)\n    '''[TODO] Not used.\n    '''\n\n    divider_height = NumericProperty(2)\n    '''[TODO] Not used.\n    '''\n\n    container = ObjectProperty(None)\n    '''The container is a :class:`~kivy.uix.gridlayout.GridLayout` widget held\n    within a :class:`~kivy.uix.scrollview.ScrollView` widget.  (See the\n    associated kv block in the Builder.load_string() setup). Item view\n    instances managed and provided by the adapter are added to this container.\n    The container is cleared with a call to clear_widgets() when the list is\n    rebuilt by the populate() method. A padding\n    :class:`~kivy.uix.widget.Widget` instance is also added as needed,\n    depending on the row height calculations.\n\n    :attr:`container` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    row_height = NumericProperty(None)\n    '''The row_height property is calculated on the basis of the height of the\n    container and the count of items.\n\n    :attr:`row_height` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to None.\n    '''\n\n    item_strings = ListProperty([])\n    '''If item_strings is provided, create an instance of\n    :class:`~kivy.adapters.simplelistadapter.SimpleListAdapter` with this list\n    of strings, and use it to manage a no-selection list.\n\n    :attr:`item_strings` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [].\n    '''\n\n    scrolling = BooleanProperty(False)\n    '''If the scroll_to() method is called while scrolling operations are\n    happening, a call recursion error can occur. scroll_to() checks to see that\n    scrolling is False before calling populate(). scroll_to() dispatches a\n    scrolling_complete event, which sets scrolling back to False.\n\n    :attr:`scrolling` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    _index = NumericProperty(0)\n    _sizes = DictProperty({})\n    _count = NumericProperty(0)\n\n    _wstart = NumericProperty(0)\n    _wend = NumericProperty(-1)\n\n    __events__ = ('on_scroll_complete', )\n\n    def __init__(self, **kwargs):\n        # Check for an adapter argument. If it doesn't exist, we\n        # check for item_strings in use with SimpleListAdapter\n        # to make a simple list.\n        if 'adapter' not in kwargs:\n            if 'item_strings' not in kwargs:\n                # Could be missing, or it could be that the ListView is\n                # declared in a kv file. If kv is in use, and item_strings is\n                # declared there, then item_strings will not be set until after\n                # __init__(). So, the data=[] set will temporarily serve for\n                # SimpleListAdapter instantiation, with the binding to\n                # item_strings_changed() handling the eventual set of the\n                # item_strings property from the application of kv rules.\n                list_adapter = SimpleListAdapter(data=[],\n                                                 cls=Label)\n            else:\n                list_adapter = SimpleListAdapter(data=kwargs['item_strings'],\n                                                 cls=Label)\n            kwargs['adapter'] = list_adapter\n\n        super(ListView, self).__init__(**kwargs)\n\n        self._trigger_populate = Clock.create_trigger(self._spopulate, -1)\n        self._trigger_reset_populate = \\\n            Clock.create_trigger(self._reset_spopulate, -1)\n\n        self.bind(size=self._trigger_populate,\n                  pos=self._trigger_populate,\n                  item_strings=self.item_strings_changed,\n                  adapter=self._trigger_populate)\n\n        self._trigger_bind_adapter = Clock.create_trigger(\n            lambda dt: self.adapter.bind_triggers_to_view(\n                self._trigger_reset_populate),\n            -1)\n        self.bind(adapter=self._trigger_bind_adapter)\n\n        # The bindings setup above sets self._trigger_populate() to fire\n        # when the adapter changes, but we also need this binding for when\n        # adapter.data and other possible triggers change for view updating.\n        # We don't know that these are, so we ask the adapter to set up the\n        # bindings back to the view updating function here.\n        self._trigger_bind_adapter()\n\n    # Added to set data when item_strings is set in a kv template, but it will\n    # be good to have also if item_strings is reset generally.\n    def item_strings_changed(self, *args):\n        self.adapter.data = self.item_strings\n\n    def _scroll(self, scroll_y):\n        if self.row_height is None:\n            return\n        self._scroll_y = scroll_y\n        scroll_y = 1 - min(1, max(scroll_y, 0))\n        container = self.container\n        mstart = (container.height - self.height) * scroll_y\n        mend = mstart + self.height\n\n        # convert distance to index\n        rh = self.row_height\n        istart = int(ceil(mstart / rh))\n        iend = int(floor(mend / rh))\n\n        istart = max(0, istart - 1)\n        iend = max(0, iend - 1)\n\n        if istart < self._wstart:\n            rstart = max(0, istart - 10)\n            self.populate(rstart, iend)\n            self._wstart = rstart\n            self._wend = iend\n        elif iend > self._wend:\n            self.populate(istart, iend + 10)\n            self._wstart = istart\n            self._wend = iend + 10\n\n    def _spopulate(self, *args):\n        self.populate()\n\n    def _reset_spopulate(self, *args):\n        self._wend = -1\n        self.populate()\n        # simulate the scroll again, only if we already scrolled before\n        # the position might not be the same, mostly because we don't know the\n        # size of the new item.\n        if hasattr(self, '_scroll_y'):\n            self._scroll(self._scroll_y)\n\n    def populate(self, istart=None, iend=None):\n        container = self.container\n        sizes = self._sizes\n        rh = self.row_height\n\n        # ensure we know what we want to show\n        if istart is None:\n            istart = self._wstart\n            iend = self._wend\n\n        # clear the view\n        container.clear_widgets()\n\n        # guess only ?\n        if iend is not None and iend != -1:\n\n            # fill with a \"padding\"\n            fh = 0\n            for x in range(istart):\n                fh += sizes[x] if x in sizes else rh\n            container.add_widget(Widget(size_hint_y=None, height=fh))\n\n            # now fill with real item_view\n            index = istart\n            while index <= iend:\n                item_view = self.adapter.get_view(index)\n                index += 1\n                if item_view is None:\n                    continue\n                sizes[index] = item_view.height\n                container.add_widget(item_view)\n        else:\n            available_height = self.height\n            real_height = 0\n            index = self._index\n            count = 0\n            while available_height > 0:\n                item_view = self.adapter.get_view(index)\n                if item_view is None:\n                    break\n                sizes[index] = item_view.height\n                index += 1\n                count += 1\n                container.add_widget(item_view)\n                available_height -= item_view.height\n                real_height += item_view.height\n\n            self._count = count\n\n            # extrapolate the full size of the container from the size\n            # of view instances in the adapter\n            if count:\n                container.height = \\\n                    real_height / count * self.adapter.get_count()\n                if self.row_height is None:\n                    self.row_height = real_height / count\n\n    def scroll_to(self, index=0):\n        if not self.scrolling:\n            self.scrolling = True\n            self._index = index\n            self.populate()\n            self.dispatch('on_scroll_complete')\n\n    def on_scroll_complete(self, *args):\n        self.scrolling = False\n"
  },
  {
    "path": "tickeys/kivy/uix/modalview.py",
    "content": "'''\nModalView\n=========\n\n.. versionadded:: 1.4.0\n\nThe :class:`ModalView` widget is used to create modal views. By default, the\nview will cover the whole \"parent\" window.\n\nRemember that the default size of a Widget is size_hint=(1, 1). If you don't\nwant your view to be fullscreen, either use size hints with values lower than\n1 (for instance size_hint=(.8, .8)) or deactivate the size_hint and use fixed\nsize attributes.\n\nExamples\n--------\n\nExample of a simple 400x400 Hello world view::\n\n    view = ModalView(size_hint=(None, None), size=(400, 400))\n    view.add_widget(Label(text='Hello world'))\n\nBy default, any click outside the view will dismiss it. If you don't\nwant that, you can set :attr:`ModalView.auto_dismiss` to False::\n\n    view = ModalView(auto_dismiss=False)\n    view.add_widget(Label(text='Hello world'))\n    view.open()\n\nTo manually dismiss/close the view, use the :meth:`ModalView.dismiss` method of\nthe ModalView instance::\n\n    view.dismiss()\n\nBoth :meth:`ModalView.open` and :meth:`ModalView.dismiss` are bindable. That\nmeans you can directly bind the function to an action, e.g. to a button's\non_press ::\n\n    # create content and add it to the view\n    content = Button(text='Close me!')\n    view = ModalView(auto_dismiss=False)\n    view.add_widget(content)\n\n    # bind the on_press event of the button to the dismiss function\n    content.bind(on_press=view.dismiss)\n\n    # open the view\n    view.open()\n\n\nModalView Events\n----------------\n\nThere are two events available: `on_open` which is raised when the view is\nopening, and `on_dismiss` which is raised when the view is closed.\nFor `on_dismiss`, you can prevent the view from closing by explictly returning\nTrue from your callback. ::\n\n    def my_callback(instance):\n        print('ModalView', instance, 'is being dismissed, but is prevented!')\n        return True\n    view = ModalView()\n    view.add_widget(Label(text='Hello world'))\n    view.bind(on_dismiss=my_callback)\n    view.open()\n\n\n.. versionchanged:: 1.5.0\n    The ModalView can be closed by hitting the escape key on the\n    keyboard if the :attr:`ModalView.auto_dismiss` property is True (the\n    default).\n\n'''\n\n__all__ = ('ModalView', )\n\nfrom kivy.logger import Logger\nfrom kivy.animation import Animation\nfrom kivy.uix.anchorlayout import AnchorLayout\nfrom kivy.properties import StringProperty, BooleanProperty, ObjectProperty, \\\n    NumericProperty, ListProperty\n\n\nclass ModalView(AnchorLayout):\n    '''ModalView class. See module documentation for more information.\n\n    :Events:\n        `on_open`:\n            Fired when the ModalView is opened.\n        `on_dismiss`:\n            Fired when the ModalView is closed. If the callback returns True,\n            the dismiss will be canceled.\n    '''\n\n    auto_dismiss = BooleanProperty(True)\n    '''This property determines if the view is automatically\n    dismissed when the user clicks outside it.\n\n    :attr:`auto_dismiss` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n\n    attach_to = ObjectProperty(None)\n    '''If a widget is set on attach_to, the view will attach to the nearest\n    parent window of the widget. If none is found, it will attach to the\n    main/global Window.\n\n    :attr:`attach_to` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    background_color = ListProperty([0, 0, 0, .7])\n    '''Background color in the format (r, g, b, a).\n\n    :attr:`background_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [0, 0, 0, .7].\n    '''\n\n    background = StringProperty(\n        'atlas://data/images/defaulttheme/modalview-background')\n    '''Background image of the view used for the view background.\n\n    :attr:`background` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/modalview-background'.\n    '''\n\n    border = ListProperty([16, 16, 16, 16])\n    '''Border used for :class:`~kivy.graphics.vertex_instructions.BorderImage`\n    graphics instruction. Used for the :attr:`background_normal` and the\n    :attr:`background_down` properties. Can be used when using custom\n    backgrounds.\n\n    It must be a list of four values: (top, right, bottom, left). Read the\n    BorderImage instructions for more information about how to use it.\n\n    :attr:`border` is a :class:`~kivy.properties.ListProperty` and defaults to\n    (16, 16, 16, 16).\n    '''\n\n    # Internals properties used for graphical representation.\n\n    _anim_alpha = NumericProperty(0)\n\n    _anim_duration = NumericProperty(.1)\n\n    _window = ObjectProperty(None, allownone=True)\n\n    __events__ = ('on_open', 'on_dismiss')\n\n    def __init__(self, **kwargs):\n        self._parent = None\n        super(ModalView, self).__init__(**kwargs)\n\n    def _search_window(self):\n        # get window to attach to\n        window = None\n        if self.attach_to is not None:\n            window = self.attach_to.get_parent_window()\n            if not window:\n                window = self.attach_to.get_root_window()\n        if not window:\n            from kivy.core.window import Window\n            window = Window\n        return window\n\n    def open(self, *largs):\n        '''Show the view window from the :attr:`attach_to` widget. If set, it\n        will attach to the nearest window. If the widget is not attached to any\n        window, the view will attach to the global\n        :class:`~kivy.core.window.Window`.\n        '''\n        if self._window is not None:\n            Logger.warning('ModalView: you can only open once.')\n            return self\n        # search window\n        self._window = self._search_window()\n        if not self._window:\n            Logger.warning('ModalView: cannot open view, no window found.')\n            return self\n        self._window.add_widget(self)\n        self._window.bind(\n            on_resize=self._align_center,\n            on_keyboard=self._handle_keyboard)\n        self.center = self._window.center\n        self.bind(size=self._update_center)\n        a = Animation(_anim_alpha=1., d=self._anim_duration)\n        a.bind(on_complete=lambda *x: self.dispatch('on_open'))\n        a.start(self)\n        return self\n\n    def _update_center(self, *args):\n        if not self._window:\n            return\n        # XXX HACK DONT REMOVE OR FOUND AND FIX THE ISSUE\n        # It seems that if we don't access to the center before assigning a new\n        # value, no dispatch will be done >_>\n        self.center = self._window.center\n\n    def dismiss(self, *largs, **kwargs):\n        '''Close the view if it is open. If you really want to close the\n        view, whatever the on_dismiss event returns, you can use the *force*\n        argument:\n        ::\n\n            view = ModalView(...)\n            view.dismiss(force=True)\n\n        When the view is dismissed, it will be faded out before being\n        removed from the parent. If you don't want animation, use::\n\n            view.dismiss(animation=False)\n\n        '''\n        if self._window is None:\n            return self\n        if self.dispatch('on_dismiss') is True:\n            if kwargs.get('force', False) is not True:\n                return self\n        if kwargs.get('animation', True):\n            Animation(_anim_alpha=0., d=self._anim_duration).start(self)\n        else:\n            self._anim_alpha = 0\n            self._real_remove_widget()\n        return self\n\n    def on_size(self, instance, value):\n        self._align_center()\n\n    def _align_center(self, *l):\n        if self._window:\n            self.center = self._window.center\n            # hack to resize dark background on window resize\n            _window = self._window\n            self._window = None\n            self._window = _window\n\n    def on_touch_down(self, touch):\n        if not self.collide_point(*touch.pos):\n            if self.auto_dismiss:\n                self.dismiss()\n                return True\n        super(ModalView, self).on_touch_down(touch)\n        return True\n\n    def on_touch_move(self, touch):\n        super(ModalView, self).on_touch_move(touch)\n        return True\n\n    def on_touch_up(self, touch):\n        super(ModalView, self).on_touch_up(touch)\n        return True\n\n    def on__anim_alpha(self, instance, value):\n        if value == 0 and self._window is not None:\n            self._real_remove_widget()\n\n    def _real_remove_widget(self):\n        if self._window is None:\n            return\n        self._window.remove_widget(self)\n        self._window.unbind(\n            on_resize=self._align_center,\n            on_keyboard=self._handle_keyboard)\n        self._window = None\n\n    def on_open(self):\n        pass\n\n    def on_dismiss(self):\n        pass\n\n    def _handle_keyboard(self, window, key, *largs):\n        if key == 27 and self.auto_dismiss:\n            self.dismiss()\n            return True\n\n\nif __name__ == '__main__':\n    from kivy.base import runTouchApp\n    from kivy.uix.button import Button\n    from kivy.uix.label import Label\n    from kivy.uix.gridlayout import GridLayout\n    from kivy.core.window import Window\n\n    # add view\n    content = GridLayout(cols=1)\n    content.add_widget(Label(text='This is a hello world'))\n    view = ModalView(size_hint=(None, None), size=(256, 256),\n                     auto_dismiss=True)\n    view.add_widget(content)\n\n    def open_view(btn):\n        view.open()\n\n    layout = GridLayout(cols=3)\n    for x in range(9):\n        btn = Button(text='click me %s' % x)\n        btn.bind(on_release=view.open)\n        layout.add_widget(btn)\n    Window.add_widget(layout)\n\n    view.open()\n\n    runTouchApp()\n"
  },
  {
    "path": "tickeys/kivy/uix/pagelayout.py",
    "content": "\"\"\"\nPageLayout\n==========\n\nThe :class:`PageLayout` class is used to create a simple multi-page\nlayout, in a way that allows easy flipping from one page to another using\nborders.\n\n:class:`PageLayout` does not currently honor\n:attr:`~kivy.uix.widget.Widget.size_hint` or\n:attr:`~kivy.uix.widget.Widget.pos_hint` properties.\n\n.. versionadded:: 1.8.0\n\nExample::\n\n    PageLayout:\n        Button:\n            text: 'page1'\n        Button:\n            text: 'page2'\n        Button:\n            text: 'page3'\n\nTransitions from one page to the next are made by swiping in from the border\nareas on the right or left hand side. If you wish to display multiple widgets\nin a page, we suggest you use a containing layout. Ideally, each page should\nconsist of a single :mod:`~kivy.uix.layout` widget that contains the remaining\nwidgets on that page.\n\"\"\"\n\n__all__ = ('PageLayout', )\n\nfrom kivy.uix.layout import Layout\nfrom kivy.properties import NumericProperty\nfrom kivy.animation import Animation\n\n\nclass PageLayout(Layout):\n    '''PageLayout class. See module documentation for more information.\n    '''\n\n    page = NumericProperty(0)\n    '''The currently displayed page.\n\n    :data:`page` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 0.\n    '''\n\n    border = NumericProperty('50dp')\n    '''The width of the border around the current page used to display\n    the previous/next page swipe areas when needed.\n\n    :data:`border` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 50dp.\n    '''\n\n    swipe_threshold = NumericProperty(.5)\n    '''The thresold used to trigger swipes as percentage of the widget\n    size.\n\n    :data:`swipe_threshold` is a :class:`~kivy.properties.NumericProperty`\n    and defaults to .5.\n    '''\n\n    def __init__(self, **kwargs):\n        super(PageLayout, self).__init__(**kwargs)\n\n        self.bind(\n            border=self._trigger_layout,\n            page=self._trigger_layout,\n            parent=self._trigger_layout,\n            children=self._trigger_layout,\n            size=self._trigger_layout,\n            pos=self._trigger_layout)\n\n    def do_layout(self, *largs):\n        l_children = len(self.children) - 1\n        h = self.height\n        x_parent, y_parent = self.pos\n        p = self.page\n        border = self.border\n        half_border = border / 2.\n        right = self.right\n        width = self.width - border\n        for i, c in enumerate(reversed(self.children)):\n            not i or i == l_children\n\n            if i < p:\n                x = x_parent\n            elif i == p:\n                if not p:  # it's first page\n                    x = x_parent\n                elif p != l_children:  # not first, but there are post pages\n                    x = x_parent + half_border\n                else:  # not first and there are no post pages\n                    x = x_parent + border\n            elif i == p + 1:\n                if not p:  # second page - no left margin\n                    x = right - border\n                else:  # there's already a left margin\n                    x = right - half_border\n            else:\n                x = right\n\n            c.height = h\n            c.width = width\n\n            Animation(\n                x=x,\n                y=y_parent,\n                d=.5, t='in_quad').start(c)\n\n    def on_touch_down(self, touch):\n        if (self.disabled or not self.collide_point(*touch.pos) or\n            not self.children):\n            return\n\n        page = self.children[-self.page - 1]\n        if self.x <= touch.x < page.x:\n            touch.ud['page'] = 'previous'\n            touch.grab(self)\n            return True\n        elif page.right <= touch.x < self.right:\n            touch.ud['page'] = 'next'\n            touch.grab(self)\n            return True\n        return page.on_touch_down(touch)\n\n    def on_touch_move(self, touch):\n        if touch.grab_current != self:\n            return\n\n        p = self.page\n        border = self.border\n        half_border = border / 2.\n        page = self.children[-p - 1]\n        if touch.ud['page'] == 'previous':\n            # move next page upto right edge\n            if p < len(self.children) - 1:\n                self.children[-p - 2].x = min(\n                    self.right - self.border * (1 - (touch.sx - touch.osx)),\n                    self.right)\n\n            # move current page until edge hits the right border\n            if p >= 1:\n                b_right = half_border if p > 1 else border\n                b_left = half_border if p < len(self.children) - 1 else border\n                self.children[-p - 1].x = max(min(\n                    self.x + b_left + (touch.x - touch.ox),\n                    self.right - b_right),\n                    self.x + b_left)\n\n            # move previous page left edge upto left border\n            if p > 1:\n                self.children[-p].x = min(\n                    self.x + half_border * (touch.sx - touch.osx),\n                    self.x + half_border)\n\n        elif touch.ud['page'] == 'next':\n            # move current page upto left edge\n            if p >= 1:\n                self.children[-p - 1].x = max(\n                    self.x + half_border * (1 - (touch.osx - touch.sx)),\n                    self.x)\n\n            # move next page until its edge hit the left border\n            if p < len(self.children) - 1:\n                b_right = half_border if p >= 1 else border\n                b_left = half_border if p < len(self.children) - 2 else border\n                self.children[-p - 2].x = min(max(\n                    self.right - b_right + (touch.x - touch.ox),\n                    self.x + b_left),\n                    self.right - b_right)\n\n            # move second next page upto right border\n            if p < len(self.children) - 2:\n                self.children[-p - 3].x = max(\n                    self.right + half_border * (touch.sx - touch.osx),\n                    self.right - half_border)\n\n        return page.on_touch_move(touch)\n\n    def on_touch_up(self, touch):\n        if touch.grab_current == self:\n            if (\n                touch.ud['page'] == 'previous' and\n                abs(touch.x - touch.ox) / self.width > self.swipe_threshold\n            ):\n                self.page -= 1\n            elif (\n                touch.ud['page'] == 'next' and\n                abs(touch.x - touch.ox) / self.width > self.swipe_threshold\n            ):\n                self.page += 1\n            else:\n                self._trigger_layout()\n\n            touch.ungrab(self)\n        return self.children[-self.page + 1].on_touch_up(touch)\n\n\nif __name__ == '__main__':\n    from kivy.base import runTouchApp\n    from kivy.uix.button import Button\n\n    pl = PageLayout()\n    for i in range(1, 4):\n        b = Button(text='page%s' % i)\n        pl.add_widget(b)\n\n    runTouchApp(pl)\n"
  },
  {
    "path": "tickeys/kivy/uix/popup.py",
    "content": "'''\nPopup\n=====\n\n.. versionadded:: 1.0.7\n\n.. image:: images/popup.jpg\n    :align: right\n\nThe :class:`Popup` widget is used to create modal popups. By default, the popup\nwill cover the whole \"parent\" window. When you are creating a popup, you\nmust at least set a :attr:`Popup.title` and :attr:`Popup.content`.\n\nRemember that the default size of a Widget is size_hint=(1, 1). If you don't\nwant your popup to be fullscreen, either use size hints with values less than 1\n(for instance size_hint=(.8, .8)) or deactivate the size_hint and use\nfixed size attributes.\n\n\n.. versionchanged:: 1.4.0\n    The :class:`Popup` class now inherits from\n    :class:`~kivy.uix.modalview.ModalView`. The :class:`Popup` offers a default\n    layout with a title and a separation bar.\n\nExamples\n--------\n\nExample of a simple 400x400 Hello world popup::\n\n    popup = Popup(title='Test popup',\n        content=Label(text='Hello world'),\n        size_hint=(None, None), size=(400, 400))\n\nBy default, any click outside the popup will dismiss/close it. If you don't\nwant that, you can set\n:attr:`~kivy.uix.modalview.ModalView.auto_dismiss` to False::\n\n    popup = Popup(title='Test popup', content=Label(text='Hello world'),\n                  auto_dismiss=False)\n    popup.open()\n\nTo manually dismiss/close the popup, use\n:attr:`~kivy.uix.modalview.ModalView.dismiss`::\n\n    popup.dismiss()\n\nBoth :meth:`~kivy.uix.modalview.ModalView.open` and\n:meth:`~kivy.uix.modalview.ModalView.dismiss` are bindable. That means you\ncan directly bind the function to an action, e.g. to a button's on_press::\n\n    # create content and add to the popup\n    content = Button(text='Close me!')\n    popup = Popup(content=content, auto_dismiss=False)\n\n    # bind the on_press event of the button to the dismiss function\n    content.bind(on_press=popup.dismiss)\n\n    # open the popup\n    popup.open()\n\n\nPopup Events\n------------\n\nThere are two events available: `on_open` which is raised when the popup is\nopening, and `on_dismiss` which is raised when the popup is closed.\nFor `on_dismiss`, you can prevent the\npopup from closing by explictly returning True from your callback::\n\n    def my_callback(instance):\n        print('Popup', instance, 'is being dismissed but is prevented!')\n        return True\n    popup = Popup(content=Label(text='Hello world'))\n    popup.bind(on_dismiss=my_callback)\n    popup.open()\n\n'''\n\n__all__ = ('Popup', 'PopupException')\n\nfrom kivy.uix.modalview import ModalView\nfrom kivy.properties import (StringProperty, ObjectProperty, OptionProperty,\n                             NumericProperty, ListProperty)\n\n\nclass PopupException(Exception):\n    '''Popup exception, fired when multiple content widgets are added to the\n    popup.\n\n    .. versionadded:: 1.4.0\n    '''\n\n\nclass Popup(ModalView):\n    '''Popup class. See module documentation for more information.\n\n    :Events:\n        `on_open`:\n            Fired when the Popup is opened.\n        `on_dismiss`:\n            Fired when the Popup is closed. If the callback returns True, the\n            dismiss will be canceled.\n    '''\n\n    title = StringProperty('No title')\n    '''String that represents the title of the popup.\n\n    :attr:`title` is a :class:`~kivy.properties.StringProperty` and defaults to\n    'No title'.\n    '''\n\n    title_size = NumericProperty('14sp')\n    '''Represents the font size of the popup title.\n\n    .. versionadded:: 1.6.0\n\n    :attr:`title_size` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to '14sp'.\n    '''\n\n    title_align = OptionProperty('left',\n                                 options=['left', 'center', 'right', 'justify'])\n    '''Horizontal alignment of the title.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`title_align` is a :class:`~kivy.properties.OptionProperty` and\n    defaults to 'left'. Available options are left, middle, right and justify.\n    '''\n\n    title_font = StringProperty('DroidSans')\n    '''Font used to render the title text.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`title_font` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'DroidSans'.\n    '''\n\n    content = ObjectProperty(None)\n    '''Content of the popup that is displayed just under the title.\n\n    :attr:`content` is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    title_color = ListProperty([1, 1, 1, 1])\n    '''Color used by the Title.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`title_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [1, 1, 1, 1].\n    '''\n\n    separator_color = ListProperty([47 / 255., 167 / 255., 212 / 255., 1.])\n    '''Color used by the separator between title and content.\n\n    .. versionadded:: 1.1.0\n\n    :attr:`separator_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [47 / 255., 167 / 255., 212 / 255., 1.]\n    '''\n\n    separator_height = NumericProperty('2dp')\n    '''Height of the separator.\n\n    .. versionadded:: 1.1.0\n\n    :attr:`separator_height` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 2dp.\n    '''\n\n    # Internal properties used for graphical representation.\n\n    _container = ObjectProperty(None)\n\n    def add_widget(self, widget):\n        if self._container:\n            if self.content:\n                raise PopupException(\n                    'Popup can have only one widget as content')\n            self.content = widget\n        else:\n            super(Popup, self).add_widget(widget)\n\n    def on_content(self, instance, value):\n        if self._container:\n            self._container.clear_widgets()\n            self._container.add_widget(value)\n\n    def on__container(self, instance, value):\n        if value is None or self.content is None:\n            return\n        self._container.clear_widgets()\n        self._container.add_widget(self.content)\n\n    def on_touch_down(self, touch):\n        if self.disabled and self.collide_point(*touch.pos):\n            return True\n        return super(Popup, self).on_touch_down(touch)\n\n\nif __name__ == '__main__':\n    from kivy.base import runTouchApp\n    from kivy.uix.button import Button\n    from kivy.uix.label import Label\n    from kivy.uix.gridlayout import GridLayout\n    from kivy.core.window import Window\n\n    # add popup\n    content = GridLayout(cols=1)\n    content_cancel = Button(text='Cancel', size_hint_y=None, height=40)\n    content.add_widget(Label(text='This is a hello world'))\n    content.add_widget(content_cancel)\n    popup = Popup(title='Test popup',\n                  size_hint=(None, None), size=(256, 256),\n                  content=content, disabled=True)\n    content_cancel.bind(on_release=popup.dismiss)\n\n    layout = GridLayout(cols=3)\n    for x in range(9):\n        btn = Button(text=str(x))\n        btn.bind(on_release=popup.open)\n        layout.add_widget(btn)\n\n    Window.add_widget(layout)\n\n    popup.open()\n\n    runTouchApp()\n"
  },
  {
    "path": "tickeys/kivy/uix/progressbar.py",
    "content": "'''\nProgress Bar\n============\n\n.. versionadded:: 1.0.8\n\n.. image:: images/progressbar.jpg\n    :align: right\n\nThe :class:`ProgressBar` widget is used to visualize the progress of some task.\nOnly the horizontal mode is currently supported: the vertical mode is not\nyet available.\n\nThe progress bar has no interactive elements and is a display-only widget.\n\nTo use it, simply assign a value to indicate the current progress::\n\n    from kivy.uix.progressbar import ProgressBar\n    pb = ProgressBar(max=1000)\n\n    # this will update the graphics automatically (75% done)\n    pb.value = 750\n\n'''\n\n__all__ = ('ProgressBar', )\n\nfrom kivy.uix.widget import Widget\nfrom kivy.properties import NumericProperty, AliasProperty\n\n\nclass ProgressBar(Widget):\n    '''Class for creating a progress bar widget.\n\n    See module documentation for more details.\n    '''\n\n    def __init__(self, **kwargs):\n        self._value = 0.\n        super(ProgressBar, self).__init__(**kwargs)\n\n    def _get_value(self):\n        return self._value\n\n    def _set_value(self, value):\n        value = max(0, min(self.max, value))\n        if value != self._value:\n            self._value = value\n            return True\n\n    value = AliasProperty(_get_value, _set_value)\n    '''Current value used for the slider.\n\n    :attr:`value` is an :class:`~kivy.properties.AliasProperty` that\n    returns the value of the progress bar. If the value is < 0 or >\n    :attr:`max`, it will be normalized to those boundaries.\n\n    .. versionchanged:: 1.6.0\n        The value is now limited to between 0 and :attr:`max`.\n    '''\n\n    def get_norm_value(self):\n        d = self.max\n        if d == 0:\n            return 0\n        return self.value / float(d)\n\n    def set_norm_value(self, value):\n        self.value = value * self.max\n\n    value_normalized = AliasProperty(get_norm_value, set_norm_value,\n                                     bind=('value', 'max'))\n    '''Normalized value inside the range 0-1::\n\n        >>> pb = ProgressBar(value=50, max=100)\n        >>> pb.value\n        50\n        >>> slider.value_normalized\n        0.5\n\n    :attr:`value_normalized` is an :class:`~kivy.properties.AliasProperty`.\n    '''\n\n    max = NumericProperty(100.)\n    '''Maximum value allowed for :attr:`value`.\n\n    :attr:`max` is a :class:`~kivy.properties.NumericProperty` and defaults to\n    100.\n    '''\n\n\nif __name__ == '__main__':\n\n    from kivy.base import runTouchApp\n    runTouchApp(ProgressBar(value=50))\n"
  },
  {
    "path": "tickeys/kivy/uix/relativelayout.py",
    "content": "'''\nRelative Layout\n===============\n\n.. versionadded:: 1.4.0\n\n\nThis layout allows you to set relative coordinates for children. If you want\nabsolute positioning, use the :class:`~kivy.uix.floatlayout.FloatLayout`.\n\nThe :class:`RelativeLayout` class behaves just like the regular\n:class:`FloatLayout` except that its child widgets are positioned relative to\nthe layout.\n\nWhen a widget with position = (0,0) is added to a RelativeLayout,\nthe child widget will also move when the position of the RelativeLayout\nis changed. The child widgets coordinates remain (0,0) as they are\nalways relative to the parent layout.\n\nCoordinate Systems\n------------------\n\nWindow coordinates\n~~~~~~~~~~~~~~~~~~\n\nBy default, there's only one coordinate system that defines the position of\nwidgets and touch events dispatched to them: the window coordinate system,\nwhich places (0, 0) at the bottom left corner of the window.\nAlthough there are other coordinate systems defined, e.g. local\nand parent coordinates, these coordinate systems are identical to the window\ncoordinate system as long as a relative layout type widget is not in the\nwidget's parent stack. When widget.pos is read or a touch is received,\nthe coordinate values are in parent coordinates, but as mentioned, these are\nidentical to window coordinates, even in complex widget stacks.\n\nFor example::\n\n    BoxLayout:\n        Label:\n            text: 'Left'\n        Button:\n            text: 'Middle'\n            on_touch_down: print('Middle: {}'.format(args[1].pos))\n        BoxLayout:\n            on_touch_down: print('Box: {}'.format(args[1].pos))\n            Button:\n                text: 'Right'\n                on_touch_down: print('Right: {}'.format(args[1].pos))\n\nWhen the middle button is clicked and the touch propagates through the\ndifferent parent coordinate systems, it prints the following::\n\n    >>> Box: (430.0, 282.0)\n    >>> Right: (430.0, 282.0)\n    >>> Middle: (430.0, 282.0)\n\nAs claimed, the touch has identical coordinates to the window coordinates\nin every coordinate system. :meth:`~kivy.uix.widget.Widget.collide_point`\nfor example, takes the point in window coordinates.\n\nParent coordinates\n~~~~~~~~~~~~~~~~~~\n\nOther :class:`RelativeLayout` type widgets are\n:class:`~kivy.uix.scatter.Scatter`,\n:class:`~kivy.uix.scatterlayout.ScatterLayout`,\nand :class:`~kivy.uix.scrollview.ScrollView`. If such a special widget is in\nthe parent stack, only then does the parent and local coordinate system\ndiverge from the window coordinate system. For each such widget in the stack,\na coordinate system with (0, 0) of that coordinate system being at the bottom\nleft corner of that widget is created. **Position and touch coordinates\nreceived and read by a widget are in the coordinate system of the most\nrecent special widget in its parent stack (not including itself) or in window\ncoordinates if there are none** (as in the first example). We call these\ncoordinates parent coordinates.\n\n\nFor example::\n\n    BoxLayout:\n        Label:\n            text: 'Left'\n        Button:\n            text: 'Middle'\n            on_touch_down: print('Middle: {}'.format(args[1].pos))\n        RelativeLayout:\n            on_touch_down: print('Relative: {}'.format(args[1].pos))\n            Button:\n                text: 'Right'\n                on_touch_down: print('Right: {}'.format(args[1].pos))\n\nClicking on the middle button prints::\n\n    >>> Relative: (396.0, 298.0)\n    >>> Right: (-137.33, 298.0)\n    >>> Middle: (396.0, 298.0)\n\nAs the touch propagates through the widgets, for each widget, the\ntouch is received in parent coordinates. Because both the relative and middle\nwidgets don't have these special widgets in their parent stack, the touch is\nthe same as window coordinates. Only the right widget, which has a\nRelativeLayout in its parent stack, receives the touch in coordinates relative\nto that RelativeLayout which is different than window coordinates.\n\nLocal and Widget coordinates\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nWhen expressed in parent coordinates, the position is expressed in the\ncoordinates of the most recent special widget in its parent stack, not\nincluding itself. When expressed in local or widget coordinates, the widgets\nthemselves are also included.\n\nChanging the above example to transform the parent coordinates into local\ncoordinates::\n\n    BoxLayout:\n        Label:\n            text: 'Left'\n        Button:\n            text: 'Middle'\n            on_touch_down: print('Middle: {}'.format(\\\nself.to_local(*args[1].pos)))\n        RelativeLayout:\n            on_touch_down: print('Relative: {}'.format(\\\nself.to_local(*args[1].pos)))\n            Button:\n                text: 'Right'\n                on_touch_down: print('Right: {}'.format(\\\nself.to_local(*args[1].pos)))\n\nNow, clicking on the middle button prints::\n\n    >>> Relative: (-135.33, 301.0)\n    >>> Right: (-135.33, 301.0)\n    >>> Middle: (398.0, 301.0)\n\nThis is because now the relative widget also expresses the coordinates\nrelative to itself.\n\nCoordinate transformations\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n:class:`~kivy.uix.widget.Widget` provides 4 functions to transform coordinates\nbetween the various coordinate systems. For now, we assume that the `relative`\nkeyword of these functions is `False`.\n:meth:`~kivy.uix.widget.Widget.to_widget` takes the coordinates expressed in\nwindow coordinates and returns them in local (widget) coordinates.\n:meth:`~kivy.uix.widget.Widget.to_window` takes the coordinates expressed in\nlocal coordinates and returns them in window coordinates.\n:meth:`~kivy.uix.widget.Widget.to_parent` takes the coordinates expressed in\nlocal coordinates and returns them in parent coordinates.\n:meth:`~kivy.uix.widget.Widget.to_local` takes the coordinates expressed in\nparent coordinates and returns them in local coordinates.\n\nEach of the 4 transformation functions take a `relative` parameter. When the\nrelative parameter is True, the coordinates are returned or originate in\ntrue relative coordinates - relative to a coordinate system with its (0, 0) at\nthe bottom left corner of the widget in question.\n\n.. _kivy-uix-relativelayout-common-pitfalls:\n\nCommon Pitfalls\n---------------\n\nAs all positions within a :class:`RelativeLayout` are relative to the position\nof the layout itself, the position of the layout should never be used in\ndetermining the position of sub-widgets or the layout's :attr:`canvas`.\n\nTake the following kv code for example:\n\n.. container:: align-right\n\n    .. figure:: images/relativelayout-fixedposition.png\n        :scale: 50%\n\n        expected result\n\n    .. figure:: images/relativelayout-doubleposition.png\n        :scale: 50%\n\n        actual result\n\n.. code::\n\n    FloatLayout:\n        Widget:\n            size_hint: None, None\n            size: 200, 200\n            pos: 200, 200\n\n            canvas:\n                Color:\n                    rgba: 1, 1, 1, 1\n                Rectangle:\n                    pos: self.pos\n                    size: self.size\n\n        RelativeLayout:\n            size_hint: None, None\n            size: 200, 200\n            pos: 200, 200\n\n            canvas:\n                Color:\n                    rgba: 1, 0, 0, 0.5\n                Rectangle:\n                    pos: self.pos  # incorrect\n                    size: self.size\n\nYou might expect this to render a single pink rectangle; however, the content\nof the :class:`RelativeLayout` is already transformed, so the use of\n`pos: self.pos` will double that transformation. In this case, using\n`pos: 0, 0` or omitting `pos` completely will provide the expected result.\n\nThis also applies to the position of sub-widgets. Instead of positioning a\n:class:`~kivy.uix.widget.Widget` based on the layout's own position::\n\n    RelativeLayout:\n        Widget:\n            pos: self.parent.pos\n        Widget:\n            center: self.parent.center\n\n...use the :attr:`pos_hint` property::\n\n    RelativeLayout:\n        Widget:\n            pos_hint: {'x': 0, 'y': 0}\n        Widget:\n            pos_hint: {'center_x': 0.5, 'center_y': 0.5}\n\n.. versionchanged:: 1.7.0\n    Prior to version 1.7.0, the :class:`RelativeLayout` was implemented as a\n    :class:`~kivy.uix.floatlayout.FloatLayout` inside a\n    :class:`~kivy.uix.scatter.Scatter`. This behaviour/widget has\n    been renamed to `ScatterLayout`. The :class:`RelativeLayout` now only\n    supports relative positions (and can't be rotated, scaled or translated on\n    a multitouch system using two or more fingers). This was done so that the\n    implementation could be optimized and avoid the heavier calculations of\n    :class:`Scatter` (e.g. inverse matrix, recaculating multiple properties\n    etc.)\n\n'''\n\n__all__ = ('RelativeLayout', )\n\nfrom kivy.uix.floatlayout import FloatLayout\n\n\nclass RelativeLayout(FloatLayout):\n    '''RelativeLayout class, see module documentation for more information.\n    '''\n\n    def __init__(self, **kw):\n        super(RelativeLayout, self).__init__(**kw)\n        self.unbind(pos=self._trigger_layout,\n                    pos_hint=self._trigger_layout)\n\n    def do_layout(self, *args):\n        super(RelativeLayout, self).do_layout(pos=(0, 0))\n\n    def to_parent(self, x, y, **k):\n        return (x + self.x, y + self.y)\n\n    def to_local(self, x, y, **k):\n        return (x - self.x, y - self.y)\n\n    def _apply_transform(self, m):\n        m.translate(self.x, self.y, 0)\n        return super(RelativeLayout, self)._apply_transform(m)\n\n    def on_touch_down(self, touch):\n        x, y = touch.x, touch.y\n        touch.push()\n        touch.apply_transform_2d(self.to_local)\n        ret = super(RelativeLayout, self).on_touch_down(touch)\n        touch.pop()\n        return ret\n\n    def on_touch_move(self, touch):\n        x, y = touch.x, touch.y\n        touch.push()\n        touch.apply_transform_2d(self.to_local)\n        ret = super(RelativeLayout, self).on_touch_move(touch)\n        touch.pop()\n        return ret\n\n    def on_touch_up(self, touch):\n        x, y = touch.x, touch.y\n        touch.push()\n        touch.apply_transform_2d(self.to_local)\n        ret = super(RelativeLayout, self).on_touch_up(touch)\n        touch.pop()\n        return ret\n"
  },
  {
    "path": "tickeys/kivy/uix/rst.py",
    "content": "'''\nreStructuredText renderer\n=========================\n\n.. versionadded:: 1.1.0\n\n`reStructuredText <http://docutils.sourceforge.net/rst.html>`_ is an\neasy-to-read, what-you-see-is-what-you-get plaintext markup syntax and parser\nsystem.\n\n.. warning::\n\n    This widget is highly experimental. The whole styling and\n    implementation are not stable until this warning has been removed.\n\nUsage with Text\n---------------\n\n::\n\n    text = \"\"\"\n    .. _top:\n\n    Hello world\n    ===========\n\n    This is an **emphased text**, some ``interpreted text``.\n    And this is a reference to top_::\n\n        $ print(\"Hello world\")\n\n    \"\"\"\n    document = RstDocument(text=text)\n\nThe rendering will output:\n\n.. image:: images/rstdocument.png\n\nUsage with Source\n-----------------\n\nYou can also render a rst file using the :attr:`RstDocument.source` property::\n\n    document = RstDocument(source='index.rst')\n\nYou can reference other documents with the role ``:doc:``. For example, in the\ndocument ``index.rst`` you can write::\n\n    Go to my next document: :doc:`moreinfo.rst`\n\nIt will generate a link that, when clicked, opens the ``moreinfo.rst``\ndocument.\n\n'''\n\n__all__ = ('RstDocument', )\n\nimport os\nfrom os.path import dirname, join, exists, abspath\nfrom kivy.clock import Clock\nfrom kivy.compat import PY2\nfrom kivy.properties import ObjectProperty, NumericProperty, \\\n    DictProperty, ListProperty, StringProperty, \\\n    BooleanProperty, OptionProperty, AliasProperty\nfrom kivy.lang import Builder\nfrom kivy.utils import get_hex_from_color, get_color_from_hex\nfrom kivy.uix.widget import Widget\nfrom kivy.uix.scrollview import ScrollView\nfrom kivy.uix.gridlayout import GridLayout\nfrom kivy.uix.label import Label\nfrom kivy.uix.image import AsyncImage, Image\nfrom kivy.uix.videoplayer import VideoPlayer\nfrom kivy.uix.anchorlayout import AnchorLayout\nfrom kivy.animation import Animation\nfrom kivy.logger import Logger\nfrom docutils.parsers import rst\nfrom docutils.parsers.rst import roles\nfrom docutils import nodes, frontend, utils\nfrom docutils.parsers.rst import Directive, directives\nfrom docutils.parsers.rst.roles import set_classes\nfrom kivy.parser import parse_color\n\n\n#\n# Handle some additional roles\n#\nif 'KIVY_DOC' not in os.environ:\n\n    class role_doc(nodes.Inline, nodes.TextElement):\n        pass\n\n    class role_video(nodes.General, nodes.TextElement):\n        pass\n\n    class VideoDirective(Directive):\n        has_content = False\n        required_arguments = 1\n        optional_arguments = 0\n        final_argument_whitespace = True\n        option_spec = {'width': directives.nonnegative_int,\n                       'height': directives.nonnegative_int}\n\n        def run(self):\n            set_classes(self.options)\n            node = role_video(source=self.arguments[0], **self.options)\n            return [node]\n\n    generic_docroles = {\n        'doc': role_doc}\n\n    for rolename, nodeclass in generic_docroles.items():\n        generic = roles.GenericRole(rolename, nodeclass)\n        role = roles.CustomRole(rolename, generic, {'classes': [rolename]})\n        roles.register_local_role(rolename, role)\n\n    directives.register_directive('video', VideoDirective)\n\nBuilder.load_string('''\n#:import parse_color kivy.parser.parse_color\n\n\n\n<RstDocument>:\n    content: content\n    scatter: scatter\n    do_scroll_x: False\n    canvas.before:\n        Color:\n            rgba: parse_color(root.colors['background'])\n        Rectangle:\n            pos: self.pos\n            size: self.size\n\n    Scatter:\n        id: scatter\n        size_hint_y: None\n        height: content.minimum_height\n        width: root.width\n        scale: 1\n        do_translation: False, False\n        do_scale: False\n        do_rotation: False\n\n        GridLayout:\n            id: content\n            cols: 1\n            height: self.minimum_height\n            width: root.width\n            padding: 10\n\n<RstTitle>:\n    markup: True\n    valign: 'top'\n    font_size:\n        sp(self.document.base_font_size - self.section * (\n        self.document.base_font_size / 31.0 * 2))\n    size_hint_y: None\n    height: self.texture_size[1] + dp(20)\n    text_size: self.width, None\n    bold: True\n\n    canvas:\n        Color:\n            rgba: parse_color(self.document.underline_color)\n        Rectangle:\n            pos: self.x, self.y + 5\n            size: self.width, 1\n\n\n<RstParagraph>:\n    markup: True\n    valign: 'top'\n    size_hint_y: None\n    height: self.texture_size[1] + self.my\n    text_size: self.width - self.mx, None\n    font_size: sp(self.document.base_font_size / 2.0)\n\n<RstTerm>:\n    size_hint: None, None\n    height: label.height\n    anchor_x: 'left'\n    Label:\n        id: label\n        text: root.text\n        markup: True\n        valign: 'top'\n        size_hint: None, None\n        size: self.texture_size[0] + dp(10), self.texture_size[1] + dp(10)\n        font_size: sp(root.document.base_font_size / 2.0)\n\n<RstBlockQuote>:\n    cols: 2\n    content: content\n    size_hint_y: None\n    height: content.height\n    Widget:\n        size_hint_x: None\n        width: 20\n    GridLayout:\n        id: content\n        cols: 1\n        size_hint_y: None\n        height: self.minimum_height\n\n<RstLiteralBlock>:\n    cols: 1\n    content: content\n    size_hint_y: None\n    height: content.texture_size[1] + dp(20)\n    canvas:\n        Color:\n            rgb: parse_color('#cccccc')\n        Rectangle:\n            pos: self.x - 1, self.y - 1\n            size: self.width + 2, self.height + 2\n        Color:\n            rgb: parse_color('#eeeeee')\n        Rectangle:\n            pos: self.pos\n            size: self.size\n    Label:\n        id: content\n        markup: True\n        valign: 'top'\n        text_size: self.width - 20, None\n        font_name: 'data/fonts/DroidSansMono.ttf'\n        color: (0, 0, 0, 1)\n\n<RstList>:\n    cols: 2\n    size_hint_y: None\n    height: self.minimum_height\n\n<RstListItem>:\n    cols: 1\n    size_hint_y: None\n    height: self.minimum_height\n\n<RstSystemMessage>:\n    cols: 1\n    size_hint_y: None\n    height: self.minimum_height\n    canvas:\n        Color:\n            rgba: 1, 0, 0, .3\n        Rectangle:\n            pos: self.pos\n            size: self.size\n\n<RstWarning>:\n    content: content\n    cols: 1\n    padding: 20\n    size_hint_y: None\n    height: self.minimum_height\n    canvas:\n        Color:\n            rgba: 1, 0, 0, .5\n        Rectangle:\n            pos: self.x + 10, self.y + 10\n            size: self.width - 20, self.height - 20\n    GridLayout:\n        cols: 1\n        id: content\n        size_hint_y: None\n        height: self.minimum_height\n\n<RstNote>:\n    content: content\n    cols: 1\n    padding: 20\n    size_hint_y: None\n    height: self.minimum_height\n    canvas:\n        Color:\n            rgba: 0, 1, 0, .5\n        Rectangle:\n            pos: self.x + 10, self.y + 10\n            size: self.width - 20, self.height - 20\n    GridLayout:\n        cols: 1\n        id: content\n        size_hint_y: None\n        height: self.minimum_height\n\n<RstImage>:\n    size_hint: None, None\n    size: self.texture_size[0], self.texture_size[1] + dp(10)\n\n<RstAsyncImage>:\n    size_hint: None, None\n    size: self.texture_size[0], self.texture_size[1] + dp(10)\n\n<RstDefinitionList>:\n    cols: 1\n    size_hint_y: None\n    height: self.minimum_height\n    font_size: sp(self.document.base_font_size / 2.0)\n\n<RstDefinition>:\n    cols: 2\n    size_hint_y: None\n    height: self.minimum_height\n    font_size: sp(self.document.base_font_size / 2.0)\n\n<RstFieldList>:\n    cols: 2\n    size_hint_y: None\n    height: self.minimum_height\n\n<RstFieldName>:\n    markup: True\n    valign: 'top'\n    size_hint: 0.2, 1\n    color: (0, 0, 0, 1)\n    bold: True\n    text_size: self.width-10, self.height - 10\n    valign: 'top'\n    font_size: sp(self.document.base_font_size / 2.0)\n\n<RstFieldBody>:\n    cols: 1\n    size_hint_y: None\n    height: self.minimum_height\n\n<RstTable>:\n    size_hint_y: None\n    height: self.minimum_height\n\n<RstEntry>:\n    cols: 1\n    size_hint_y: None\n    height: self.minimum_height\n\n    canvas:\n        Color:\n            rgb: .2, .2, .2\n        Line:\n            points: [\\\n            self.x,\\\n            self.y,\\\n            self.right,\\\n            self.y,\\\n            self.right,\\\n            self.top,\\\n            self.x,\\\n            self.top,\\\n            self.x,\\\n            self.y]\n\n<RstTransition>:\n    size_hint_y: None\n    height: 20\n    canvas:\n        Color:\n            rgb: .2, .2, .2\n        Line:\n            points: [self.x, self.center_y, self.right, self.center_y]\n\n<RstListBullet>:\n    markup: True\n    valign: 'top'\n    size_hint_x: None\n    width: self.texture_size[0] + dp(10)\n    text_size: None, self.height - dp(10)\n    font_size: sp(self.document.base_font_size / 2.0)\n\n<RstEmptySpace>:\n    size_hint: 0.01, 0.01\n\n<RstDefinitionSpace>:\n    size_hint: None, 0.1\n    width: 50\n    font_size: sp(self.document.base_font_size / 2.0)\n\n<RstVideoPlayer>:\n    options: {'allow_stretch': True}\n    canvas.before:\n        Color:\n            rgba: (1, 1, 1, 1)\n        BorderImage:\n            source: 'atlas://data/images/defaulttheme/player-background'\n            pos: self.x - 25, self.y - 25\n            size: self.width + 50, self.height + 50\n            border: (25, 25, 25, 25)\n''')\n\n\nclass RstVideoPlayer(VideoPlayer):\n    pass\n\n\nclass RstDocument(ScrollView):\n    '''Base widget used to store an Rst document. See module documentation for\n    more information.\n    '''\n    source = StringProperty(None)\n    '''Filename of the RST document.\n\n    :attr:`source` is a :class:`~kivy.properties.StringProperty` and\n    defaults to None.\n    '''\n\n    source_encoding = StringProperty('utf-8')\n    '''Encoding to be used for the :attr:`source` file.\n\n    :attr:`source_encoding` is a :class:`~kivy.properties.StringProperty` and\n    defaults to `utf-8`.\n\n    .. Note::\n        It is your responsibility to ensure that the value provided is a\n        valid codec supported by python.\n    '''\n\n    source_error = OptionProperty('strict',\n                                  options=('strict', 'ignore', 'replace',\n                                           'xmlcharrefreplace',\n                                           'backslashreplac'))\n    '''Error handling to be used while encoding the :attr:`source` file.\n\n    :attr:`source_error` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to `strict`. Can be one of 'strict', 'ignore', 'replace',\n    'xmlcharrefreplace' or 'backslashreplac'.\n    '''\n\n    text = StringProperty(None)\n    '''RST markup text of the document.\n\n    :attr:`text` is a :class:`~kivy.properties.StringProperty` and defaults to\n    None.\n    '''\n\n    document_root = StringProperty(None)\n    '''Root path where :doc: will search for rst documents. If no path is\n    given, it will use the directory of the first loaded source file.\n\n    :attr:`document_root` is a :class:`~kivy.properties.StringProperty` and\n    defaults to None.\n    '''\n\n    base_font_size = NumericProperty(31)\n    '''Font size for the biggest title, 31 by default. All other font sizes are\n    derived from this.\n\n    .. versionadded:: 1.8.0\n    '''\n\n    show_errors = BooleanProperty(False)\n    '''Indicate whether RST parsers errors should be shown on the screen\n    or not.\n\n    :attr:`show_errors` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    def _get_bgc(self):\n        return get_color_from_hex(self.colors.background)\n\n    def _set_bgc(self, value):\n        self.colors.background = get_hex_from_color(value)[1:]\n\n    background_color = AliasProperty(_get_bgc, _set_bgc, bind=('colors',))\n    '''Specifies the background_color to be used for the RstDocument.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`background_color` is an :class:`~kivy.properties.AliasProperty`\n    for colors['background'].\n    '''\n\n    colors = DictProperty({\n        'background': 'e5e6e9ff',\n        'link': 'ce5c00ff',\n        'paragraph': '202020ff',\n        'title': '204a87ff',\n        'bullet': '000000ff'})\n    '''Dictionary of all the colors used in the RST rendering.\n\n    .. warning::\n\n        This dictionary is needs special handling. You also need to call\n        :meth:`RstDocument.render` if you change them after loading.\n\n    :attr:`colors` is a :class:`~kivy.properties.DictProperty`.\n    '''\n\n    title = StringProperty('')\n    '''Title of the current document.\n\n    :attr:`title` is a :class:`~kivy.properties.StringProperty` and defaults to\n    ''. It is read-only.\n    '''\n\n    toctrees = DictProperty({})\n    '''Toctree of all loaded or preloaded documents. This dictionary is filled\n    when a rst document is explicitly loaded or where :meth:`preload` has been\n    called.\n\n    If the document has no filename, e.g. when the document is loaded from a\n    text file, the key will be ''.\n\n    :attr:`toctrees` is a :class:`~kivy.properties.DictProperty` and defaults\n    to {}.\n    '''\n\n    underline_color = StringProperty('204a9699')\n    '''underline color of the titles, expressed in html color notation\n\n    :attr:`underline_color` is a\n    :class:`~kivy.properties.StringProperty` and defaults to '204a9699'.\n\n    .. versionadded: 1.9.0\n    '''\n\n    # internals.\n    content = ObjectProperty(None)\n    scatter = ObjectProperty(None)\n    anchors_widgets = ListProperty([])\n    refs_assoc = DictProperty({})\n\n    def __init__(self, **kwargs):\n        self._trigger_load = Clock.create_trigger(self._load_from_text, -1)\n        self._parser = rst.Parser()\n        self._settings = frontend.OptionParser(\n            components=(rst.Parser, )).get_default_values()\n        super(RstDocument, self).__init__(**kwargs)\n\n    def on_source(self, instance, value):\n        if not value:\n            return\n        if self.document_root is None:\n            # set the documentation root to the directory name of the\n            # first tile\n            self.document_root = abspath(dirname(value))\n        self._load_from_source()\n\n    def on_text(self, instance, value):\n        self._trigger_load()\n\n    def render(self):\n        '''Force document rendering.\n        '''\n        self._load_from_text()\n\n    def resolve_path(self, filename):\n        '''Get the path for this filename. If the filename doesn't exist,\n        it returns the document_root + filename.\n        '''\n        if exists(filename):\n            return filename\n        return join(self.document_root, filename)\n\n    def preload(self, filename, encoding='utf-8', errors='strict'):\n        '''Preload a rst file to get its toctree and its title.\n\n        The result will be stored in :attr:`toctrees` with the ``filename`` as\n        key.\n        '''\n\n        with open(filename, 'rb') as fd:\n            text = fd.read().decode(encoding, errors)\n        # parse the source\n        document = utils.new_document('Document', self._settings)\n        self._parser.parse(text, document)\n        # fill the current document node\n        visitor = _ToctreeVisitor(document)\n        document.walkabout(visitor)\n        self.toctrees[filename] = visitor.toctree\n        return text\n\n    def _load_from_source(self):\n        filename = self.resolve_path(self.source)\n        self.text = self.preload(filename,\n                                 self.source_encoding,\n                                 self.source_error)\n\n    def _load_from_text(self, *largs):\n        try:\n            # clear the current widgets\n            self.content.clear_widgets()\n            self.anchors_widgets = []\n            self.refs_assoc = {}\n\n            # parse the source\n            document = utils.new_document('Document', self._settings)\n            text = self.text\n            if PY2 and type(text) is str:\n                text = text.decode('utf-8')\n            self._parser.parse(text, document)\n\n            # fill the current document node\n            visitor = _Visitor(self, document)\n            document.walkabout(visitor)\n\n            self.title = visitor.title or 'No title'\n        except:\n            Logger.exception('Rst: error while loading text')\n\n    def on_ref_press(self, node, ref):\n        self.goto(ref)\n\n    def goto(self, ref, *largs):\n        '''Scroll to the reference. If it's not found, nothing will be done.\n\n        For this text::\n\n            .. _myref:\n\n            This is something I always wanted.\n\n        You can do::\n\n            from kivy.clock import Clock\n            from functools import partial\n\n            doc = RstDocument(...)\n            Clock.schedule_once(partial(doc.goto, 'myref'), 0.1)\n\n        .. note::\n\n            It is preferable to delay the call of the goto if you just loaded\n            the document because the layout might not be finished or the\n            size of the RstDocument has not yet been determined. In\n            either case, the calculation of the scrolling would be\n            wrong.\n\n            You can, however, do a direct call if the document is already\n            loaded.\n\n        .. versionadded:: 1.3.0\n        '''\n        # check if it's a file ?\n        if ref.endswith('.rst'):\n            # whether it's a valid or invalid file, let source deal with it\n            self.source = ref\n            return\n\n        # get the association\n        ref = self.refs_assoc.get(ref, ref)\n\n        # search into all the nodes containing anchors\n        ax = ay = None\n        for node in self.anchors_widgets:\n            if ref in node.anchors:\n                ax, ay = node.anchors[ref]\n                break\n\n        # not found, stop here\n        if ax is None:\n            return\n\n        # found, calculate the real coordinate\n\n        # get the anchor coordinate inside widget space\n        ax += node.x\n        ay = node.top - ay\n        #ay += node.y\n\n        # what's the current coordinate for us?\n        sx, sy = self.scatter.x, self.scatter.top\n        #ax, ay = self.scatter.to_parent(ax, ay)\n\n        ay -= self.height\n\n        dx, dy = self.convert_distance_to_scroll(0, ay)\n        dy = max(0, min(1, dy))\n        Animation(scroll_y=dy, d=.25, t='in_out_expo').start(self)\n\n    def add_anchors(self, node):\n        self.anchors_widgets.append(node)\n\n\nclass RstTitle(Label):\n\n    section = NumericProperty(0)\n\n    document = ObjectProperty(None)\n\n\nclass RstParagraph(Label):\n\n    mx = NumericProperty(10)\n\n    my = NumericProperty(10)\n\n    document = ObjectProperty(None)\n\n\nclass RstTerm(AnchorLayout):\n\n    text = StringProperty('')\n\n    document = ObjectProperty(None)\n\n\nclass RstBlockQuote(GridLayout):\n    content = ObjectProperty(None)\n\n\nclass RstLiteralBlock(GridLayout):\n    content = ObjectProperty(None)\n\n\nclass RstList(GridLayout):\n    pass\n\n\nclass RstListItem(GridLayout):\n    content = ObjectProperty(None)\n\n\nclass RstListBullet(Label):\n\n    document = ObjectProperty(None)\n\n\nclass RstSystemMessage(GridLayout):\n    pass\n\n\nclass RstWarning(GridLayout):\n    content = ObjectProperty(None)\n\n\nclass RstNote(GridLayout):\n    content = ObjectProperty(None)\n\n\nclass RstImage(Image):\n    pass\n\n\nclass RstAsyncImage(AsyncImage):\n    pass\n\n\nclass RstDefinitionList(GridLayout):\n\n    document = ObjectProperty(None)\n\n\nclass RstDefinition(GridLayout):\n\n    document = ObjectProperty(None)\n\n\nclass RstFieldList(GridLayout):\n    pass\n\n\nclass RstFieldName(Label):\n\n    document = ObjectProperty(None)\n\n\nclass RstFieldBody(GridLayout):\n    pass\n\n\nclass RstGridLayout(GridLayout):\n    pass\n\n\nclass RstTable(GridLayout):\n    pass\n\n\nclass RstEntry(GridLayout):\n    pass\n\n\nclass RstTransition(Widget):\n    pass\n\n\nclass RstEmptySpace(Widget):\n    pass\n\n\nclass RstDefinitionSpace(Widget):\n\n    document = ObjectProperty(None)\n\n\nclass _ToctreeVisitor(nodes.NodeVisitor):\n\n    def __init__(self, *largs):\n        self.toctree = self.current = []\n        self.queue = []\n        self.text = ''\n        nodes.NodeVisitor.__init__(self, *largs)\n\n    def push(self, tree):\n        self.queue.append(tree)\n        self.current = tree\n\n    def pop(self):\n        self.current = self.queue.pop()\n\n    def dispatch_visit(self, node):\n        cls = node.__class__\n        if cls is nodes.section:\n            section = {\n                'ids': node['ids'],\n                'names': node['names'],\n                'title': '',\n                'children': []}\n            if isinstance(self.current, dict):\n                self.current['children'].append(section)\n            else:\n                self.current.append(section)\n            self.push(section)\n        elif cls is nodes.title:\n            self.text = ''\n        elif cls is nodes.Text:\n            self.text += node\n\n    def dispatch_departure(self, node):\n        cls = node.__class__\n        if cls is nodes.section:\n            self.pop()\n        elif cls is nodes.title:\n            self.current['title'] = self.text\n\n\nclass _Visitor(nodes.NodeVisitor):\n\n    def __init__(self, root, *largs):\n        self.root = root\n        self.title = None\n        self.current_list = []\n        self.current = None\n        self.idx_list = None\n        self.text = ''\n        self.text_have_anchor = False\n        self.section = 0\n        self.do_strip_text = False\n        nodes.NodeVisitor.__init__(self, *largs)\n\n    def push(self, widget):\n        self.current_list.append(self.current)\n        self.current = widget\n\n    def pop(self):\n        self.current = self.current_list.pop()\n\n    def dispatch_visit(self, node):\n        cls = node.__class__\n        if cls is nodes.document:\n            self.push(self.root.content)\n\n        elif cls is nodes.section:\n            self.section += 1\n\n        elif cls is nodes.title:\n            label = RstTitle(section=self.section, document=self.root)\n            self.current.add_widget(label)\n            self.push(label)\n            #assert(self.text == '')\n\n        elif cls is nodes.Text:\n            if self.do_strip_text:\n                node = node.replace('\\n', ' ')\n                node = node.replace('  ', ' ')\n                node = node.replace('\\t', ' ')\n                node = node.replace('  ', ' ')\n                if node.startswith(' '):\n                    node = ' ' + node.lstrip(' ')\n                if node.endswith(' '):\n                    node = node.rstrip(' ') + ' '\n                if self.text.endswith(' ') and node.startswith(' '):\n                    node = node[1:]\n            self.text += node\n\n        elif cls is nodes.paragraph:\n            self.do_strip_text = True\n            label = RstParagraph(document=self.root)\n            if isinstance(self.current, RstEntry):\n                label.mx = 10\n            self.current.add_widget(label)\n            self.push(label)\n\n        elif cls is nodes.literal_block:\n            box = RstLiteralBlock()\n            self.current.add_widget(box)\n            self.push(box)\n\n        elif cls is nodes.emphasis:\n            self.text += '[i]'\n\n        elif cls is nodes.strong:\n            self.text += '[b]'\n\n        elif cls is nodes.literal:\n            self.text += '[font=fonts/DroidSansMono.ttf]'\n\n        elif cls is nodes.block_quote:\n            box = RstBlockQuote()\n            self.current.add_widget(box)\n            self.push(box.content)\n            assert(self.text == '')\n\n        elif cls is nodes.enumerated_list:\n            box = RstList()\n            self.current.add_widget(box)\n            self.push(box)\n            self.idx_list = 0\n\n        elif cls is nodes.bullet_list:\n            box = RstList()\n            self.current.add_widget(box)\n            self.push(box)\n            self.idx_list = None\n\n        elif cls is nodes.list_item:\n            bullet = '-'\n            if self.idx_list is not None:\n                self.idx_list += 1\n                bullet = '%d.' % self.idx_list\n            bullet = self.colorize(bullet, 'bullet')\n            item = RstListItem()\n            self.current.add_widget(RstListBullet(\n                text=bullet, document=self.root))\n            self.current.add_widget(item)\n            self.push(item)\n\n        elif cls is nodes.system_message:\n            label = RstSystemMessage()\n            if self.root.show_errors:\n                self.current.add_widget(label)\n            self.push(label)\n\n        elif cls is nodes.warning:\n            label = RstWarning()\n            self.current.add_widget(label)\n            self.push(label.content)\n            assert(self.text == '')\n\n        elif cls is nodes.note:\n            label = RstNote()\n            self.current.add_widget(label)\n            self.push(label.content)\n            assert(self.text == '')\n\n        elif cls is nodes.image:\n            uri = node['uri']\n            if uri.startswith('/') and self.root.document_root:\n                uri = join(self.root.document_root, uri[1:])\n            if uri.startswith('http://') or uri.startswith('https://'):\n                image = RstAsyncImage(source=uri)\n            else:\n                image = RstImage(source=uri)\n\n            align = node.get('align', 'center')\n            root = AnchorLayout(size_hint_y=None, anchor_x=align, height=1)\n            image.bind(height=root.setter('height'))\n            root.add_widget(image)\n            self.current.add_widget(root)\n\n        elif cls is nodes.definition_list:\n            lst = RstDefinitionList(document=self.root)\n            self.current.add_widget(lst)\n            self.push(lst)\n\n        elif cls is nodes.term:\n            assert(isinstance(self.current, RstDefinitionList))\n            term = RstTerm(document=self.root)\n            self.current.add_widget(term)\n            self.push(term)\n\n        elif cls is nodes.definition:\n            assert(isinstance(self.current, RstDefinitionList))\n            definition = RstDefinition(document=self.root)\n            definition.add_widget(RstDefinitionSpace(document=self.root))\n            self.current.add_widget(definition)\n            self.push(definition)\n\n        elif cls is nodes.field_list:\n            fieldlist = RstFieldList()\n            self.current.add_widget(fieldlist)\n            self.push(fieldlist)\n\n        elif cls is nodes.field_name:\n            name = RstFieldName(document=self.root)\n            self.current.add_widget(name)\n            self.push(name)\n\n        elif cls is nodes.field_body:\n            body = RstFieldBody()\n            self.current.add_widget(body)\n            self.push(body)\n\n        elif cls is nodes.table:\n            table = RstTable(cols=0)\n            self.current.add_widget(table)\n            self.push(table)\n\n        elif cls is nodes.colspec:\n            self.current.cols += 1\n\n        elif cls is nodes.entry:\n            entry = RstEntry()\n            self.current.add_widget(entry)\n            self.push(entry)\n\n        elif cls is nodes.transition:\n            self.current.add_widget(RstTransition())\n\n        elif cls is nodes.reference:\n            name = node.get('name', node.get('refuri'))\n            self.text += '[ref=%s][color=%s]' % (\n                name, self.root.colors.get(\n                    'link', self.root.colors.get('paragraph')))\n            if 'refname' in node and 'name' in node:\n                self.root.refs_assoc[node['name']] = node['refname']\n\n        elif cls is nodes.target:\n            name = None\n            if 'ids' in node:\n                name = node['ids'][0]\n            elif 'names' in node:\n                name = node['names'][0]\n            self.text += '[anchor=%s]' % name\n            self.text_have_anchor = True\n\n        elif cls is role_doc:\n            self.doc_index = len(self.text)\n\n        elif cls is role_video:\n            pass\n\n    def dispatch_departure(self, node):\n        cls = node.__class__\n        if cls is nodes.document:\n            self.pop()\n\n        elif cls is nodes.section:\n            self.section -= 1\n\n        elif cls is nodes.title:\n            assert(isinstance(self.current, RstTitle))\n            if not self.title:\n                self.title = self.text\n            self.set_text(self.current, 'title')\n            self.pop()\n\n        elif cls is nodes.Text:\n            pass\n\n        elif cls is nodes.paragraph:\n            self.do_strip_text = False\n            assert(isinstance(self.current, RstParagraph))\n            self.set_text(self.current, 'paragraph')\n            self.pop()\n\n        elif cls is nodes.literal_block:\n            assert(isinstance(self.current, RstLiteralBlock))\n            self.set_text(self.current.content, 'literal_block')\n            self.pop()\n\n        elif cls is nodes.emphasis:\n            self.text += '[/i]'\n\n        elif cls is nodes.strong:\n            self.text += '[/b]'\n\n        elif cls is nodes.literal:\n            self.text += '[/font]'\n\n        elif cls is nodes.block_quote:\n            self.pop()\n\n        elif cls is nodes.enumerated_list:\n            self.idx_list = None\n            self.pop()\n\n        elif cls is nodes.bullet_list:\n            self.pop()\n\n        elif cls is nodes.list_item:\n            self.pop()\n\n        elif cls is nodes.system_message:\n            self.pop()\n\n        elif cls is nodes.warning:\n            self.pop()\n\n        elif cls is nodes.note:\n            self.pop()\n\n        elif cls is nodes.definition_list:\n            self.pop()\n\n        elif cls is nodes.term:\n            assert(isinstance(self.current, RstTerm))\n            self.set_text(self.current, 'term')\n            self.pop()\n\n        elif cls is nodes.definition:\n            self.pop()\n\n        elif cls is nodes.field_list:\n            self.pop()\n\n        elif cls is nodes.field_name:\n            assert(isinstance(self.current, RstFieldName))\n            self.set_text(self.current, 'field_name')\n            self.pop()\n\n        elif cls is nodes.field_body:\n            self.pop()\n\n        elif cls is nodes.table:\n            self.pop()\n\n        elif cls is nodes.colspec:\n            pass\n\n        elif cls is nodes.entry:\n            self.pop()\n\n        elif cls is nodes.reference:\n            self.text += '[/color][/ref]'\n\n        elif cls is role_doc:\n            docname = self.text[self.doc_index:]\n            rst_docname = docname\n            if rst_docname.endswith('.rst'):\n                docname = docname[:-4]\n            else:\n                rst_docname += '.rst'\n\n            # try to preload it\n            filename = self.root.resolve_path(rst_docname)\n            self.root.preload(filename)\n\n            # if exist, use the title of the first section found in the\n            # document\n            title = docname\n            if filename in self.root.toctrees:\n                toctree = self.root.toctrees[filename]\n                if len(toctree):\n                    title = toctree[0]['title']\n\n            # replace the text with a good reference\n            text = '[ref=%s]%s[/ref]' % (\n                rst_docname,\n                self.colorize(title, 'link'))\n            self.text = self.text[:self.doc_index] + text\n\n        elif cls is role_video:\n            width = node['width'] if 'width' in node.attlist() else 400\n            height = node['height'] if 'height' in node.attlist() else 300\n            uri = node['source']\n            if uri.startswith('/') and self.root.document_root:\n                uri = join(self.root.document_root, uri[1:])\n            video = RstVideoPlayer(\n                source=uri,\n                size_hint=(None, None),\n                size=(width, height))\n            anchor = AnchorLayout(size_hint_y=None, height=height + 20)\n            anchor.add_widget(video)\n            self.current.add_widget(anchor)\n\n    def set_text(self, node, parent):\n        text = self.text\n        if parent == 'term' or parent == 'field_name':\n            text = '[b]%s[/b]' % text\n        # search anchors\n        node.text = self.colorize(text, parent)\n        node.bind(on_ref_press=self.root.on_ref_press)\n        if self.text_have_anchor:\n            self.root.add_anchors(node)\n        self.text = ''\n        self.text_have_anchor = False\n\n    def colorize(self, text, name):\n        return '[color=%s]%s[/color]' % (\n            self.root.colors.get(name, self.root.colors['paragraph']),\n            text)\n\nif __name__ == '__main__':\n    from kivy.base import runTouchApp\n    import sys\n    runTouchApp(RstDocument(source=sys.argv[1]))\n"
  },
  {
    "path": "tickeys/kivy/uix/sandbox.py",
    "content": "'''\nSandbox\n=======\n\n.. versionadded:: 1.8.0\n\n.. warning::\n\n    This is experimental and subject to change as long as this warning notice\n    is present.\n\nThis is a widget that runs itself and all of its children in a Sandbox. That\nmeans if a child raises an Exception, it will be caught. The Sandbox\nitself runs its own Clock, Cache, etc.\n\nThe SandBox widget is still experimental and required for the Kivy designer.\nWhen the user designs their own widget, if they do something wrong (wrong size\nvalue, invalid python code), it will be caught correctly without breaking\nthe whole application. Because it has been designed that way, we are still\nenhancing this widget and the :mod:`kivy.context` module.\nDon't use it unless you know what you are doing.\n\n'''\n\n__all__ = ('Sandbox', )\n\nfrom kivy.context import Context\nfrom kivy.base import ExceptionManagerBase\nfrom kivy.clock import Clock\nfrom kivy.uix.widget import Widget\nfrom kivy.uix.floatlayout import FloatLayout\nfrom kivy.uix.relativelayout import RelativeLayout\nfrom kivy.lang import Builder\n\n\ndef sandbox(f):\n    def _f2(self, *args, **kwargs):\n        ret = None\n        with self:\n            ret = f(self, *args, **kwargs)\n        return ret\n    return _f2\n\n\nclass SandboxExceptionManager(ExceptionManagerBase):\n\n    def __init__(self, sandbox):\n        ExceptionManagerBase.__init__(self)\n        self.sandbox = sandbox\n\n    def handle_exception(self, e):\n        if not self.sandbox.on_exception(e):\n            return ExceptionManagerBase.RAISE\n        return ExceptionManagerBase.PASS\n\n\nclass SandboxContent(RelativeLayout):\n    pass\n\n\nclass Sandbox(FloatLayout):\n    '''Sandbox widget, used to trap all the exceptions raised by child\n    widgets.\n    '''\n\n    def __init__(self, **kwargs):\n        self._context = Context(init=True)\n        self._context['ExceptionManager'] = SandboxExceptionManager(self)\n        self._context.sandbox = self\n        self._context.push()\n        self.on_context_created()\n        self._container = None\n        super(Sandbox, self).__init__(**kwargs)\n        self._container = SandboxContent(size=self.size, pos=self.pos)\n        super(Sandbox, self).add_widget(self._container)\n        self._context.pop()\n\n        # force SandboxClock's scheduling\n        Clock.schedule_interval(self._clock_sandbox, 0)\n        Clock.schedule_once(self._clock_sandbox_draw, -1)\n        self.main_clock = object.__getattribute__(Clock, '_obj')\n\n    def __enter__(self):\n        self._context.push()\n\n    def __exit__(self, _type, value, traceback):\n        self._context.pop()\n        if _type is not None:\n            return self.on_exception(value, _traceback=traceback)\n\n    def on_context_created(self):\n        '''Override this method in order to load your kv file or do anything\n        else with the newly created context.\n        '''\n        pass\n\n    def on_exception(self, exception, _traceback=None):\n        '''Override this method in order to catch all the exceptions from\n        children.\n\n        If you return True, it will not reraise the exception.\n        If you return False, the exception will be raised to the parent.\n        '''\n        import traceback\n        traceback.print_tb(_traceback)\n        return True\n\n    on_touch_down = sandbox(Widget.on_touch_down)\n    on_touch_move = sandbox(Widget.on_touch_move)\n    on_touch_up = sandbox(Widget.on_touch_up)\n\n    @sandbox\n    def add_widget(self, *args, **kwargs):\n        self._container.add_widget(*args, **kwargs)\n\n    @sandbox\n    def remove_widget(self, *args, **kwargs):\n        self._container.remove_widget(*args, **kwargs)\n\n    @sandbox\n    def clear_widgets(self, *args, **kwargs):\n        self._container.clear_widgets()\n\n    @sandbox\n    def on_size(self, *args):\n        if self._container:\n            self._container.size = self.size\n\n    @sandbox\n    def on_pos(self, *args):\n        if self._container:\n            self._container.pos = self.pos\n\n    @sandbox\n    def _clock_sandbox(self, dt):\n        #import pdb; pdb.set_trace()\n        Clock.tick()\n        Builder.sync()\n\n    @sandbox\n    def _clock_sandbox_draw(self, dt):\n        Clock.tick_draw()\n        Builder.sync()\n        self.main_clock.schedule_once(self._call_draw, 0)\n\n    def _call_draw(self, dt):\n        self.main_clock.schedule_once(self._clock_sandbox_draw, -1)\n\nif __name__ == '__main__':\n    from kivy.base import runTouchApp\n    from kivy.uix.button import Button\n\n    class TestButton(Button):\n\n        def on_touch_up(self, touch):\n            #raise Exception('fdfdfdfdfdfdfd')\n            return super(TestButton, self).on_touch_up(touch)\n\n        def on_touch_down(self, touch):\n            #raise Exception('')\n            return super(TestButton, self).on_touch_down(touch)\n\n    s = Sandbox()\n    with s:\n        Builder.load_string('''\n<TestButton>:\n    canvas:\n        Color:\n            rgb: (.3, .2, 0) if self.state == 'normal' else (.7, .7, 0)\n        Rectangle:\n            pos: self.pos\n            size: self.size\n        Color:\n            rgb: 1, 1, 1\n        Rectangle:\n            size: self.texture_size\n            pos: self.center_x - self.texture_size[0] / 2.,\\\n                 self.center_y - self.texture_size[1] / 2.\n            texture: self.texture\n\n    # invalid... for testing.\n    #on_touch_up: root.d()\n    #on_touch_down: root.f()\n    on_release: root.args()\n    #on_press: root.args()\n''')\n        b = TestButton(text='Hello World')\n        s.add_widget(b)\n\n        # this exception is within the \"with\" block, but will be ignored by\n        # default because the sandbox on_exception will return True\n        raise Exception('hello')\n\n    runTouchApp(s)\n"
  },
  {
    "path": "tickeys/kivy/uix/scatter.py",
    "content": "'''\nScatter\n=======\n\n:class:`Scatter` is used to build interactive widgets that can be translated,\nrotated and scaled with two or more fingers on a multitouch system.\n\nScatter has its own matrix transformation: the modelview matrix is changed\nbefore the children are drawn and the previous matrix is restored when the\ndrawing is finished. That makes it possible to perform rotation, scaling and\ntranslation over the entire children tree without changing any widget\nproperties. That specific behavior makes the scatter unique, but there are some\nadvantages / constraints that you should consider:\n\n#. The children are positioned relative to the scatter similar to a\n   RelativeLayout (see :mod:`~kivy.uix.relativelayout`). So when dragging the\n   scatter, the position of the children don't change, only the position of\n   the scatter does.\n#. The scatter size has no impact on the size of it's children.\n#. If you want to resize the scatter, use scale, not size (read #2). Scale\n   transforms both the scatter and its children, but does not change size.\n#. The scatter is not a layout. You must manage the size of the children\n   yourself.\n\nFor touch events, the scatter converts from the parent matrix to the scatter\nmatrix automatically in on_touch_down/move/up events. If you are doing things\nmanually, you will need to use :meth:`~kivy.uix.widget.Widget.to_parent` and\n:meth:`~kivy.uix.widget.Widget.to_local`.\n\nUsage\n-----\n\nBy default, the Scatter does not have a graphical representation: it is a\ncontainer only. The idea is to combine the Scatter with another widget, for\nexample an :class:`~kivy.uix.image.Image`::\n\n    scatter = Scatter()\n    image = Image(source='sun.jpg')\n    scatter.add_widget(image)\n\nControl Interactions\n--------------------\n\nBy default, all interactions are enabled. You can selectively disable\nthem using the do_rotation, do_translation and do_scale properties.\n\nDisable rotation::\n\n    scatter = Scatter(do_rotation=False)\n\nAllow only translation::\n\n    scatter = Scatter(do_rotation=False, do_scale=False)\n\nAllow only translation on x axis::\n\n    scatter = Scatter(do_rotation=False, do_scale=False,\n                      do_translation_y=False)\n\n\nAutomatic Bring to Front\n------------------------\n\nIf the :attr:`Scatter.auto_bring_to_front` property is True, the scatter\nwidget will be removed and re-added to the parent when it is touched\n(brought to front, above all other widgets in the parent). This is useful\nwhen you are manipulating several scatter widgets and don't want the active\none to be partially hidden.\n\nScale Limitation\n----------------\n\nWe are using a 32-bit matrix in double representation. That means we have\na limit for scaling. You cannot do infinite scaling down/up with our\nimplementation. Generally, you don't hit the minimum scale (because you don't\nsee it on the screen), but the maximum scale is 9.99506983235e+19 (2^66).\n\nYou can also limit the minimum and maximum scale allowed::\n\n    scatter = Scatter(scale_min=.5, scale_max=3.)\n\nBehavior\n--------\n\n.. versionchanged:: 1.1.0\n    If no control interactions are enabled, then the touch handler will never\n    return True.\n\n'''\n\n__all__ = ('Scatter', 'ScatterPlane')\n\nfrom math import radians\nfrom kivy.properties import BooleanProperty, AliasProperty, \\\n    NumericProperty, ObjectProperty, BoundedNumericProperty\nfrom kivy.vector import Vector\nfrom kivy.uix.widget import Widget\nfrom kivy.graphics.transformation import Matrix\n\n\nclass Scatter(Widget):\n    '''Scatter class. See module documentation for more information.\n\n    :Events:\n        `on_transform_with_touch`:\n            Fired when the scatter has been transformed by user touch\n            or multitouch, such as panning or zooming.\n        `on_bring_to_front`:\n            Fired when the scatter is brought to the front.\n\n    .. versionchanged:: 1.9.0\n        Event `on_bring_to_front` added.\n\n    .. versionchanged:: 1.8.0\n        Event `on_transform_with_touch` added.\n    '''\n\n    __events__ = ('on_transform_with_touch', 'on_bring_to_front')\n\n    auto_bring_to_front = BooleanProperty(True)\n    '''If True, the widget will be automatically pushed on the top of parent\n    widget list for drawing.\n\n    :attr:`auto_bring_to_front` is a :class:`~kivy.properties.BooleanProperty`\n    and defaults to True.\n    '''\n\n    do_translation_x = BooleanProperty(True)\n    '''Allow translation on the X axis.\n\n    :attr:`do_translation_x` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n\n    do_translation_y = BooleanProperty(True)\n    '''Allow translation on Y axis.\n\n    :attr:`do_translation_y` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n\n    def _get_do_translation(self):\n        return (self.do_translation_x, self.do_translation_y)\n\n    def _set_do_translation(self, value):\n        if type(value) in (list, tuple):\n            self.do_translation_x, self.do_translation_y = value\n        else:\n            self.do_translation_x = self.do_translation_y = bool(value)\n    do_translation = AliasProperty(\n        _get_do_translation, _set_do_translation,\n        bind=('do_translation_x', 'do_translation_y'))\n    '''Allow translation on the X or Y axis.\n\n    :attr:`do_translation` is an :class:`~kivy.properties.AliasProperty` of\n    (:attr:`do_translation_x` + :attr:`do_translation_y`)\n    '''\n\n    translation_touches = BoundedNumericProperty(1, min=1)\n    '''Determine whether translation was triggered by a single or multiple\n    touches. This only has effect when :attr:`do_translation` = True.\n\n    :attr:`translation_touches` is a :class:`~kivy.properties.NumericProperty`\n    and defaults to 1.\n\n    .. versionadded:: 1.7.0\n    '''\n\n    do_rotation = BooleanProperty(True)\n    '''Allow rotation.\n\n    :attr:`do_rotation` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n\n    do_scale = BooleanProperty(True)\n    '''Allow scaling.\n\n    :attr:`do_scale` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n\n    do_collide_after_children = BooleanProperty(False)\n    '''If True, the collision detection for limiting the touch inside the\n    scatter will be done after dispaching the touch to the children.\n    You can put children outside the bounding box of the scatter and still be\n    able to touch them.\n\n    .. versionadded:: 1.3.0\n    '''\n\n    scale_min = NumericProperty(0.01)\n    '''Minimum scaling factor allowed.\n\n    :attr:`scale_min` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.01.\n    '''\n\n    scale_max = NumericProperty(1e20)\n    '''Maximum scaling factor allowed.\n\n    :attr:`scale_max` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 1e20.\n    '''\n\n    transform = ObjectProperty(Matrix())\n    '''Transformation matrix.\n\n    :attr:`transform` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to the identity matrix.\n\n    .. note::\n\n        This matrix reflects the current state of the transformation matrix\n        but setting it directly will erase previously applied\n        transformations. To apply a transformation considering context,\n        please use the :attr:`~Scatter.apply_transform` method.\n\n    '''\n\n    transform_inv = ObjectProperty(Matrix())\n    '''Inverse of the transformation matrix.\n\n    :attr:`transform_inv` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to the identity matrix.\n    '''\n\n    def _get_bbox(self):\n        xmin, ymin = xmax, ymax = self.to_parent(0, 0)\n        for point in [(self.width, 0), (0, self.height), self.size]:\n            x, y = self.to_parent(*point)\n            if x < xmin:\n                xmin = x\n            if y < ymin:\n                ymin = y\n            if x > xmax:\n                xmax = x\n            if y > ymax:\n                ymax = y\n        return (xmin, ymin), (xmax - xmin, ymax - ymin)\n    bbox = AliasProperty(_get_bbox, None, bind=(\n        'transform', 'width', 'height'))\n    '''Bounding box of the widget in parent space::\n\n        ((x, y), (w, h))\n        # x, y = lower left corner\n\n    :attr:`bbox` is an :class:`~kivy.properties.AliasProperty`.\n    '''\n\n    def _get_rotation(self):\n        v1 = Vector(0, 10)\n        tp = self.to_parent\n        v2 = Vector(*tp(*self.pos)) - tp(self.x, self.y + 10)\n        return -1.0 * (v1.angle(v2) + 180) % 360\n\n    def _set_rotation(self, rotation):\n        angle_change = self.rotation - rotation\n        r = Matrix().rotate(-radians(angle_change), 0, 0, 1)\n        self.apply_transform(r, post_multiply=True,\n                             anchor=self.to_local(*self.center))\n    rotation = AliasProperty(_get_rotation, _set_rotation, bind=(\n        'x', 'y', 'transform'))\n    '''Rotation value of the scatter.\n\n    :attr:`rotation` is an :class:`~kivy.properties.AliasProperty` and defaults\n    to 0.0.\n    '''\n\n    def _get_scale(self):\n        p1 = Vector(*self.to_parent(0, 0))\n        p2 = Vector(*self.to_parent(1, 0))\n        scale = p1.distance(p2)\n\n        # XXX float calculation are not accurate, and then, scale can be\n        # throwed again even with only the position change. So to\n        # prevent anything wrong with scale, just avoid to dispatch it\n        # if the scale \"visually\" didn't change. #947\n        # Remove this ugly hack when we'll be Python 3 only.\n        if hasattr(self, '_scale_p'):\n            if str(scale) == str(self._scale_p):\n                return self._scale_p\n\n        self._scale_p = scale\n        return scale\n\n    def _set_scale(self, scale):\n        rescale = scale * 1.0 / self.scale\n        self.apply_transform(Matrix().scale(rescale, rescale, rescale),\n                             post_multiply=True,\n                             anchor=self.to_local(*self.center))\n    scale = AliasProperty(_get_scale, _set_scale, bind=('x', 'y', 'transform'))\n    '''Scale value of the scatter.\n\n    :attr:`scale` is an :class:`~kivy.properties.AliasProperty` and defaults to\n    1.0.\n    '''\n\n    def _get_center(self):\n        return (self.bbox[0][0] + self.bbox[1][0] / 2.0,\n                self.bbox[0][1] + self.bbox[1][1] / 2.0)\n\n    def _set_center(self, center):\n        if center == self.center:\n            return False\n        t = Vector(*center) - self.center\n        trans = Matrix().translate(t.x, t.y, 0)\n        self.apply_transform(trans)\n    center = AliasProperty(_get_center, _set_center, bind=('bbox', ))\n\n    def _get_pos(self):\n        return self.bbox[0]\n\n    def _set_pos(self, pos):\n        _pos = self.bbox[0]\n        if pos == _pos:\n            return\n        t = Vector(*pos) - _pos\n        trans = Matrix().translate(t.x, t.y, 0)\n        self.apply_transform(trans)\n    pos = AliasProperty(_get_pos, _set_pos, bind=('bbox', ))\n\n    def _get_x(self):\n        return self.bbox[0][0]\n\n    def _set_x(self, x):\n        if x == self.bbox[0][0]:\n            return False\n        self.pos = (x, self.y)\n        return True\n    x = AliasProperty(_get_x, _set_x, bind=('bbox', ))\n\n    def _get_y(self):\n        return self.bbox[0][1]\n\n    def _set_y(self, y):\n        if y == self.bbox[0][1]:\n            return False\n        self.pos = (self.x, y)\n        return True\n    y = AliasProperty(_get_y, _set_y, bind=('bbox', ))\n\n    def get_right(self):\n        return self.x + self.bbox[1][0]\n\n    def set_right(self, value):\n        self.x = value - self.bbox[1][0]\n\n    right = AliasProperty(get_right, set_right, bind=('x', 'width'))\n\n    def get_top(self):\n        return self.y + self.bbox[1][1]\n\n    def set_top(self, value):\n        self.y = value - self.bbox[1][1]\n\n    top = AliasProperty(get_top, set_top, bind=('y', 'height'))\n\n    def get_center_x(self):\n        return self.x + self.bbox[1][0] / 2.\n\n    def set_center_x(self, value):\n        self.x = value - self.bbox[1][0] / 2.\n    center_x = AliasProperty(get_center_x, set_center_x, bind=('x', 'width'))\n\n    def get_center_y(self):\n        return self.y + self.bbox[1][1] / 2.\n\n    def set_center_y(self, value):\n        self.y = value - self.bbox[1][1] / 2.\n    center_y = AliasProperty(get_center_y, set_center_y, bind=('y', 'height'))\n\n    def __init__(self, **kwargs):\n        self._touches = []\n        self._last_touch_pos = {}\n        super(Scatter, self).__init__(**kwargs)\n\n    def on_transform(self, instance, value):\n        self.transform_inv = value.inverse()\n\n    def collide_point(self, x, y):\n        x, y = self.to_local(x, y)\n        return 0 <= x <= self.width and 0 <= y <= self.height\n\n    def to_parent(self, x, y, **k):\n        p = self.transform.transform_point(x, y, 0)\n        return (p[0], p[1])\n\n    def to_local(self, x, y, **k):\n        p = self.transform_inv.transform_point(x, y, 0)\n        return (p[0], p[1])\n\n    def _apply_transform(self, m):\n        m = self.transform.multiply(m)\n        return super(Scatter, self)._apply_transform(m)\n\n    def apply_transform(self, trans, post_multiply=False, anchor=(0, 0)):\n        '''\n        Transforms the scatter by applying the \"trans\" transformation\n        matrix (on top of its current transformation state). The resultant\n        matrix can be found in the :attr:`~Scatter.transform` property.\n\n        :Parameters:\n            `trans`: :class:`~kivy.graphics.transformation.Matrix`.\n                Transformation matix to be applied to the scatter widget.\n            `anchor`: tuple, defaults to (0, 0).\n                The point to use as the origin of the transformation\n                (uses local widget space).\n            `post_multiply`: bool, defaults to False.\n                If True, the transform matrix is post multiplied\n                (as if applied before the current transform).\n\n        Usage example::\n\n            from kivy.graphics.transformation import Matrix\n            mat = Matrix().scale(3, 3, 3)\n            scatter_instance.apply_transform(mat)\n\n        '''\n        t = Matrix().translate(anchor[0], anchor[1], 0)\n        t = t.multiply(trans)\n        t = t.multiply(Matrix().translate(-anchor[0], -anchor[1], 0))\n\n        if post_multiply:\n            self.transform = self.transform.multiply(t)\n        else:\n            self.transform = t.multiply(self.transform)\n\n    def transform_with_touch(self, touch):\n        # just do a simple one finger drag\n        changed = False\n        if len(self._touches) == self.translation_touches:\n            # _last_touch_pos has last pos in correct parent space,\n            # just like incoming touch\n            dx = (touch.x - self._last_touch_pos[touch][0]) \\\n                * self.do_translation_x\n            dy = (touch.y - self._last_touch_pos[touch][1]) \\\n                * self.do_translation_y\n            dx = dx / self.translation_touches\n            dy = dy / self.translation_touches\n            self.apply_transform(Matrix().translate(dx, dy, 0))\n            changed = True\n\n        if len(self._touches) == 1:\n            return changed\n\n        # we have more than one touch... list of last known pos\n        points = [Vector(self._last_touch_pos[t]) for t in self._touches\n                  if t is not touch]\n        # add current touch last\n        points.append(Vector(touch.pos))\n\n        # we only want to transform if the touch is part of the two touches\n        # farthest apart! So first we find anchor, the point to transform\n        # around as another touch farthest away from current touch's pos\n        anchor = max(points[:-1], key=lambda p: p.distance(touch.pos))\n\n        # now we find the touch farthest away from anchor, if its not the\n        # same as touch. Touch is not one of the two touches used to transform\n        farthest = max(points, key=anchor.distance)\n        if farthest is not points[-1]:\n            return changed\n\n        # ok, so we have touch, and anchor, so we can actually compute the\n        # transformation\n        old_line = Vector(*touch.ppos) - anchor\n        new_line = Vector(*touch.pos) - anchor\n        if not old_line.length():   # div by zero\n            return changed\n\n        angle = radians(new_line.angle(old_line)) * self.do_rotation\n        self.apply_transform(Matrix().rotate(angle, 0, 0, 1), anchor=anchor)\n\n        if self.do_scale:\n            scale = new_line.length() / old_line.length()\n            new_scale = scale * self.scale\n            if new_scale < self.scale_min:\n                scale = self.scale_min / self.scale\n            elif new_scale > self.scale_max:\n                scale = self.scale_max / self.scale\n            self.apply_transform(Matrix().scale(scale, scale, scale),\n                                 anchor=anchor)\n            changed = True\n        return changed\n\n    def _bring_to_front(self, touch):\n        # auto bring to front\n        if self.auto_bring_to_front and self.parent:\n            parent = self.parent\n            if parent.children[0] is self:\n                return\n            parent.remove_widget(self)\n            parent.add_widget(self)\n            self.dispatch('on_bring_to_front', touch)\n\n    def on_touch_down(self, touch):\n        x, y = touch.x, touch.y\n\n        # if the touch isnt on the widget we do nothing\n        if not self.do_collide_after_children:\n            if not self.collide_point(x, y):\n                return False\n\n        # let the child widgets handle the event if they want\n        touch.push()\n        touch.apply_transform_2d(self.to_local)\n        if super(Scatter, self).on_touch_down(touch):\n            # ensure children don't have to do it themselves\n            if 'multitouch_sim' in touch.profile:\n                touch.multitouch_sim = True\n            touch.pop()\n            self._bring_to_front(touch)\n            return True\n        touch.pop()\n\n        # if our child didn't do anything, and if we don't have any active\n        # interaction control, then don't accept the touch.\n        if not self.do_translation_x and \\\n                not self.do_translation_y and \\\n                not self.do_rotation and \\\n                not self.do_scale:\n            return False\n\n        if self.do_collide_after_children:\n            if not self.collide_point(x, y):\n                return False\n\n        if 'multitouch_sim' in touch.profile:\n            touch.multitouch_sim = True\n        # grab the touch so we get all it later move events for sure\n        self._bring_to_front(touch)\n        touch.grab(self)\n        self._touches.append(touch)\n        self._last_touch_pos[touch] = touch.pos\n\n        return True\n\n    def on_touch_move(self, touch):\n        x, y = touch.x, touch.y\n        # let the child widgets handle the event if they want\n        if self.collide_point(x, y) and not touch.grab_current == self:\n            touch.push()\n            touch.apply_transform_2d(self.to_local)\n            if super(Scatter, self).on_touch_move(touch):\n                touch.pop()\n                return True\n            touch.pop()\n\n        # rotate/scale/translate\n        if touch in self._touches and touch.grab_current == self:\n            if self.transform_with_touch(touch):\n                self.dispatch('on_transform_with_touch', touch)\n            self._last_touch_pos[touch] = touch.pos\n\n        # stop propagating if its within our bounds\n        if self.collide_point(x, y):\n            return True\n\n    def on_transform_with_touch(self, touch):\n        '''\n        Called when a touch event has transformed the scatter widget.\n        By default this does nothing, but can be overriden by derived\n        classes that need to react to transformations caused by user\n        input.\n\n        :Parameters:\n            `touch`: the touch object which triggered the transformation.\n\n        .. versionadded:: 1.8.0\n        '''\n        pass\n\n    def on_bring_to_front(self, touch):\n        '''\n        Called when a touch event causes the scatter to be brought to the\n        front of the parent (only if :attr:`auto_bring_to_front` is True)\n\n        :Parameters:\n            `touch`: the touch object which brought the scatter to front.\n\n        .. versionadded:: 1.9.0\n        '''\n        pass\n\n    def on_touch_up(self, touch):\n        x, y = touch.x, touch.y\n        # if the touch isnt on the widget we do nothing, just try children\n        if not touch.grab_current == self:\n            touch.push()\n            touch.apply_transform_2d(self.to_local)\n            if super(Scatter, self).on_touch_up(touch):\n                touch.pop()\n                return True\n            touch.pop()\n\n        # remove it from our saved touches\n        if touch in self._touches and touch.grab_state:\n            touch.ungrab(self)\n            del self._last_touch_pos[touch]\n            self._touches.remove(touch)\n\n        # stop propagating if its within our bounds\n        if self.collide_point(x, y):\n            return True\n\n\nclass ScatterPlane(Scatter):\n    '''This is essentially an unbounded Scatter widget. It's a convenience\n       class to make it easier to handle infinite planes.\n    '''\n\n    def __init__(self, **kwargs):\n        kwargs.setdefault('auto_bring_to_front', False)\n        super(ScatterPlane, self).__init__(**kwargs)\n\n    def collide_point(self, x, y):\n        return True\n"
  },
  {
    "path": "tickeys/kivy/uix/scatterlayout.py",
    "content": "'''\nScatter Layout\n===============\n\n.. versionadded:: 1.6.0\n\nThis layout behaves just like a\n:class:`~kivy.uix.relativelayout.RelativeLayout`.\nWhen a widget is added with position = (0,0) to a :class:`ScatterLayout`,\nthe child widget will also move when you change the position of the\n:class:`ScatterLayout`. The child widget's coordinates remain\n(0,0) as they are relative to the parent layout.\n\nHowever, since :class:`ScatterLayout` is implemented using a\n:class:`~kivy.uix.scatter.Scatter`\nwidget, you can also translate, rotate and scale the layout using touches\nor clicks, just like in the case of a normal Scatter widget, and the child\nwidgets will behave as expected.\n\nIn contrast to a Scatter, the Layout favours 'hint' properties, such as\nsize_hint, size_hint_x, size_hint_y and pos_hint.\n\n.. note::\n\n    The :class:`ScatterLayout` is implemented as a\n    :class:`~kivy.uix.floatlayout.FloatLayout`\n    inside a :class:`~kivy.uix.scatter.Scatter`.\n\n.. warning::\n\n    Since the actual :class:`ScatterLayout` is a\n    :class:`~kivy.uix.scatter.Scatter`, its\n    add_widget and remove_widget functions are overridden to add children\n    to the embedded :class:`~kivy.uix.floatlayout.FloatLayout` (accessible as\n    the `content` property of :class:`~kivy.uix.scatter.Scatter`)\n    automatically. So if you want to access the added child elements,\n    you need self.content.children instead of self.children.\n\n.. warning::\n\n    The :class:`ScatterLayout` was introduced in 1.7.0 and was called\n    :class:`~kivy.uix.relativelayout.RelativeLayout` in prior versions.\n    The :class:`~kivy.uix.relativelayout.RelativeLayout` is now an optimized\n    implementation that uses only a positional transform to avoid some of the\n    heavier calculation involved for :class:`~kivy.uix.scatter.Scatter`.\n\n'''\n\n__all__ = ('ScatterLayout', 'ScatterPlaneLayout')\n\nfrom kivy.uix.floatlayout import FloatLayout\nfrom kivy.uix.scatter import Scatter, ScatterPlane\nfrom kivy.properties import ObjectProperty\n\n\nclass ScatterLayout(Scatter):\n    '''ScatterLayout class, see module documentation for more information.\n    '''\n\n    content = ObjectProperty()\n\n    def __init__(self, **kw):\n        self.content = FloatLayout()\n        super(ScatterLayout, self).__init__(**kw)\n        if self.content.size != self.size:\n            self.content.size = self.size\n        super(ScatterLayout, self).add_widget(self.content)\n        self.bind(size=self.update_size)\n\n    def update_size(self, instance, size):\n        self.content.size = size\n\n    def add_widget(self, *l):\n        self.content.add_widget(*l)\n\n    def remove_widget(self, *l):\n        self.content.remove_widget(*l)\n\n    def clear_widgets(self):\n        self.content.clear_widgets()\n\n\nclass ScatterPlaneLayout(ScatterPlane):\n    '''ScatterPlaneLayout class, see module documentation for more information.\n\n    Similar to ScatterLayout, but based on ScatterPlane - so the input is not\n    bounded.\n\n    .. versionadded:: 1.9.0\n    '''\n\n    def __init__(self, **kwargs):\n        kwargs.setdefault('auto_bring_to_front', False)\n        super(ScatterPlaneLayout, self).__init__(**kwargs)\n\n    def collide_point(self, x, y):\n        return True\n"
  },
  {
    "path": "tickeys/kivy/uix/screenmanager.py",
    "content": "'''Screen Manager\n==============\n\n.. versionadded:: 1.4.0\n\nThe screen manager is a widget dedicated to managing multiple screens for your\napplication. The default :class:`ScreenManager` displays only one\n:class:`Screen` at a time and uses a :class:`TransitionBase` to switch from one\nScreen to another.\n\nMultiple transitions are supported based on changing the screen coordinates /\nscale or even performing fancy animation using custom shaders.\n\nBasic Usage\n-----------\n\nLet's construct a Screen Manager with 4 named screens. When you are creating\na screen, **you absolutely need to give a name to it**::\n\n    from kivy.uix.screenmanager import ScreenManager, Screen\n\n    # Create the manager\n    sm = ScreenManager()\n\n    # Add few screens\n    for i in range(4):\n        screen = Screen(name='Title %d' % i)\n        sm.add_widget(screen)\n\n    # By default, the first screen added into the ScreenManager will be\n    # displayed. You can then change to another screen.\n\n    # Let's display the screen named 'Title 2'\n    # A transition will automatically be used.\n    sm.current = 'Title 2'\n\nThe default :attr:`ScreenManager.transition` is a :class:`SlideTransition` with\noptions :attr:`~SlideTransition.direction` and\n:attr:`~TransitionBase.duration`.\n\nPlease note that by default, a :class:`Screen` displays nothing: it's just a\n:class:`~kivy.uix.relativelayout.RelativeLayout`. You need to use that class as\na root widget for your own screen, the best way being to subclass.\n\n.. warning::\n    As :class:`Screen` is a :class:`~kivy.uix.relativelayout.RelativeLayout`,\n    it is important to understand the\n    :ref:`kivy-uix-relativelayout-common-pitfalls`.\n\nHere is an example with a 'Menu Screen' and a 'Settings Screen'::\n\n    from kivy.app import App\n    from kivy.lang import Builder\n    from kivy.uix.screenmanager import ScreenManager, Screen\n\n    # Create both screens. Please note the root.manager.current: this is how\n    # you can control the ScreenManager from kv. Each screen has by default a\n    # property manager that gives you the instance of the ScreenManager used.\n    Builder.load_string(\"\"\"\n    <MenuScreen>:\n        BoxLayout:\n            Button:\n                text: 'Goto settings'\n                on_press: root.manager.current = 'settings'\n            Button:\n                text: 'Quit'\n\n    <SettingsScreen>:\n        BoxLayout:\n            Button:\n                text: 'My settings button'\n            Button:\n                text: 'Back to menu'\n                on_press: root.manager.current = 'menu'\n    \"\"\")\n\n    # Declare both screens\n    class MenuScreen(Screen):\n        pass\n\n    class SettingsScreen(Screen):\n        pass\n\n    # Create the screen manager\n    sm = ScreenManager()\n    sm.add_widget(MenuScreen(name='menu'))\n    sm.add_widget(SettingsScreen(name='settings'))\n\n    class TestApp(App):\n\n        def build(self):\n            return sm\n\n    if __name__ == '__main__':\n        TestApp().run()\n\n\nChanging Direction\n------------------\n\nA common use case for :class:`ScreenManager` involves using a\n:class:`SlideTransition` which slides right to the next screen\nand slides left to the previous screen. Building on the previous\nexample, this can be accomplished like so::\n\n    Builder.load_string(\"\"\"\n    <MenuScreen>:\n        BoxLayout:\n            Button:\n                text: 'Goto settings'\n                on_press:\n                    root.manager.transition.direction = 'left'\n                    root.manager.current = 'settings'\n            Button:\n                text: 'Quit'\n\n    <SettingScreen>:\n        BoxLayout:\n            Button:\n                text: 'My settings button'\n            Button:\n                text: 'Back to menu'\n                on_press:\n                    root.manager.transition.direction = 'right'\n                    root.manager.current = 'menu'\n    \"\"\")\n\n\nAdvanced Usage\n--------------\n\nFrom 1.8.0, you can now switch dynamically to a new screen, change the\ntransition options and remove the previous one by using\n:meth:`~ScreenManager.switch_to`::\n\n    sm = ScreenManager()\n    screens = [Screen(name='Title {}'.format(i)) for i in range(4)]\n\n    sm.switch_to(screens[0])\n    # later\n    sm.switch_to(screens[1], direction='right')\n\nNote that this method adds the screen to the :class:`ScreenManager` instance\nand should not be used if your screens have already been added to this\ninstance. To switch to a screen which is already added, you should use the\n:attr:`~ScreenManager.current` property.\n\n\nChanging transitions\n--------------------\n\nYou have multiple transitions available by default, such as:\n\n- :class:`NoTransition` - switches screens instantly with no animation\n- :class:`SlideTransition` - slide the screen in/out, from any direction\n- :class:`SwapTransition` - implementation of the iOS swap transition\n- :class:`FadeTransition` - shader to fade the screen in/out\n- :class:`WipeTransition` - shader to wipe the screens from right to left\n- :class:`FallOutTransition` - shader where the old screen 'falls' and\n  becomes transparent, revealing the new one behind it.\n- :class:`RiseInTransition` - shader where the new screen rises from the\n  screen centre while fading from transparent to opaque.\n\nYou can easily switch transitions by changing the\n:attr:`ScreenManager.transition` property::\n\n    sm = ScreenManager(transition=FadeTransition())\n\n.. note::\n\n    Currently, none of Shader based Transitions use\n    anti-aliasing. This is because they use the FBO which doesn't have\n    any logic to handle supersampling. This is a known issue and we\n    are working on a transparent implementation that will give the\n    same results as if it had been rendered on screen.\n\n    To be more concrete, if you see sharp edged text during the animation, it's\n    normal.\n\n'''\n\n__all__ = ('Screen', 'ScreenManager', 'ScreenManagerException',\n           'TransitionBase', 'ShaderTransition', 'SlideTransition',\n           'SwapTransition', 'FadeTransition', 'WipeTransition',\n           'FallOutTransition', 'RiseInTransition', 'NoTransition')\n\nfrom kivy.compat import iteritems\nfrom kivy.logger import Logger\nfrom kivy.event import EventDispatcher\nfrom kivy.clock import Clock\nfrom kivy.uix.floatlayout import FloatLayout\nfrom kivy.properties import (StringProperty, ObjectProperty, AliasProperty,\n                             NumericProperty, ListProperty, OptionProperty,\n                             BooleanProperty)\nfrom kivy.animation import Animation, AnimationTransition\nfrom kivy.uix.relativelayout import RelativeLayout\nfrom kivy.lang import Builder\nfrom kivy.graphics import (RenderContext, Rectangle, Fbo,\n                           ClearColor, ClearBuffers, BindTexture, PushMatrix,\n                           PopMatrix, Translate, Callback)\n\n\nclass ScreenManagerException(Exception):\n    '''Exception for the :class:`ScreenManager`.\n    '''\n    pass\n\n\nclass Screen(RelativeLayout):\n    '''Screen is an element intended to be used with a :class:`ScreenManager`.\n    Check module documentation for more information.\n\n    :Events:\n        `on_pre_enter`: ()\n            Event fired when the screen is about to be used: the entering\n            animation is started.\n        `on_enter`: ()\n            Event fired when the screen is displayed: the entering animation is\n            complete.\n        `on_pre_leave`: ()\n            Event fired when the screen is about to be removed: the leaving\n            animation is started.\n        `on_leave`: ()\n            Event fired when the screen is removed: the leaving animation is\n            finished.\n\n    .. versionchanged:: 1.6.0\n        Events `on_pre_enter`, `on_enter`, `on_pre_leave` and `on_leave` were\n        added.\n    '''\n\n    name = StringProperty('')\n    '''\n    Name of the screen which must be unique within a :class:`ScreenManager`.\n    This is the name used for :attr:`ScreenManager.current`.\n\n    :attr:`name` is a :class:`~kivy.properties.StringProperty` and defaults to\n    ''.\n    '''\n\n    manager = ObjectProperty(None, allownone=True)\n    ''':class:`ScreenManager` object, set when the screen is added to a\n    manager.\n\n    :attr:`manager` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None, read-only.\n\n    '''\n\n    transition_progress = NumericProperty(0.)\n    '''Value that represents the completion of the current transition, if any\n    is occuring.\n\n    If a transition is in progress, whatever the mode, the value will change\n    from 0 to 1. If you want to know if it's an entering or leaving animation,\n    check the :attr:`transition_state`.\n\n    :attr:`transition_progress` is a :class:`~kivy.properties.NumericProperty`\n    and defaults to 0.\n    '''\n\n    transition_state = OptionProperty('out', options=('in', 'out'))\n    '''Value that represents the state of the transition:\n\n    - 'in' if the transition is going to show your screen\n    - 'out' if the transition is going to hide your screen\n\n    After the transition is complete, the state will retain it's last value (in\n    or out).\n\n    :attr:`transition_state` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to 'out'.\n    '''\n\n    __events__ = ('on_pre_enter', 'on_enter', 'on_pre_leave', 'on_leave')\n\n    def on_pre_enter(self, *args):\n        pass\n\n    def on_enter(self, *args):\n        pass\n\n    def on_pre_leave(self, *args):\n        pass\n\n    def on_leave(self, *args):\n        pass\n\n    def __repr__(self):\n        return '<Screen name=%r>' % self.name\n\n\nclass TransitionBase(EventDispatcher):\n    '''TransitionBase is used to animate 2 screens within the\n    :class:`ScreenManager`. This class acts as a base for other\n    implementations like the :class:`SlideTransition` and\n    :class:`SwapTransition`.\n\n    :Events:\n        `on_progress`: Transition object, progression float\n            Fired during the animation of the transition.\n        `on_complete`: Transition object\n            Fired when the transition is fininshed.\n    '''\n\n    screen_out = ObjectProperty()\n    '''Property that contains the screen to hide.\n    Automatically set by the :class:`ScreenManager`.\n\n    :class:`screen_out` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    screen_in = ObjectProperty()\n    '''Property that contains the screen to show.\n    Automatically set by the :class:`ScreenManager`.\n\n    :class:`screen_in` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    duration = NumericProperty(.4)\n    '''Duration in seconds of the transition.\n\n    :class:`duration` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to .4 (= 400ms).\n\n    .. versionchanged:: 1.8.0\n\n        Default duration has been changed from 700ms to 400ms.\n    '''\n\n    manager = ObjectProperty()\n    ''':class:`ScreenManager` object, set when the screen is added to a\n    manager.\n\n    :attr:`manager` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None, read-only.\n\n    '''\n\n    is_active = BooleanProperty(False)\n    '''Indicate whether the transition is currently active or not.\n\n    :attr:`is_active` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False, read-only.\n    '''\n\n    # privates\n\n    _anim = ObjectProperty(allownone=True)\n\n    __events__ = ('on_progress', 'on_complete')\n\n    def start(self, manager):\n        '''(internal) Starts the transition. This is automatically\n        called by the :class:`ScreenManager`.\n        '''\n        if self.is_active:\n            raise ScreenManagerException('start() is called twice!')\n        self.manager = manager\n        self._anim = Animation(d=self.duration, s=0)\n        self._anim.bind(on_progress=self._on_progress,\n                        on_complete=self._on_complete)\n\n        self.add_screen(self.screen_in)\n        self.screen_in.transition_progress = 0.\n        self.screen_in.transition_state = 'in'\n        self.screen_out.transition_progress = 0.\n        self.screen_out.transition_state = 'out'\n        self.screen_in.dispatch('on_pre_enter')\n        self.screen_out.dispatch('on_pre_leave')\n\n        self.is_active = True\n        self._anim.start(self)\n        self.dispatch('on_progress', 0)\n\n    def stop(self):\n        '''(internal) Stops the transition. This is automatically called by the\n        :class:`ScreenManager`.\n        '''\n        if self._anim:\n            self._anim.cancel(self)\n            self.dispatch('on_complete')\n            self._anim = None\n        self.is_active = False\n\n    def add_screen(self, screen):\n        '''(internal) Used to add a screen to the :class:`ScreenManager`.\n        '''\n        self.manager.real_add_widget(screen)\n\n    def remove_screen(self, screen):\n        '''(internal) Used to remove a screen from the :class:`ScreenManager`.\n        '''\n        self.manager.real_remove_widget(screen)\n\n    def on_complete(self):\n        self.remove_screen(self.screen_out)\n\n    def on_progress(self, progression):\n        pass\n\n    def _on_progress(self, *l):\n        progress = l[-1]\n        self.screen_in.transition_progress = progress\n        self.screen_out.transition_progress = 1. - progress\n        self.dispatch('on_progress', progress)\n\n    def _on_complete(self, *l):\n        self.is_active = False\n        self.dispatch('on_complete')\n        self.screen_in.dispatch('on_enter')\n        self.screen_out.dispatch('on_leave')\n        self._anim = None\n\n\nclass ShaderTransition(TransitionBase):\n    '''Transition class that uses a Shader for animating the transition between\n    2 screens. By default, this class doesn't assign any fragment/vertex\n    shader. If you want to create your own fragment shader for the transition,\n    you need to declare the header yourself and include the \"t\", \"tex_in\" and\n    \"tex_out\" uniform::\n\n        # Create your own transition. This shader implements a \"fading\"\n        # transition.\n        fs = \"\"\"$HEADER\n            uniform float t;\n            uniform sampler2D tex_in;\n            uniform sampler2D tex_out;\n\n            void main(void) {\n                vec4 cin = texture2D(tex_in, tex_coord0);\n                vec4 cout = texture2D(tex_out, tex_coord0);\n                gl_FragColor = mix(cout, cin, t);\n            }\n        \"\"\"\n\n        # And create your transition\n        tr = ShaderTransition(fs=fs)\n        sm = ScreenManager(transition=tr)\n\n    '''\n\n    fs = StringProperty(None)\n    '''Fragment shader to use.\n\n    :attr:`fs` is a :class:`~kivy.properties.StringProperty` and defaults to\n    None.'''\n\n    vs = StringProperty(None)\n    '''Vertex shader to use.\n\n    :attr:`vs` is a :class:`~kivy.properties.StringProperty` and defaults to\n    None.'''\n\n    clearcolor = ListProperty([0, 0, 0, 1])\n    '''Sets the color of Fbo ClearColor.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`clearcolor` is a :class:`~kivy.properties.ListProperty`\n    and defaults to [0, 0, 0, 1].'''\n\n    def make_screen_fbo(self, screen):\n        fbo = Fbo(size=screen.size)\n        with fbo:\n            ClearColor(*self.clearcolor)\n            ClearBuffers()\n        fbo.add(screen.canvas)\n        with fbo.before:\n            PushMatrix()\n            Translate(-screen.x, -screen.y, 0)\n        with fbo.after:\n            PopMatrix()\n        return fbo\n\n    def on_progress(self, progress):\n        self.render_ctx['t'] = progress\n\n    def on_complete(self):\n        self.render_ctx['t'] = 1.\n        super(ShaderTransition, self).on_complete()\n\n    def _remove_out_canvas(self, *args):\n        if (self.screen_out\n                and self.screen_out.canvas in self.manager.canvas.children\n                and self.screen_out not in self.manager.children):\n            self.manager.canvas.remove(self.screen_out.canvas)\n\n    def add_screen(self, screen):\n        self.screen_in.pos = self.screen_out.pos\n        self.screen_in.size = self.screen_out.size\n        self.manager.real_remove_widget(self.screen_out)\n        self.manager.canvas.add(self.screen_out.canvas)\n\n        def remove_screen_out(instr):\n            Clock.schedule_once(self._remove_out_canvas, -1)\n            self.render_ctx.remove(instr)\n\n        self.fbo_in = self.make_screen_fbo(self.screen_in)\n        self.fbo_out = self.make_screen_fbo(self.screen_out)\n        self.manager.canvas.add(self.fbo_in)\n        self.manager.canvas.add(self.fbo_out)\n\n        self.render_ctx = RenderContext(fs=self.fs, vs=self.vs,\n                                        use_parent_modelview=True,\n                                        use_parent_projection=True)\n        with self.render_ctx:\n            BindTexture(texture=self.fbo_out.texture, index=1)\n            BindTexture(texture=self.fbo_in.texture, index=2)\n            x, y = self.screen_in.pos\n            w, h = self.fbo_in.texture.size\n            Rectangle(size=(w, h), pos=(x, y),\n                      tex_coords=self.fbo_in.texture.tex_coords)\n            Callback(remove_screen_out)\n        self.render_ctx['tex_out'] = 1\n        self.render_ctx['tex_in'] = 2\n        self.manager.canvas.add(self.render_ctx)\n\n    def remove_screen(self, screen):\n        self.manager.canvas.remove(self.fbo_in)\n        self.manager.canvas.remove(self.fbo_out)\n        self.manager.canvas.remove(self.render_ctx)\n        self._remove_out_canvas()\n        self.manager.real_add_widget(self.screen_in)\n\n    def stop(self):\n        self._remove_out_canvas()\n        super(ShaderTransition, self).stop()\n\n\nclass NoTransition(TransitionBase):\n    '''No transition, instantly switches to the next screen with no delay or\n    animation.\n\n    .. versionadded:: 1.8.0\n    '''\n\n    duration = NumericProperty(0.0)\n\n    def on_complete(self):\n        self.screen_in.pos = self.manager.pos\n        self.screen_out.pos = self.manager.pos\n        super(NoTransition, self).on_complete()\n\n\nclass SlideTransition(TransitionBase):\n    '''Slide Transition, can be used to show a new screen from any direction:\n    left, right, up or down.\n    '''\n\n    direction = OptionProperty('left', options=('left', 'right', 'up', 'down'))\n    '''Direction of the transition.\n\n    :attr:`direction` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to 'left'. Can be one of 'left', 'right', 'up' or 'down'.\n    '''\n\n    def on_progress(self, progression):\n        a = self.screen_in\n        b = self.screen_out\n        manager = self.manager\n        x, y = manager.pos\n        width, height = manager.size\n        direction = self.direction\n        al = AnimationTransition.out_quad\n        progression = al(progression)\n        if direction == 'left':\n            a.y = b.y = y\n            a.x = x + width * (1 - progression)\n            b.x = x - width * progression\n        elif direction == 'right':\n            a.y = b.y = y\n            b.x = x + width * progression\n            a.x = x - width * (1 - progression)\n        elif direction == 'down':\n            a.x = b.x = x\n            a.y = y + height * (1 - progression)\n            b.y = y - height * progression\n        elif direction == 'up':\n            a.x = b.x = manager.x\n            b.y = y + height * progression\n            a.y = y - height * (1 - progression)\n\n    def on_complete(self):\n        self.screen_in.pos = self.manager.pos\n        self.screen_out.pos = self.manager.pos\n        super(SlideTransition, self).on_complete()\n\n\nclass SwapTransition(TransitionBase):\n    '''Swap transition that looks like iOS transition when a new window\n    appears on the screen.\n    '''\n\n    def add_screen(self, screen):\n        self.manager.real_add_widget(screen, 1)\n\n    def on_complete(self):\n        self.screen_in.scale = 1.\n        self.screen_out.scale = 1.\n        self.screen_in.pos = self.manager.pos\n        self.screen_out.pos = self.manager.pos\n        super(SwapTransition, self).on_complete()\n\n    def on_progress(self, progression):\n        a = self.screen_in\n        b = self.screen_out\n        manager = self.manager\n\n        b.scale = 1. - progression * 0.7\n        a.scale = 0.5 + progression * 0.5\n        a.center_y = b.center_y = manager.center_y\n\n        al = AnimationTransition.in_out_sine\n\n        if progression < 0.5:\n            p2 = al(progression * 2)\n            width = manager.width * 0.7\n            widthb = manager.width * 0.2\n            a.x = manager.center_x + p2 * width / 2.\n            b.center_x = manager.center_x - p2 * widthb / 2.\n        else:\n            if self.screen_in is self.manager.children[-1]:\n                self.manager.real_remove_widget(self.screen_in)\n                self.manager.real_add_widget(self.screen_in)\n            p2 = al((progression - 0.5) * 2)\n            width = manager.width * 0.85\n            widthb = manager.width * 0.2\n            a.x = manager.x + width * (1 - p2)\n            b.center_x = manager.center_x - (1 - p2) * widthb / 2.\n\n\nclass WipeTransition(ShaderTransition):\n    '''Wipe transition, based on a fragment Shader.\n    '''\n\n    WIPE_TRANSITION_FS = '''$HEADER$\n    uniform float t;\n    uniform sampler2D tex_in;\n    uniform sampler2D tex_out;\n\n    void main(void) {\n        vec4 cin = texture2D(tex_in, tex_coord0);\n        vec4 cout = texture2D(tex_out, tex_coord0);\n        gl_FragColor = mix(cout, cin, clamp((-1.5 + 1.5*tex_coord0.x + 2.5*t),\n            0.0, 1.0));\n    }\n    '''\n    fs = StringProperty(WIPE_TRANSITION_FS)\n\n\nclass FadeTransition(ShaderTransition):\n    '''Fade transition, based on a fragment Shader.\n    '''\n\n    FADE_TRANSITION_FS = '''$HEADER$\n    uniform float t;\n    uniform sampler2D tex_in;\n    uniform sampler2D tex_out;\n\n    void main(void) {\n        vec4 cin = vec4(texture2D(tex_in, tex_coord0.st));\n        vec4 cout = vec4(texture2D(tex_out, tex_coord0.st));\n        vec4 frag_col = vec4(t * cin) + vec4((1.0 - t) * cout);\n        gl_FragColor = frag_col;\n    }\n    '''\n    fs = StringProperty(FADE_TRANSITION_FS)\n\n\nclass FallOutTransition(ShaderTransition):\n    '''Transition where the new screen 'falls' from the screen centre,\n    becoming smaller and more transparent until it disappears, and\n    revealing the new screen behind it. Mimics the popular/standard\n    Android transition.\n\n    .. versionadded:: 1.8.0\n\n    '''\n\n    duration = NumericProperty(0.15)\n    '''Duration in seconds of the transition, replacing the default of\n    :class:`TransitionBase`.\n\n    :class:`duration` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to .15 (= 150ms).\n    '''\n\n    FALLOUT_TRANSITION_FS = '''$HEADER$\n    uniform float t;\n    uniform sampler2D tex_in;\n    uniform sampler2D tex_out;\n\n    void main(void) {\n        /* quantities for position and opacity calculation */\n        float tr = 0.5*sin(t);  /* 'real' time */\n        vec2 diff = (tex_coord0.st - 0.5) * (1.0/(1.0-tr));\n        vec2 dist = diff + 0.5;\n        float max_dist = 1.0 - tr;\n\n        /* in and out colors */\n        vec4 cin = vec4(texture2D(tex_in, tex_coord0.st));\n        vec4 cout = vec4(texture2D(tex_out, dist));\n\n        /* opacities for in and out textures */\n        float oin = clamp(1.0-cos(t), 0.0, 1.0);\n        float oout = clamp(cos(t), 0.0, 1.0);\n\n        bvec2 outside_bounds = bvec2(abs(tex_coord0.s - 0.5) > 0.5*max_dist,\n                                     abs(tex_coord0.t - 0.5) > 0.5*max_dist);\n\n        vec4 frag_col;\n        if (any(outside_bounds) ){\n            frag_col = vec4(cin.x, cin.y, cin.z, 1.0);\n            }\n        else {\n            frag_col = vec4(oout*cout.x + oin*cin.x, oout*cout.y + oin*cin.y,\n                            oout*cout.z + oin*cin.z, 1.0);\n            }\n\n        gl_FragColor = frag_col;\n    }\n    '''\n\n    fs = StringProperty(FALLOUT_TRANSITION_FS)\n\n\nclass RiseInTransition(ShaderTransition):\n    '''Transition where the new screen rises from the screen centre,\n    becoming larger and changing from transparent to opaque until it\n    fills the screen. Mimics the popular/standard Android transition.\n\n    .. versionadded:: 1.8.0\n    '''\n\n    duration = NumericProperty(0.2)\n    '''Duration in seconds of the transition, replacing the default of\n    :class:`TransitionBase`.\n\n    :class:`duration` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to .2 (= 200ms).\n    '''\n\n    RISEIN_TRANSITION_FS = '''$HEADER$\n    uniform float t;\n    uniform sampler2D tex_in;\n    uniform sampler2D tex_out;\n\n    void main(void) {\n        /* quantities for position and opacity calculation */\n        float tr = 0.5 - 0.5*sqrt(sin(t));  /* 'real' time */\n        vec2 diff = (tex_coord0.st - 0.5) * (1.0/(1.0-tr));\n        vec2 dist = diff + 0.5;\n        float max_dist = 1.0 - tr;\n\n        /* in and out colors */\n        vec4 cin = vec4(texture2D(tex_in, dist));\n        vec4 cout = vec4(texture2D(tex_out, tex_coord0.st));\n\n        /* opacities for in and out textures */\n        float oin = clamp(sin(2.0*t), 0.0, 1.0);\n        float oout = clamp(1.0 - sin(2.0*t), 0.0, 1.0);\n\n        bvec2 outside_bounds = bvec2(abs(tex_coord0.s - 0.5) > 0.5*max_dist,\n                                     abs(tex_coord0.t - 0.5) > 0.5*max_dist);\n\n        vec4 frag_col;\n        if (any(outside_bounds) ){\n            frag_col = vec4(cout.x, cout.y, cout.z, 1.0);\n            }\n        else {\n            frag_col = vec4(oout*cout.x + oin*cin.x, oout*cout.y + oin*cin.y,\n                            oout*cout.z + oin*cin.z, 1.0);\n            }\n\n        gl_FragColor = frag_col;\n    }\n    '''\n\n    fs = StringProperty(RISEIN_TRANSITION_FS)\n\n\nclass ScreenManager(FloatLayout):\n    '''Screen manager. This is the main class that will control your\n    :class:`Screen` stack and memory.\n\n    By default, the manager will show only one screen at a time.\n    '''\n\n    current = StringProperty(None)\n    '''Name of the screen currently shown, or the screen to show.\n\n  ::\n\n        from kivy.uix.screenmanager import ScreenManager, Screen\n\n        sm = ScreenManager()\n        sm.add_widget(Screen(name='first'))\n        sm.add_widget(Screen(name='second'))\n\n        # By default, the first added screen will be shown. If you want to\n        # show another one, just set the 'current' property.\n        sm.current = 'second'\n    '''\n\n    transition = ObjectProperty(SlideTransition(), baseclass=TransitionBase)\n    '''Transition object to use for animating the screen that will be hidden\n    and the screen that will be shown. By default, an instance of\n    :class:`SlideTransition` will be given.\n\n    For example, if you want to change to a :class:`WipeTransition`::\n\n        from kivy.uix.screenmanager import ScreenManager, Screen,\n        WipeTransition\n\n        sm = ScreenManager(transition=WipeTransition())\n        sm.add_widget(Screen(name='first'))\n        sm.add_widget(Screen(name='second'))\n\n        # by default, the first added screen will be shown. If you want to\n        # show another one, just set the 'current' property.\n        sm.current = 'second'\n\n    .. versionchanged:: 1.8.0\n\n        Default transition has been changed from :class:`SwapTransition` to\n        :class:`SlideTransition`.\n    '''\n\n    screens = ListProperty()\n    '''List of all the :class:`Screen` widgets added. You must not change the\n    list manually. Use :meth:`Screen.add_widget` instead.\n\n    :attr:`screens` is a :class:`~kivy.properties.ListProperty` and defaults to\n    [], read-only.\n    '''\n\n    current_screen = ObjectProperty(None)\n    '''Contains the currently displayed screen. You must not change this\n    property manually, use :attr:`current` instead.\n\n    :attr:`current_screen` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None, read-only.\n    '''\n\n    def _get_screen_names(self):\n        return [s.name for s in self.screens]\n\n    screen_names = AliasProperty(_get_screen_names,\n                                 None, bind=('screens', ))\n    '''List of the names of all the :class:`Screen` widgets added. The list\n    is read only.\n\n    :attr:`screens_names` is an :class:`~kivy.properties.AliasProperty` and\n    is read-only. It is updated if the screen list changes or the name\n    of a screen changes.\n    '''\n\n    def __init__(self, **kwargs):\n        super(ScreenManager, self).__init__(**kwargs)\n        self.bind(pos=self._update_pos)\n\n    def _screen_name_changed(self, screen, name):\n        self.property('screen_names').dispatch(self)\n        if screen == self.current_screen:\n            self.current = name\n\n    def add_widget(self, screen):\n        if not isinstance(screen, Screen):\n            raise ScreenManagerException(\n                'ScreenManager accepts only Screen widget.')\n        if screen.manager:\n            if screen.manager is self:\n                raise ScreenManagerException(\n                    'Screen already managed by this ScreenManager (are you '\n                    'calling `switch_to` when you should be setting '\n                    '`current`?)')\n            raise ScreenManagerException(\n                'Screen already managed by another ScreenManager.')\n        screen.manager = self\n        screen.bind(name=self._screen_name_changed)\n        self.screens.append(screen)\n        if self.current is None:\n            self.current = screen.name\n\n    def remove_widget(self, *l):\n        screen = l[0]\n        if not isinstance(screen, Screen):\n            raise ScreenManagerException(\n                'ScreenManager uses remove_widget only to remove' +\n                'screens added via add_widget! use real_remove_widget.')\n\n        if not screen in self.screens:\n            return\n        if self.current_screen == screen:\n            other = next(self)\n            if other:\n                self.current = other\n        screen.manager = None\n        screen.unbind(name=self._screen_name_changed)\n        self.screens.remove(screen)\n\n    def real_add_widget(self, *l):\n        # ensure screen is removed from it's previous parent before adding'\n        if l[0].parent:\n            l[0].parent.remove_widget(l[0])\n        super(ScreenManager, self).add_widget(*l)\n\n    def real_remove_widget(self, *l):\n        super(ScreenManager, self).remove_widget(*l)\n\n    def on_current(self, instance, value):\n        screen = self.get_screen(value)\n        if not screen:\n            return\n        if screen == self.current_screen:\n            return\n\n        self.transition.stop()\n\n        previous_screen = self.current_screen\n        self.current_screen = screen\n        if previous_screen:\n            self.transition.screen_in = screen\n            self.transition.screen_out = previous_screen\n            self.transition.start(self)\n        else:\n            self.real_add_widget(screen)\n            screen.pos = self.pos\n            self.do_layout()\n            screen.dispatch('on_pre_enter')\n            screen.dispatch('on_enter')\n\n    def get_screen(self, name):\n        '''Return the screen widget associated with the name or raise a\n        :class:`ScreenManagerException` if not found.\n        '''\n        matches = [s for s in self.screens if s.name == name]\n        num_matches = len(matches)\n        if num_matches == 0:\n            raise ScreenManagerException('No Screen with name \"%s\".' % name)\n        if num_matches > 1:\n            Logger.warn('Multiple screens named \"%s\": %s' % (name, matches))\n        return matches[0]\n\n    def has_screen(self, name):\n        '''Return True if a screen with the `name` has been found.\n\n        .. versionadded:: 1.6.0\n        '''\n        return bool([s for s in self.screens if s.name == name])\n\n    def __next__(self):\n        '''Py2K backwards compatability without six or other lib.\n        '''\n        screens = self.screens\n        if not screens:\n            return\n        try:\n            index = screens.index(self.current_screen)\n            index = (index + 1) % len(screens)\n            return screens[index].name\n        except ValueError:\n            return\n\n    def next(self):\n        '''Return the name of the next screen from the screen list.'''\n        return self.__next__()\n\n    def previous(self):\n        '''Return the name of the previous screen from the screen list.\n        '''\n        screens = self.screens\n        if not screens:\n            return\n        try:\n            index = screens.index(self.current_screen)\n            index = (index - 1) % len(screens)\n            return screens[index].name\n        except ValueError:\n            return\n\n    def switch_to(self, screen, **options):\n        '''Add a new screen to the ScreenManager and switch to it. The previous\n        screen will be removed from the children. `options` are the\n        :attr:`transition` options that will be changed before the animation\n        happens.\n\n        If no previous screens are available, the screen will be used as the\n        main one::\n\n            sm = ScreenManager()\n            sm.switch_to(screen1)\n            # later\n            sm.switch_to(screen2, direction='left')\n            # later\n            sm.switch_to(screen3, direction='right', duration=1.)\n\n        If any animation is in progress, it will be stopped and replaced by\n        this one: you should avoid this because the animation will just look\n        weird. Use either :meth:`switch_to` or :attr:`current` but not both.\n\n        The `screen` name will be changed if there is any conflict with the\n        current screen.\n\n        .. versionadded: 1.8.0\n        '''\n        assert(screen is not None)\n\n        if not isinstance(screen, Screen):\n            raise ScreenManagerException(\n                'ScreenManager accepts only Screen widget.')\n\n        # stop any transition that might be happening already\n        self.transition.stop()\n\n        # ensure the screen name will be unique\n        if screen not in self.children:\n            if self.has_screen(screen.name):\n                screen.name = self._generate_screen_name()\n\n        # change the transition if given explicitly\n        old_transition = self.transition\n        specified_transition = options.pop(\"transition\", None)\n        if specified_transition:\n            self.transition = specified_transition\n\n        # change the transition options\n        for key, value in iteritems(options):\n            setattr(self.transition, key, value)\n\n        # add and leave if we are set as the current screen\n        self.add_widget(screen)\n        if self.current_screen is screen:\n            return\n\n        old_current = self.current_screen\n\n        def remove_old_screen(transition):\n            if old_current in self.children:\n                self.remove_widget(old_current)\n                self.transition = old_transition\n            transition.unbind(on_complete=remove_old_screen)\n        self.transition.bind(on_complete=remove_old_screen)\n\n        self.current = screen.name\n\n    def _generate_screen_name(self):\n        i = 0\n        while True:\n            name = '_screen{}'.format(i)\n            if not self.has_screen(name):\n                return name\n            i += 1\n\n    def _update_pos(self, instance, value):\n        for child in self.children:\n            if self.transition.is_active and \\\n                (child == self.transition.screen_in or\n                 child == self.transition.screen_out):\n                    continue\n            child.pos = value\n\n    def on_touch_down(self, touch):\n        if self.transition.is_active:\n            return False\n        return super(ScreenManager, self).on_touch_down(touch)\n\n    def on_touch_move(self, touch):\n        if self.transition.is_active:\n            return False\n        return super(ScreenManager, self).on_touch_move(touch)\n\n    def on_touch_up(self, touch):\n        if self.transition.is_active:\n            return False\n        return super(ScreenManager, self).on_touch_up(touch)\n\nif __name__ == '__main__':\n    from kivy.app import App\n    from kivy.uix.button import Button\n    Builder.load_string('''\n<Screen>:\n    canvas:\n        Color:\n            rgb: .2, .2, .2\n        Rectangle:\n            size: self.size\n\n    GridLayout:\n        cols: 2\n        Button:\n            text: 'Hello world'\n        Button:\n            text: 'Hello world'\n        Button:\n            text: 'Hello world'\n        Button:\n            text: 'Hello world'\n''')\n\n    class TestApp(App):\n\n        def change_view(self, *l):\n            #d = ('left', 'up', 'down', 'right')\n            #di = d.index(self.sm.transition.direction)\n            #self.sm.transition.direction = d[(di + 1) % len(d)]\n            self.sm.current = next(self.sm)\n\n        def remove_screen(self, *l):\n            self.sm.remove_widget(self.sm.get_screen('test1'))\n\n        def build(self):\n            root = FloatLayout()\n            self.sm = sm = ScreenManager(transition=SwapTransition())\n\n            sm.add_widget(Screen(name='test1'))\n            sm.add_widget(Screen(name='test2'))\n\n            btn = Button(size_hint=(None, None))\n            btn.bind(on_release=self.change_view)\n\n            btn2 = Button(size_hint=(None, None), x=100)\n            btn2.bind(on_release=self.remove_screen)\n\n            root.add_widget(sm)\n            root.add_widget(btn)\n            root.add_widget(btn2)\n            return root\n\n    TestApp().run()\n"
  },
  {
    "path": "tickeys/kivy/uix/scrollview.py",
    "content": "'''Scroll View\n===========\n\n.. versionadded:: 1.0.4\n\nThe :class:`ScrollView` widget provides a scrollable/pannable viewport that is\nclipped at the scrollview's bounding box.\n\n\nScrolling Behavior\n------------------\n\nThe ScrollView accepts only one child and applies a viewport/window to\nit according to the :attr:`ScrollView.scroll_x` and\n:attr:`ScrollView.scroll_y` properties. Touches are analyzed to\ndetermine if the user wants to scroll or control the child in some\nother manner - you cannot do both at the same time. To determine if\ninteraction is a scrolling gesture, these properties are used:\n\n    - :attr:`ScrollView.scroll_distance`: the minimum distance to travel,\n         defaults to 20 pixels.\n    - :attr:`ScrollView.scroll_timeout`: the maximum time period, defaults\n         to 250 milliseconds.\n\nIf a touch travels :attr:`~ScrollView.scroll_distance` pixels within the\n:attr:`~ScrollView.scroll_timeout` period, it is recognized as a scrolling\ngesture and translation (scroll/pan) will begin. If the timeout occurs, the\ntouch down event is dispatched to the child instead (no translation).\n\nThe default value for those settings can be changed in the configuration file::\n\n    [widgets]\n    scroll_timeout = 250\n    scroll_distance = 20\n\n.. versionadded:: 1.1.1\n\n    ScrollView now animates scrolling in Y when a mousewheel is used.\n\n\nLimiting to the X or Y Axis\n---------------------------\n\nBy default, the ScrollView allows scrolling in both the X and Y axes. You can\nexplicitly disable scrolling on an axis by setting\n:attr:`ScrollView.do_scroll_x` or :attr:`ScrollView.do_scroll_y` to False.\n\n\nManaging the Content Size and Position\n--------------------------------------\n\nScrollView manages the position of its children similarly to a\nRelativeLayout (see :mod:`~kivy.uix.relativelayout`) but not the size. You must\ncarefully specify the `size_hint` of your content to get the desired\nscroll/pan effect.\n\nBy default, size_hint is (1, 1), so the content size will fit your ScrollView\nexactly (you will have nothing to scroll). You must deactivate at least one of\nthe size_hint instructions (x or y) of the child to enable scrolling.\n\nTo scroll a :class:`GridLayout` on Y-axis/vertically, set the child's width\nidentical to that of the ScrollView (size_hint_x=1, default), and set the\nsize_hint_y property to None::\n\n    layout = GridLayout(cols=1, spacing=10, size_hint_y=None)\n    # Make sure the height is such that there is something to scroll.\n    layout.bind(minimum_height=layout.setter('height'))\n    for i in range(30):\n        btn = Button(text=str(i), size_hint_y=None, height=40)\n        layout.add_widget(btn)\n    root = ScrollView(size_hint=(None, None), size=(400, 400))\n    root.add_widget(layout)\n\n\nOverscroll Effects\n------------------\n\n.. versionadded:: 1.7.0\n\nWhen scrolling would exceed the bounds of the :class:`ScrollView`, it\nuses a :class:`~kivy.effects.scroll.ScrollEffect` to handle the\noverscroll. These effects can perform actions like bouncing back,\nchanging opacity, or simply preventing scrolling beyond the normal\nboundaries. Note that complex effects may perform many computations,\nwhich can be slow on weaker hardware.\n\nYou can change what effect is being used by setting\n:attr:`ScrollView.effect_cls` to any effect class. Current options\ninclude:\n\n    - :class:`~kivy.effects.scroll.ScrollEffect`: Does not allow\n      scrolling beyond the :class:`ScrollView` boundaries.\n    - :class:`~kivy.effects.dampedscroll.DampedScrollEffect`: The\n      current default. Allows the user to scroll beyond the normal\n      boundaries, but has the content spring back once the\n      touch/click is released.\n    - :class:`~kivy.effects.opacityscroll.OpacityScrollEffect`: Similar\n      to the :class:`~kivy.effect.dampedscroll.DampedScrollEffect`, but\n      also reduces opacity during overscroll.\n\nYou can also create your own scroll effect by subclassing one of these,\nthen pass it as the :attr:`~ScrollView.effect_cls` in the same way.\n\nAlternatively, you can set :attr:`ScrollView.effect_x` and/or\n:attr:`ScrollView.effect_y` to an *instance* of the effect you want to\nuse. This will override the default effect set in\n:attr:`ScrollView.effect_cls`.\n\nAll the effects are located in the :mod:`kivy.effects`.\n\n'''\n\n__all__ = ('ScrollView', )\n\nfrom functools import partial\nfrom kivy.animation import Animation\nfrom kivy.compat import string_types\nfrom kivy.config import Config\nfrom kivy.clock import Clock\nfrom kivy.factory import Factory\nfrom kivy.uix.stencilview import StencilView\nfrom kivy.metrics import sp\nfrom kivy.effects.dampedscroll import DampedScrollEffect\nfrom kivy.properties import NumericProperty, BooleanProperty, AliasProperty, \\\n    ObjectProperty, ListProperty, ReferenceListProperty, OptionProperty\n\n\n# When we are generating documentation, Config doesn't exist\n_scroll_timeout = _scroll_distance = 0\nif Config:\n    _scroll_timeout = Config.getint('widgets', 'scroll_timeout')\n    _scroll_distance = sp(Config.getint('widgets', 'scroll_distance'))\n\n\nclass ScrollView(StencilView):\n    '''ScrollView class. See module documentation for more information.\n\n    :Events:\n        `on_scroll_start`\n            Generic event fired when scrolling starts from touch.\n        `on_scroll_move`\n            Generic event fired when scrolling move from touch.\n        `on_scroll_stop`\n            Generic event fired when scrolling stops from touch.\n\n    .. versionchanged:: 1.9.0\n        `on_scroll_start`, `on_scroll_move` and `on_scroll_stop` events are\n        now dispatched when scrolling to handle nested ScrollViews.\n\n    .. versionchanged:: 1.7.0\n        `auto_scroll`, `scroll_friction`, `scroll_moves`, `scroll_stoptime' has\n        been deprecated, use :attr:`effect_cls` instead.\n    '''\n\n    scroll_distance = NumericProperty(_scroll_distance)\n    '''Distance to move before scrolling the :class:`ScrollView`, in pixels. As\n    soon as the distance has been traveled, the :class:`ScrollView` will start\n    to scroll, and no touch event will go to children.\n    It is advisable that you base this value on the dpi of your target device's\n    screen.\n\n    :attr:`scroll_distance` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 20 (pixels), according to the default value in user\n    configuration.\n    '''\n\n    scroll_wheel_distance = NumericProperty(20)\n    '''Distance to move when scrolling with a mouse wheel.\n    It is advisable that you base this value on the dpi of your target device's\n    screen.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`scroll_wheel_distance` is a\n    :class:`~kivy.properties.NumericProperty` , defaults to 20 pixels.\n    '''\n\n    scroll_timeout = NumericProperty(_scroll_timeout)\n    '''Timeout allowed to trigger the :attr:`scroll_distance`, in milliseconds.\n    If the user has not moved :attr:`scroll_distance` within the timeout,\n    the scrolling will be disabled, and the touch event will go to the\n    children.\n\n    :attr:`scroll_timeout` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 55 (milliseconds) according to the default value in user\n    configuration.\n\n    .. versionchanged:: 1.5.0\n        Default value changed from 250 to 55.\n    '''\n\n    scroll_x = NumericProperty(0.)\n    '''X scrolling value, between 0 and 1. If 0, the content's left side will\n    touch the left side of the ScrollView. If 1, the content's right side will\n    touch the right side.\n\n    This property is controled by :class:`ScrollView` only if\n    :attr:`do_scroll_x` is True.\n\n    :attr:`scroll_x` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    scroll_y = NumericProperty(1.)\n    '''Y scrolling value, between 0 and 1. If 0, the content's bottom side will\n    touch the bottom side of the ScrollView. If 1, the content's top side will\n    touch the top side.\n\n    This property is controled by :class:`ScrollView` only if\n    :attr:`do_scroll_y` is True.\n\n    :attr:`scroll_y` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 1.\n    '''\n\n    do_scroll_x = BooleanProperty(True)\n    '''Allow scroll on X axis.\n\n    :attr:`do_scroll_x` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n\n    do_scroll_y = BooleanProperty(True)\n    '''Allow scroll on Y axis.\n\n    :attr:`do_scroll_y` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n\n    def _get_do_scroll(self):\n        return (self.do_scroll_x, self.do_scroll_y)\n\n    def _set_do_scroll(self, value):\n        if type(value) in (list, tuple):\n            self.do_scroll_x, self.do_scroll_y = value\n        else:\n            self.do_scroll_x = self.do_scroll_y = bool(value)\n    do_scroll = AliasProperty(_get_do_scroll, _set_do_scroll,\n                              bind=('do_scroll_x', 'do_scroll_y'))\n    '''Allow scroll on X or Y axis.\n\n    :attr:`do_scroll` is a :class:`~kivy.properties.AliasProperty` of\n    (:attr:`do_scroll_x` + :attr:`do_scroll_y`)\n    '''\n\n    def _get_vbar(self):\n        # must return (y, height) in %\n        # calculate the viewport size / scrollview size %\n        if self._viewport is None:\n            return 0, 1.\n        vh = self._viewport.height\n        h = self.height\n        if vh < h or vh == 0:\n            return 0, 1.\n        ph = max(0.01, h / float(vh))\n        sy = min(1.0, max(0.0, self.scroll_y))\n        py = (1. - ph) * sy\n        return (py, ph)\n\n    vbar = AliasProperty(_get_vbar, None, bind=(\n        'scroll_y', '_viewport', 'viewport_size'))\n    '''Return a tuple of (position, size) of the vertical scrolling bar.\n\n    .. versionadded:: 1.2.0\n\n    The position and size are normalized between 0-1, and represent a\n    percentage of the current scrollview height. This property is used\n    internally for drawing the little vertical bar when you're scrolling.\n\n    :attr:`vbar` is a :class:`~kivy.properties.AliasProperty`, readonly.\n    '''\n\n    def _get_hbar(self):\n        # must return (x, width) in %\n        # calculate the viewport size / scrollview size %\n        if self._viewport is None:\n            return 0, 1.\n        vw = self._viewport.width\n        w = self.width\n        if vw < w or vw == 0:\n            return 0, 1.\n        pw = max(0.01, w / float(vw))\n        sx = min(1.0, max(0.0, self.scroll_x))\n        px = (1. - pw) * sx\n        return (px, pw)\n\n    hbar = AliasProperty(_get_hbar, None, bind=(\n        'scroll_x', '_viewport', 'viewport_size'))\n    '''Return a tuple of (position, size) of the horizontal scrolling bar.\n\n    .. versionadded:: 1.2.0\n\n    The position and size are normalized between 0-1, and represent a\n    percentage of the current scrollview height. This property is used\n    internally for drawing the little horizontal bar when you're scrolling.\n\n    :attr:`vbar` is a :class:`~kivy.properties.AliasProperty`, readonly.\n    '''\n\n    bar_color = ListProperty([.7, .7, .7, .9])\n    '''Color of horizontal / vertical scroll bar, in RGBA format.\n\n    .. versionadded:: 1.2.0\n\n    :attr:`bar_color` is a :class:`~kivy.properties.ListProperty` and defaults\n    to [.7, .7, .7, .9].\n    '''\n\n    bar_inactive_color = ListProperty([.7, .7, .7, .2])\n    '''Color of horizontal / vertical scroll bar (in RGBA format), when no\n    scroll is happening.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`bar_inactive_color` is a\n    :class:`~kivy.properties.ListProperty` and defaults to [.7, .7, .7, .2].\n    '''\n\n    bar_width = NumericProperty('2dp')\n    '''Width of the horizontal / vertical scroll bar. The width is interpreted\n    as a height for the horizontal bar.\n\n    .. versionadded:: 1.2.0\n\n    :attr:`bar_width` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 2.\n    '''\n\n    bar_pos_x = OptionProperty('bottom', options=('top', 'bottom'))\n    '''Which side of the ScrollView the horizontal scroll bar should go\n    on. Possible values are 'top' and 'bottom'.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`bar_pos_x` is an :class:`~kivy.properties.OptionProperty`,\n    defaults to 'bottom'.\n\n    '''\n\n    bar_pos_y = OptionProperty('right', options=('left', 'right'))\n    '''Which side of the ScrollView the vertical scroll bar should go\n    on. Possible values are 'left' and 'right'.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`bar_pos_y` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to 'right'.\n\n    '''\n\n    bar_pos = ReferenceListProperty(bar_pos_x, bar_pos_y)\n    '''Which side of the scroll view to place each of the bars on.\n\n    :attr:`bar_pos` is a :class:`~kivy.properties.ReferenceListProperty` of\n    (:attr:`bar_pos_x`, :attr:`bar_pos_y`)\n    '''\n\n    bar_margin = NumericProperty(0)\n    '''Margin between the bottom / right side of the scrollview when drawing\n    the horizontal / vertical scroll bar.\n\n    .. versionadded:: 1.2.0\n\n    :attr:`bar_margin` is a :class:`~kivy.properties.NumericProperty`, default\n    to 0\n    '''\n\n    effect_cls = ObjectProperty(DampedScrollEffect, allownone=True)\n    '''Class effect to instanciate for X and Y axis.\n\n    .. versionadded:: 1.7.0\n\n    :attr:`effect_cls` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to :class:`DampedScrollEffect`.\n\n    .. versionchanged:: 1.8.0\n        If you set a string, the :class:`~kivy.factory.Factory` will be used to\n        resolve the class.\n\n    '''\n\n    effect_x = ObjectProperty(None, allownone=True)\n    '''Effect to apply for the X axis. If None is set, an instance of\n    :attr:`effect_cls` will be created.\n\n    .. versionadded:: 1.7.0\n\n    :attr:`effect_x` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    effect_y = ObjectProperty(None, allownone=True)\n    '''Effect to apply for the Y axis. If None is set, an instance of\n    :attr:`effect_cls` will be created.\n\n    .. versionadded:: 1.7.0\n\n    :attr:`effect_y` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None, read-only.\n    '''\n\n    viewport_size = ListProperty([0, 0])\n    '''(internal) Size of the internal viewport. This is the size of your only\n    child in the scrollview.\n    '''\n\n    scroll_type = OptionProperty(['content'], options=(['content'], ['bars'],\n                                 ['bars', 'content'], ['content', 'bars']))\n    '''Sets the type of scrolling to use for the content of the scrollview.\n    Available options are: ['content'], ['bars'], ['bars', 'content'].\n\n    .. versionadded:: 1.8.0\n\n    :attr:`scroll_type` is a :class:`~kivy.properties.OptionProperty`, defaults\n    to ['content'].\n    '''\n\n    # private, for internal use only\n\n    _viewport = ObjectProperty(None, allownone=True)\n    _bar_color = ListProperty([0, 0, 0, 0])\n\n    def _set_viewport_size(self, instance, value):\n        self.viewport_size = value\n\n    def on__viewport(self, instance, value):\n        if value:\n            value.bind(size=self._set_viewport_size)\n            self.viewport_size = value.size\n\n    __events__ = ('on_scroll_start', 'on_scroll_move', 'on_scroll_stop')\n\n    def __init__(self, **kwargs):\n        self._touch = None\n        self._trigger_update_from_scroll = Clock.create_trigger(\n            self.update_from_scroll, -1)\n        # create a specific canvas for the viewport\n        from kivy.graphics import PushMatrix, Translate, PopMatrix, Canvas\n        self.canvas_viewport = Canvas()\n        self.canvas = Canvas()\n        with self.canvas_viewport.before:\n            PushMatrix()\n            self.g_translate = Translate(0, 0)\n        with self.canvas_viewport.after:\n            PopMatrix()\n\n        super(ScrollView, self).__init__(**kwargs)\n\n        self.register_event_type('on_scroll_start')\n        self.register_event_type('on_scroll_move')\n        self.register_event_type('on_scroll_stop')\n\n        # now add the viewport canvas to our canvas\n        self.canvas.add(self.canvas_viewport)\n\n        effect_cls = self.effect_cls\n        if isinstance(effect_cls, string_types):\n            effect_cls = Factory.get(effect_cls)\n        if self.effect_x is None and effect_cls is not None:\n            self.effect_x = effect_cls(target_widget=self._viewport)\n        if self.effect_y is None and effect_cls is not None:\n            self.effect_y = effect_cls(target_widget=self._viewport)\n        self.bind(\n            width=self._update_effect_x_bounds,\n            height=self._update_effect_y_bounds,\n            viewport_size=self._update_effect_bounds,\n            _viewport=self._update_effect_widget,\n            scroll_x=self._trigger_update_from_scroll,\n            scroll_y=self._trigger_update_from_scroll,\n            pos=self._trigger_update_from_scroll,\n            size=self._trigger_update_from_scroll)\n\n        self._update_effect_widget()\n        self._update_effect_x_bounds()\n        self._update_effect_y_bounds()\n\n    def on_effect_x(self, instance, value):\n        if value:\n            value.bind(scroll=self._update_effect_x)\n            value.target_widget = self._viewport\n\n    def on_effect_y(self, instance, value):\n        if value:\n            value.bind(scroll=self._update_effect_y)\n            value.target_widget = self._viewport\n\n    def on_effect_cls(self, instance, cls):\n        if isinstance(cls, string_types):\n            cls = Factory.get(cls)\n        self.effect_x = cls(target_widget=self._viewport)\n        self.effect_x.bind(scroll=self._update_effect_x)\n        self.effect_y = cls(target_widget=self._viewport)\n        self.effect_y.bind(scroll=self._update_effect_y)\n\n    def _update_effect_widget(self, *args):\n        if self.effect_x:\n            self.effect_x.target_widget = self._viewport\n        if self.effect_y:\n            self.effect_y.target_widget = self._viewport\n\n    def _update_effect_x_bounds(self, *args):\n        if not self._viewport or not self.effect_x:\n            return\n        self.effect_x.min = -(self.viewport_size[0] - self.width)\n        self.effect_x.max = 0\n        self.effect_x.value = self.effect_x.min * self.scroll_x\n\n    def _update_effect_y_bounds(self, *args):\n        if not self._viewport or not self.effect_y:\n            return\n        self.effect_y.min = -(self.viewport_size[1] - self.height)\n        self.effect_y.max = 0\n        self.effect_y.value = self.effect_y.min * self.scroll_y\n\n    def _update_effect_bounds(self, *args):\n        if not self._viewport:\n            return\n        if self.effect_x:\n            self._update_effect_x_bounds()\n        if self.effect_y:\n            self._update_effect_y_bounds()\n\n    def _update_effect_x(self, *args):\n        vp = self._viewport\n        if not vp or not self.effect_x:\n            return\n        sw = vp.width - self.width\n        if sw < 1:\n            return\n        sx = self.effect_x.scroll / float(sw)\n        self.scroll_x = -sx\n        self._trigger_update_from_scroll()\n\n    def _update_effect_y(self, *args):\n        vp = self._viewport\n        if not vp or not self.effect_y:\n            return\n        sh = vp.height - self.height\n        if sh < 1:\n            return\n        sy = self.effect_y.scroll / float(sh)\n        self.scroll_y = -sy\n        self._trigger_update_from_scroll()\n\n    def to_local(self, x, y, **k):\n        tx, ty = self.g_translate.xy\n        return x - tx, y - ty\n\n    def to_parent(self, x, y, **k):\n        tx, ty = self.g_translate.xy\n        return x + tx, y + ty\n\n    def _apply_transform(self, m):\n        tx, ty = self.g_translate.xy\n        m.translate(tx, ty, 0)\n        return super(ScrollView, self)._apply_transform(m)\n\n    def simulate_touch_down(self, touch):\n        # at this point the touch is in parent coords\n        touch.push()\n        touch.apply_transform_2d(self.to_local)\n        ret = super(ScrollView, self).on_touch_down(touch)\n        touch.pop()\n        return ret\n\n    def on_touch_down(self, touch):\n        if self.dispatch('on_scroll_start', touch):\n            self._touch = touch\n            touch.grab(self)\n            return True\n\n    def on_scroll_start(self, touch, check_children=True):\n        if check_children:\n            touch.push()\n            touch.apply_transform_2d(self.to_local)\n            if self.dispatch_children('on_scroll_start', touch):\n                return True\n            touch.pop()\n\n        if not self.collide_point(*touch.pos):\n            touch.ud[self._get_uid('svavoid')] = True\n            return\n        if self.disabled:\n            return True\n        if self._touch or (not (self.do_scroll_x or self.do_scroll_y)):\n            return self.simulate_touch_down(touch)\n\n        # handle mouse scrolling, only if the viewport size is bigger than the\n        # scrollview size, and if the user allowed to do it\n        vp = self._viewport\n        if not vp:\n            return True\n        scroll_type = self.scroll_type\n        ud = touch.ud\n        scroll_bar = 'bars' in scroll_type\n\n        # check if touch is in bar_x(horizontal) or bay_y(bertical)\n        ud['in_bar_x'] = ud['in_bar_y'] = False\n        width_scrollable = vp.width > self.width\n        height_scrollable = vp.height > self.height\n        bar_pos_x = self.bar_pos_x[0]\n        bar_pos_y = self.bar_pos_y[0]\n\n        d = {'b': True if touch.y < self.y + self.bar_width else False,\n             't': True if touch.y > self.top - self.bar_width else False,\n             'l': True if touch.x < self.x + self.bar_width else False,\n             'r': True if touch.x > self.right - self.bar_width else False}\n        if scroll_bar:\n            if (width_scrollable and d[bar_pos_x]):\n                ud['in_bar_x'] = True\n            if (height_scrollable and d[bar_pos_y]):\n                ud['in_bar_y'] = True\n\n        if vp and 'button' in touch.profile and \\\n                touch.button.startswith('scroll'):\n            btn = touch.button\n            m = sp(self.scroll_wheel_distance)\n            e = None\n\n            if ((btn == 'scrolldown' and self.scroll_y >= 1) or\n                (btn == 'scrollup' and self.scroll_y <= 0) or\n                (btn == 'scrollleft' and self.scroll_x >= 1) or\n                (btn == 'scrollright' and self.scroll_x <= 0)):\n                return False\n\n            if (self.effect_x and self.do_scroll_y and height_scrollable\n                    and btn in ('scrolldown', 'scrollup')):\n                e = self.effect_x if ud['in_bar_x'] else self.effect_y\n\n            elif (self.effect_y and self.do_scroll_x and width_scrollable\n                    and btn in ('scrollleft', 'scrollright')):\n                e = self.effect_y if ud['in_bar_y'] else self.effect_x\n\n            if e:\n                if btn in ('scrolldown', 'scrollleft'):\n                    e.value = max(e.value - m, e.min)\n                    e.velocity = 0\n                elif btn in ('scrollup', 'scrollright'):\n                    e.value = min(e.value + m, e.max)\n                    e.velocity = 0\n                touch.ud[self._get_uid('svavoid')] = True\n                e.trigger_velocity_update()\n            return True\n\n        # no mouse scrolling, so the user is going to drag the scrollview with\n        # this touch.\n        self._touch = touch\n        uid = self._get_uid()\n\n        ud[uid] = {\n            'mode': 'unknown',\n            'dx': 0,\n            'dy': 0,\n            'user_stopped': False,\n            'frames': Clock.frames,\n            'time': touch.time_start}\n\n        if self.do_scroll_x and self.effect_x and not ud['in_bar_x']:\n            self.effect_x.start(touch.x)\n            self._scroll_x_mouse = self.scroll_x\n        if self.do_scroll_y and self.effect_y and not ud['in_bar_y']:\n            self.effect_y.start(touch.y)\n            self._scroll_y_mouse = self.scroll_y\n\n        if (ud.get('in_bar_x', False) or ud.get('in_bar_y', False)):\n            return True\n\n        Clock.schedule_once(self._change_touch_mode,\n                                self.scroll_timeout / 1000.)\n        if scroll_type == ['bars']:\n            return False\n        else:\n            return True\n\n    def on_touch_move(self, touch):\n        if self._touch is not touch:\n            # touch is in parent\n            touch.push()\n            touch.apply_transform_2d(self.to_local)\n            super(ScrollView, self).on_touch_move(touch)\n            touch.pop()\n            return self._get_uid() in touch.ud\n        if touch.grab_current is not self:\n            return True\n\n        if not (self.do_scroll_y or self.do_scroll_x):\n            return super(ScrollView, self).on_touch_move(touch)\n\n        touch.ud['sv.handled'] = {'x': False, 'y': False}\n        if self.dispatch('on_scroll_move', touch):\n            return True\n\n    def on_scroll_move(self, touch):\n        if self._get_uid('svavoid') in touch.ud:\n            return False\n\n        touch.push()\n        touch.apply_transform_2d(self.to_local)\n        if self.dispatch_children('on_scroll_move', touch):\n            return True\n        touch.pop()\n\n        rv = True\n\n        uid = self._get_uid()\n        if not uid in touch.ud:\n            self._touch = False\n            return self.on_scroll_start(touch, False)\n        ud = touch.ud[uid]\n        mode = ud['mode']\n\n        # check if the minimum distance has been travelled\n        if mode == 'unknown' or mode == 'scroll':\n            if not touch.ud['sv.handled']['x'] and self.do_scroll_x \\\n                    and self.effect_x:\n                width = self.width\n                if touch.ud.get('in_bar_x', False):\n                    dx = touch.dx / float(width - width * self.hbar[1])\n                    self.scroll_x = min(max(self.scroll_x + dx, 0.), 1.)\n                    self._trigger_update_from_scroll()\n                else:\n                    if self.scroll_type != ['bars']:\n                        self.effect_x.update(touch.x)\n                if self.scroll_x < 0 or self.scroll_x > 1:\n                    rv = False\n                else:\n                    touch.ud['sv.handled']['x'] = True\n            if not touch.ud['sv.handled']['y'] and self.do_scroll_y \\\n                    and self.effect_y:\n                height = self.height\n                if touch.ud.get('in_bar_y', False):\n                    dy = touch.dy / float(height - height * self.vbar[1])\n                    self.scroll_y = min(max(self.scroll_y + dy, 0.), 1.)\n                    self._trigger_update_from_scroll()\n                else:\n                    if self.scroll_type != ['bars']:\n                        self.effect_y.update(touch.y)\n                if self.scroll_y < 0 or self.scroll_y > 1:\n                    rv = False\n                else:\n                    touch.ud['sv.handled']['y'] = True\n\n        if mode == 'unknown':\n            ud['dx'] += abs(touch.dx)\n            ud['dy'] += abs(touch.dy)\n            if ud['dx'] > self.scroll_distance:\n                if not self.do_scroll_x:\n                    # touch is in parent, but _change expects window coords\n                    touch.push()\n                    touch.apply_transform_2d(self.to_local)\n                    touch.apply_transform_2d(self.to_window)\n                    self._change_touch_mode()\n                    touch.pop()\n                    return\n                mode = 'scroll'\n\n            if ud['dy'] > self.scroll_distance:\n                if not self.do_scroll_y:\n                    # touch is in parent, but _change expects window coords\n                    touch.push()\n                    touch.apply_transform_2d(self.to_local)\n                    touch.apply_transform_2d(self.to_window)\n                    self._change_touch_mode()\n                    touch.pop()\n                    return\n                mode = 'scroll'\n            ud['mode'] = mode\n\n        if mode == 'scroll':\n            ud['dt'] = touch.time_update - ud['time']\n            ud['time'] = touch.time_update\n            ud['user_stopped'] = True\n\n        return rv\n\n    def on_touch_up(self, touch):\n        if self._touch is not touch and self.uid not in touch.ud:\n            # touch is in parents\n            touch.push()\n            touch.apply_transform_2d(self.to_local)\n            if super(ScrollView, self).on_touch_up(touch):\n                return True\n            touch.pop()\n            return False\n\n        if self.dispatch('on_scroll_stop', touch):\n            touch.ungrab(self)\n            return True\n\n    def on_scroll_stop(self, touch, check_children=True):\n        self._touch = None\n\n        if check_children:\n            touch.push()\n            touch.apply_transform_2d(self.to_local)\n            if self.dispatch_children('on_scroll_stop', touch):\n                return True\n            touch.pop()\n\n        if self._get_uid('svavoid') in touch.ud:\n            return\n        if self._get_uid() not in touch.ud:\n            return False\n\n        self._touch = None\n        uid = self._get_uid()\n        ud = touch.ud[uid]\n        if self.do_scroll_x and self.effect_x:\n            if not touch.ud.get('in_bar_x', False) and\\\n                    self.scroll_type != ['bars']:\n                self.effect_x.stop(touch.x)\n        if self.do_scroll_y and self.effect_y and\\\n                self.scroll_type != ['bars']:\n            if not touch.ud.get('in_bar_y', False):\n                self.effect_y.stop(touch.y)\n        if ud['mode'] == 'unknown':\n            # we must do the click at least..\n            # only send the click if it was not a click to stop\n            # autoscrolling\n            if not ud['user_stopped']:\n                self.simulate_touch_down(touch)\n            Clock.schedule_once(partial(self._do_touch_up, touch), .2)\n        Clock.unschedule(self._update_effect_bounds)\n        Clock.schedule_once(self._update_effect_bounds)\n\n        # if we do mouse scrolling, always accept it\n        if 'button' in touch.profile and touch.button.startswith('scroll'):\n            return True\n\n        return self._get_uid() in touch.ud\n\n    def convert_distance_to_scroll(self, dx, dy):\n        '''Convert a distance in pixels to a scroll distance, depending on the\n        content size and the scrollview size.\n\n        The result will be a tuple of scroll distance that can be added to\n        :data:`scroll_x` and :data:`scroll_y`\n        '''\n        if not self._viewport:\n            return 0, 0\n        vp = self._viewport\n        if vp.width > self.width:\n            sw = vp.width - self.width\n            sx = dx / float(sw)\n        else:\n            sx = 0\n        if vp.height > self.height:\n            sh = vp.height - self.height\n            sy = dy / float(sh)\n        else:\n            sy = 1\n        return sx, sy\n\n    def update_from_scroll(self, *largs):\n        '''Force the reposition of the content, according to current value of\n        :attr:`scroll_x` and :attr:`scroll_y`.\n\n        This method is automatically called when one of the :attr:`scroll_x`,\n        :attr:`scroll_y`, :attr:`pos` or :attr:`size` properties change, or\n        if the size of the content changes.\n        '''\n        if not self._viewport:\n            return\n        vp = self._viewport\n\n        # update from size_hint\n        if vp.size_hint_x is not None:\n            vp.width = vp.size_hint_x * self.width\n        if vp.size_hint_y is not None:\n            vp.height = vp.size_hint_y * self.height\n\n        if vp.width > self.width:\n            sw = vp.width - self.width\n            x = self.x - self.scroll_x * sw\n        else:\n            x = self.x\n        if vp.height > self.height:\n            sh = vp.height - self.height\n            y = self.y - self.scroll_y * sh\n        else:\n            y = self.top - vp.height\n\n        # from 1.8.0, we now use a matrix by default, instead of moving the\n        # widget position behind. We set it here, but it will be a no-op most of\n        # the time.\n        vp.pos = 0, 0\n        self.g_translate.xy = x, y\n\n        # New in 1.2.0, show bar when scrolling happens and (changed in 1.9.0)\n        # fade to bar_inactive_color when no scroll is happening.\n        Clock.unschedule(self._bind_inactive_bar_color)\n        self.unbind(bar_inactive_color=self._change_bar_color)\n        Animation.stop_all(self, '_bar_color')\n        self.bind(bar_color=self._change_bar_color)\n        self._bar_color = self.bar_color\n        Clock.schedule_once(self._bind_inactive_bar_color, .5)\n\n    def _bind_inactive_bar_color(self, *l):\n        self.unbind(bar_color=self._change_bar_color)\n        self.bind(bar_inactive_color=self._change_bar_color)\n        Animation(\n            _bar_color=self.bar_inactive_color, d=.5, t='out_quart').start(self)\n\n    def _change_bar_color(self, inst, value):\n        self._bar_color = value\n\n    #\n    # Private\n    #\n    def add_widget(self, widget, index=0):\n        if self._viewport:\n            raise Exception('ScrollView accept only one widget')\n        canvas = self.canvas\n        self.canvas = self.canvas_viewport\n        super(ScrollView, self).add_widget(widget, index)\n        self.canvas = canvas\n        self._viewport = widget\n        widget.bind(size=self._trigger_update_from_scroll)\n        self._trigger_update_from_scroll()\n\n    def remove_widget(self, widget):\n        canvas = self.canvas\n        self.canvas = self.canvas_viewport\n        super(ScrollView, self).remove_widget(widget)\n        self.canvas = canvas\n        if widget is self._viewport:\n            self._viewport = None\n\n    def _get_uid(self, prefix='sv'):\n        return '{0}.{1}'.format(prefix, self.uid)\n\n    def _change_touch_mode(self, *largs):\n        if not self._touch:\n            return\n        uid = self._get_uid()\n        touch = self._touch\n        if uid not in touch.ud:\n            self._touch = False\n            return\n        ud = touch.ud[uid]\n        if ud['mode'] != 'unknown' or ud['user_stopped']:\n            return\n        diff_frames = Clock.frames - ud['frames']\n\n        # in order to be able to scroll on very slow devices, let at least 3\n        # frames displayed to accumulate some velocity. And then, change the\n        # touch mode. Otherwise, we might never be able to compute velocity, and\n        # no way to scroll it. See #1464 and #1499\n        if diff_frames < 3:\n            Clock.schedule_once(self._change_touch_mode, 0)\n            return\n\n        if self.do_scroll_x and self.effect_x:\n            self.effect_x.cancel()\n        if self.do_scroll_y and self.effect_y:\n            self.effect_y.cancel()\n        # XXX the next line was in the condition. But this stop\n        # the possibily to \"drag\" an object out of the scrollview in the\n        # non-used direction: if you have an horizontal scrollview, a\n        # vertical gesture will not \"stop\" the scroll view to look for an\n        # horizontal gesture, until the timeout is done.\n        # and touch.dx + touch.dy == 0:\n        touch.ungrab(self)\n        self._touch = None\n        # touch is in window coords\n        touch.push()\n        touch.apply_transform_2d(self.to_widget)\n        touch.apply_transform_2d(self.to_parent)\n        self.simulate_touch_down(touch)\n        touch.pop()\n        return\n\n    def _do_touch_up(self, touch, *largs):\n        # touch is in window coords\n        touch.push()\n        touch.apply_transform_2d(self.to_widget)\n        super(ScrollView, self).on_touch_up(touch)\n        touch.pop()\n        # don't forget about grab event!\n        for x in touch.grab_list[:]:\n            touch.grab_list.remove(x)\n            x = x()\n            if not x:\n                continue\n            touch.grab_current = x\n            # touch is in window coords\n            touch.push()\n            touch.apply_transform_2d(self.to_widget)\n            super(ScrollView, self).on_touch_up(touch)\n            touch.pop()\n        touch.grab_current = None\n\n\nif __name__ == '__main__':\n    from kivy.app import App\n\n    from kivy.uix.gridlayout import GridLayout\n    from kivy.uix.button import Button\n\n    class ScrollViewApp(App):\n\n        def build(self):\n            layout1 = GridLayout(cols=4, spacing=10, size_hint=(None, None))\n            layout1.bind(minimum_height=layout1.setter('height'),\n                         minimum_width=layout1.setter('width'))\n            for i in range(40):\n                btn = Button(text=str(i), size_hint=(None, None),\n                             size=(200, 100))\n                layout1.add_widget(btn)\n            scrollview1 = ScrollView(bar_width='2dp')\n            scrollview1.add_widget(layout1)\n\n            layout2 = GridLayout(cols=4, spacing=10, size_hint=(None, None))\n            layout2.bind(minimum_height=layout2.setter('height'),\n                         minimum_width=layout2.setter('width'))\n            for i in range(40):\n                btn = Button(text=str(i), size_hint=(None, None),\n                             size=(200, 100))\n                layout2.add_widget(btn)\n            scrollview2 = ScrollView(scroll_type=['bars'],\n                                     bar_width='9dp',\n                                     scroll_wheel_distance=100)\n            scrollview2.add_widget(layout2)\n\n            root = GridLayout(cols=2)\n            root.add_widget(scrollview1)\n            root.add_widget(scrollview2)\n            return root\n\n    ScrollViewApp().run()\n"
  },
  {
    "path": "tickeys/kivy/uix/selectableview.py",
    "content": "from kivy.properties import NumericProperty, BooleanProperty\n\n\nclass SelectableView(object):\n    '''The :class:`SelectableView` mixin is used with list items and other\n    classes that are to be instantiated in a list view or other classes\n    which use a selection-enabled adapter such as ListAdapter. select() and\n    deselect() can be overridden with display code to mark items as\n    selected or not, if desired.\n    '''\n\n    index = NumericProperty(-1)\n    '''The index into the underlying data list or the data item this view\n    represents.\n    '''\n\n    is_selected = BooleanProperty(False)\n    '''A SelectableView instance carries this property which should be kept\n    in sync with the equivalent property the data item represents.\n    '''\n\n    def __init__(self, **kwargs):\n        super(SelectableView, self).__init__(**kwargs)\n\n    def select(self, *args):\n        '''The list item is responsible for updating the display when\n        being selected, if desired.\n        '''\n        self.is_selected = True\n\n    def deselect(self, *args):\n        '''The list item is responsible for updating the display when\n        being unselected, if desired.\n        '''\n        self.is_selected = False\n"
  },
  {
    "path": "tickeys/kivy/uix/settings.py",
    "content": "'''\nSettings\n========\n\n.. versionadded:: 1.0.7\n\nThis module is a complete and extensible framework for adding a\nSettings interface to your application. By default, the interface uses\na :class:`SettingsWithSpinner`, which consists of a\n:class:`~kivy.uix.spinner.Spinner` (top) to switch between individual\nsettings panels (bottom). See :ref:`differentlayouts` for some\nalternatives.\n\n.. image:: images/settingswithspinner_kivy.jpg\n    :align: center\n\nA :class:`SettingsPanel` represents a group of configurable options. The\n:attr:`SettingsPanel.title` property is used by :class:`Settings` when a panel\nis added - it determines the name of the sidebar button. SettingsPanel controls\na :class:`~kivy.config.ConfigParser` instance.\n\nThe panel can be automatically constructed from a JSON definition file: you\ndescribe the settings you want and corresponding sections/keys in the\nConfigParser instance... and you're done!\n\nSettings are also integrated with the :class:`~kivy.app.App` class. Use\n:meth:`Settings.add_kivy_panel` to configure the Kivy core settings in a panel.\n\n\n.. _settings_json:\n\nCreate a panel from JSON\n------------------------\n\nTo create a panel from a JSON-file, you need two things:\n\n    * a :class:`~kivy.config.ConfigParser` instance with default values\n    * a JSON file\n\n.. warning::\n\n    The :class:`kivy.config.ConfigParser` is required. You cannot use the\n    default ConfigParser from Python libraries.\n\nYou must create and handle the :class:`~kivy.config.ConfigParser`\nobject. SettingsPanel will read the values from the associated\nConfigParser instance. Make sure you have default values for all sections/keys\nin your JSON file!\n\nThe JSON file contains structured information to describe the available\nsettings. Here is an example::\n\n    [\n        {\n            \"type\": \"title\",\n            \"title\": \"Windows\"\n        },\n        {\n            \"type\": \"bool\",\n            \"title\": \"Fullscreen\",\n            \"desc\": \"Set the window in windowed or fullscreen\",\n            \"section\": \"graphics\",\n            \"key\": \"fullscreen\",\n            \"true\": \"auto\"\n        }\n    ]\n\nEach element in the root list represents a setting that the user can configure.\nOnly the \"type\" key is mandatory: an instance of the associated class will be\ncreated and used for the setting - other keys are assigned to corresponding\nproperties of that class.\n\n    ============== =================================================\n     Type           Associated class\n    -------------- -------------------------------------------------\n    title          :class:`SettingTitle`\n    bool           :class:`SettingBoolean`\n    numeric        :class:`SettingNumeric`\n    options        :class:`SettingOptions`\n    string         :class:`SettingString`\n    path           :class:`SettingPath` (new from 1.1.0)\n    ============== =================================================\n\nIn the JSON example above, the first element is of type \"title\". It will create\na new instance of :class:`SettingTitle` and apply the rest of the key/value\npairs to the properties of that class, i.e. \"title\": \"Windows\" sets the\n:attr:`SettingTitle.title` property to \"Windows\".\n\nTo load the JSON example to a :class:`Settings` instance, use the\n:meth:`Settings.add_json_panel` method. It will automatically instantiate a\n:class:`SettingsPanel` and add it to :class:`Settings`::\n\n    from kivy.config import ConfigParser\n\n    config = ConfigParser()\n    config.read('myconfig.ini')\n\n    s = Settings()\n    s.add_json_panel('My custom panel', config, 'settings_custom.json')\n    s.add_json_panel('Another panel', config, 'settings_test2.json')\n\n    # then use the s as a widget...\n\n\n.. _differentlayouts:\n\nDifferent panel layouts\n-----------------------\n\nA kivy :class:`~kivy.app.App` can automatically create and display a\n:class:`Settings` instance. See the :attr:`~kivy.app.App.settings_cls`\ndocumentation for details on how to choose which settings class to\ndisplay.\n\nSeveral pre-built settings widgets are available. All except\n:class:`SettingsWithNoMenu` include close buttons triggering the\non_close event.\n\n- :class:`Settings`: Displays settings with a sidebar at the left to\n  switch between json panels.\n\n- :class:`SettingsWithSidebar`: A trivial subclass of\n  :class:`Settings`.\n\n- :class:`SettingsWithSpinner`: Displays settings with a spinner at\n  the top, which can be used to switch between json panels. Uses\n  :class:`InterfaceWithSpinner` as the\n  :attr:`~Settings.interface_cls`. This is the default behavior from\n  Kivy 1.8.0.\n\n- :class:`SettingsWithTabbedPanel`: Displays json panels as individual\n  tabs in a :class:`~kivy.uix.tabbedpanel.TabbedPanel`. Uses\n  :class:`InterfaceWithTabbedPanel` as the :attr:`~Settings.interface_cls`.\n\n- :class:`SettingsWithNoMenu`: Displays a single json panel, with no\n  way to switch to other panels and no close button. This makes it\n  impossible for the user to exit unless\n  :meth:`~kivy.app.App.close_settings` is overridden with a different\n  close trigger! Uses :class:`InterfaceWithNoMenu` as the\n  :attr:`~Settings.interface_cls`.\n\nYou can construct your own settings panels with any layout you choose\nby setting :attr:`Settings.interface_cls`. This should be a widget\nthat displays a json settings panel with some way to switch between\npanels. An instance will be automatically created by :class:`Settings`.\n\nInterface widgets may be anything you like, but *must* have a method\nadd_panel that recieves newly created json settings panels for the\ninterface to display. See the documentation for\n:class:`InterfaceWithSidebar` for more information. They may\noptionally dispatch an on_close event, for instance if a close button\nis clicked. This event is used by :class:`Settings` to trigger its own\non_close event.\n\n'''\n\n__all__ = ('Settings', 'SettingsPanel', 'SettingItem', 'SettingString',\n           'SettingPath', 'SettingBoolean', 'SettingNumeric', 'SettingOptions',\n           'SettingTitle', 'SettingsWithSidebar', 'SettingsWithSpinner',\n           'SettingsWithTabbedPanel', 'SettingsWithNoMenu',\n           'InterfaceWithSidebar', 'ContentPanel')\n\nimport json\nimport os\nfrom kivy.compat import string_types\nfrom kivy.factory import Factory\nfrom kivy.metrics import dp\nfrom kivy.config import ConfigParser\nfrom kivy.animation import Animation\nfrom kivy.compat import string_types, text_type\nfrom kivy.core.window import Window\nfrom kivy.uix.boxlayout import BoxLayout\nfrom kivy.uix.tabbedpanel import TabbedPanelHeader\nfrom kivy.uix.button import Button\nfrom kivy.uix.filechooser import FileChooserListView\nfrom kivy.uix.scrollview import ScrollView\nfrom kivy.uix.floatlayout import FloatLayout\nfrom kivy.uix.gridlayout import GridLayout\nfrom kivy.uix.label import Label\nfrom kivy.uix.popup import Popup\nfrom kivy.uix.textinput import TextInput\nfrom kivy.uix.togglebutton import ToggleButton\nfrom kivy.uix.widget import Widget\nfrom kivy.properties import ObjectProperty, StringProperty, ListProperty, \\\n    BooleanProperty, NumericProperty, DictProperty\n\n\nclass SettingSpacer(Widget):\n    # Internal class, not documented.\n    pass\n\n\nclass SettingItem(FloatLayout):\n    '''Base class for individual settings (within a panel). This class cannot\n    be used directly; it is used for implementing the other setting classes.\n    It builds a row with a title/description (left) and a setting control\n    (right).\n\n    Look at :class:`SettingBoolean`, :class:`SettingNumeric` and\n    :class:`SettingOptions` for usage examples.\n\n    :Events:\n        `on_release`\n            Fired when the item is touched and then released.\n\n    '''\n\n    title = StringProperty('<No title set>')\n    '''Title of the setting, defaults to '<No title set>'.\n\n    :attr:`title` is a :class:`~kivy.properties.StringProperty` and defaults to\n    '<No title set>'.\n    '''\n\n    desc = StringProperty(None, allownone=True)\n    '''Description of the setting, rendered on the line below the title.\n\n    :attr:`desc` is a :class:`~kivy.properties.StringProperty` and defaults to\n    None.\n    '''\n\n    disabled = BooleanProperty(False)\n    '''Indicate if this setting is disabled. If True, all touches on the\n    setting item will be discarded.\n\n    :attr:`disabled` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    section = StringProperty(None)\n    '''Section of the token inside the :class:`~kivy.config.ConfigParser`\n    instance.\n\n    :attr:`section` is a :class:`~kivy.properties.StringProperty` and defaults\n    to None.\n    '''\n\n    key = StringProperty(None)\n    '''Key of the token inside the :attr:`section` in the\n    :class:`~kivy.config.ConfigParser` instance.\n\n    :attr:`key` is a :class:`~kivy.properties.StringProperty` and defaults to\n    None.\n    '''\n\n    value = ObjectProperty(None)\n    '''Value of the token according to the :class:`~kivy.config.ConfigParser`\n    instance. Any change to this value will trigger a\n    :meth:`Settings.on_config_change` event.\n\n    :attr:`value` is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    panel = ObjectProperty(None)\n    '''(internal) Reference to the SettingsPanel for this setting. You don't\n    need to use it.\n\n    :attr:`panel` is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    content = ObjectProperty(None)\n    '''(internal) Reference to the widget that contains the real setting.\n    As soon as the content object is set, any further call to add_widget will\n    call the content.add_widget. This is automatically set.\n\n    :attr:`content` is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    selected_alpha = NumericProperty(0)\n    '''(internal) Float value from 0 to 1, used to animate the background when\n    the user touches the item.\n\n    :attr:`selected_alpha` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    __events__ = ('on_release', )\n\n    def __init__(self, **kwargs):\n        super(SettingItem, self).__init__(**kwargs)\n        self.value = self.panel.get_value(self.section, self.key)\n\n    def add_widget(self, *largs):\n        if self.content is None:\n            return super(SettingItem, self).add_widget(*largs)\n        return self.content.add_widget(*largs)\n\n    def on_touch_down(self, touch):\n        if not self.collide_point(*touch.pos):\n            return\n        if self.disabled:\n            return\n        touch.grab(self)\n        self.selected_alpha = 1\n        return super(SettingItem, self).on_touch_down(touch)\n\n    def on_touch_up(self, touch):\n        if touch.grab_current is self:\n            touch.ungrab(self)\n            self.dispatch('on_release')\n            Animation(selected_alpha=0, d=.25, t='out_quad').start(self)\n            return True\n        return super(SettingItem, self).on_touch_up(touch)\n\n    def on_release(self):\n        pass\n\n    def on_value(self, instance, value):\n        if not self.section or not self.key:\n            return\n        # get current value in config\n        panel = self.panel\n        if not isinstance(value, string_types):\n            value = str(value)\n        panel.set_value(self.section, self.key, value)\n\n\nclass SettingBoolean(SettingItem):\n    '''Implementation of a boolean setting on top of a :class:`SettingItem`. It\n    is visualized with a :class:`~kivy.uix.switch.Switch` widget. By default,\n    0 and 1 are used for values: you can change them by setting :attr:`values`.\n    '''\n\n    values = ListProperty(['0', '1'])\n    '''Values used to represent the state of the setting. If you want to use\n    \"yes\" and \"no\" in your ConfigParser instance::\n\n        SettingBoolean(..., values=['no', 'yes'])\n\n    .. warning::\n\n        You need a minimum of two values, the index 0 will be used as False,\n        and index 1 as True\n\n    :attr:`values` is a :class:`~kivy.properties.ListProperty` and defaults to\n    ['0', '1']\n    '''\n\n\nclass SettingString(SettingItem):\n    '''Implementation of a string setting on top of a :class:`SettingItem`.\n    It is visualized with a :class:`~kivy.uix.label.Label` widget that, when\n    clicked, will open a :class:`~kivy.uix.popup.Popup` with a\n    :class:`~kivy.uix.textinput.Textinput` so the user can enter a custom\n    value.\n    '''\n\n    popup = ObjectProperty(None, allownone=True)\n    '''(internal) Used to store the current popup when it's shown.\n\n    :attr:`popup` is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    textinput = ObjectProperty(None)\n    '''(internal) Used to store the current textinput from the popup and\n    to listen for changes.\n\n    :attr:`textinput` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    def on_panel(self, instance, value):\n        if value is None:\n            return\n        self.bind(on_release=self._create_popup)\n\n    def _dismiss(self, *largs):\n        if self.textinput:\n            self.textinput.focus = False\n        if self.popup:\n            self.popup.dismiss()\n        self.popup = None\n\n    def _validate(self, instance):\n        self._dismiss()\n        value = self.textinput.text.strip()\n        self.value = value\n\n    def _create_popup(self, instance):\n        # create popup layout\n        content = BoxLayout(orientation='vertical', spacing='5dp')\n        popup_width = min(0.95 * Window.width, dp(500))\n        self.popup = popup = Popup(\n            title=self.title, content=content, size_hint=(None, None),\n            size=(popup_width, '250dp'))\n\n        # create the textinput used for numeric input\n        self.textinput = textinput = TextInput(\n            text=self.value, font_size='24sp', multiline=False,\n            size_hint_y=None, height='42sp')\n        textinput.bind(on_text_validate=self._validate)\n        self.textinput = textinput\n\n        # construct the content, widget are used as a spacer\n        content.add_widget(Widget())\n        content.add_widget(textinput)\n        content.add_widget(Widget())\n        content.add_widget(SettingSpacer())\n\n        # 2 buttons are created for accept or cancel the current value\n        btnlayout = BoxLayout(size_hint_y=None, height='50dp', spacing='5dp')\n        btn = Button(text='Ok')\n        btn.bind(on_release=self._validate)\n        btnlayout.add_widget(btn)\n        btn = Button(text='Cancel')\n        btn.bind(on_release=self._dismiss)\n        btnlayout.add_widget(btn)\n        content.add_widget(btnlayout)\n\n        # all done, open the popup !\n        popup.open()\n\n\nclass SettingPath(SettingItem):\n    '''Implementation of a Path setting on top of a :class:`SettingItem`.\n    It is visualized with a :class:`~kivy.uix.label.Label` widget that, when\n    clicked, will open a :class:`~kivy.uix.popup.Popup` with a\n    :class:`~kivy.uix.filechooser.FileChooserListView` so the user can enter\n    a custom value.\n\n    .. versionadded:: 1.1.0\n    '''\n\n    popup = ObjectProperty(None, allownone=True)\n    '''(internal) Used to store the current popup when it is shown.\n\n    :attr:`popup` is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    textinput = ObjectProperty(None)\n    '''(internal) Used to store the current textinput from the popup and\n    to listen for changes.\n\n    :attr:`textinput` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    def on_panel(self, instance, value):\n        if value is None:\n            return\n        self.bind(on_release=self._create_popup)\n\n    def _dismiss(self, *largs):\n        if self.textinput:\n            self.textinput.focus = False\n        if self.popup:\n            self.popup.dismiss()\n        self.popup = None\n\n    def _validate(self, instance):\n        self._dismiss()\n        value = self.textinput.selection\n\n        if not value:\n            return\n\n        self.value = os.path.realpath(value[0])\n\n    def _create_popup(self, instance):\n        # create popup layout\n        content = BoxLayout(orientation='vertical', spacing=5)\n        popup_width = min(0.95 * Window.width, dp(500))\n        self.popup = popup = Popup(\n            title=self.title, content=content, size_hint=(None, 0.9),\n            width=popup_width)\n\n        # create the filechooser\n        self.textinput = textinput = FileChooserListView(\n            path=self.value, size_hint=(1, 1), dirselect=True)\n        textinput.bind(on_path=self._validate)\n        self.textinput = textinput\n\n        # construct the content\n        content.add_widget(textinput)\n        content.add_widget(SettingSpacer())\n\n        # 2 buttons are created for accept or cancel the current value\n        btnlayout = BoxLayout(size_hint_y=None, height='50dp', spacing='5dp')\n        btn = Button(text='Ok')\n        btn.bind(on_release=self._validate)\n        btnlayout.add_widget(btn)\n        btn = Button(text='Cancel')\n        btn.bind(on_release=self._dismiss)\n        btnlayout.add_widget(btn)\n        content.add_widget(btnlayout)\n\n        # all done, open the popup !\n        popup.open()\n\n\nclass SettingNumeric(SettingString):\n    '''Implementation of a numeric setting on top of a :class:`SettingString`.\n    It is visualized with a :class:`~kivy.uix.label.Label` widget that, when\n    clicked, will open a :class:`~kivy.uix.popup.Popup` with a\n    :class:`~kivy.uix.textinput.Textinput` so the user can enter a custom\n    value.\n    '''\n\n    def _validate(self, instance):\n        # we know the type just by checking if there is a '.' in the original\n        # value\n        is_float = '.' in str(self.value)\n        self._dismiss()\n        try:\n            if is_float:\n                self.value = text_type(float(self.textinput.text))\n            else:\n                self.value = text_type(int(self.textinput.text))\n        except ValueError:\n            return\n\n\nclass SettingOptions(SettingItem):\n    '''Implementation of an option list on top of a :class:`SettingItem`.\n    It is visualized with a :class:`~kivy.uix.label.Label` widget that, when\n    clicked, will open a :class:`~kivy.uix.popup.Popup` with a\n    list of options from which the user can select.\n    '''\n\n    options = ListProperty([])\n    '''List of all availables options. This must be a list of \"string\" items.\n    Otherwise, it will crash. :)\n\n    :attr:`options` is a :class:`~kivy.properties.ListProperty` and defaults\n    to [].\n    '''\n\n    popup = ObjectProperty(None, allownone=True)\n    '''(internal) Used to store the current popup when it is shown.\n\n    :attr:`popup` is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    def on_panel(self, instance, value):\n        if value is None:\n            return\n        self.bind(on_release=self._create_popup)\n\n    def _set_option(self, instance):\n        self.value = instance.text\n        self.popup.dismiss()\n\n    def _create_popup(self, instance):\n        # create the popup\n        content = BoxLayout(orientation='vertical', spacing='5dp')\n        popup_width = min(0.95 * Window.width, dp(500))\n        self.popup = popup = Popup(\n            content=content, title=self.title, size_hint=(None, None),\n            size=(popup_width, '400dp'))\n        popup.height = len(self.options) * dp(55) + dp(150)\n\n        # add all the options\n        content.add_widget(Widget(size_hint_y=None, height=1))\n        uid = str(self.uid)\n        for option in self.options:\n            state = 'down' if option == self.value else 'normal'\n            btn = ToggleButton(text=option, state=state, group=uid)\n            btn.bind(on_release=self._set_option)\n            content.add_widget(btn)\n\n        # finally, add a cancel button to return on the previous panel\n        content.add_widget(SettingSpacer())\n        btn = Button(text='Cancel', size_hint_y=None, height=dp(50))\n        btn.bind(on_release=popup.dismiss)\n        content.add_widget(btn)\n\n        # and open the popup !\n        popup.open()\n\n\nclass SettingTitle(Label):\n    '''A simple title label, used to organize the settings in sections.\n    '''\n\n    title = Label.text\n\n\nclass SettingsPanel(GridLayout):\n    '''This class is used to contruct panel settings, for use with a\n    :class:`Settings` instance or subclass.\n    '''\n\n    title = StringProperty('Default title')\n    '''Title of the panel. The title will be reused by the :class:`Settings` in\n    the sidebar.\n    '''\n\n    config = ObjectProperty(None, allownone=True)\n    '''A :class:`kivy.config.ConfigParser` instance. See module documentation\n    for more information.\n    '''\n\n    settings = ObjectProperty(None)\n    '''A :class:`Settings` instance that will be used to fire the\n    `on_config_change` event.\n    '''\n\n    def __init__(self, **kwargs):\n        kwargs.setdefault('cols', 1)\n        super(SettingsPanel, self).__init__(**kwargs)\n\n    def on_config(self, instance, value):\n        if value is None:\n            return\n        if not isinstance(value, ConfigParser):\n            raise Exception('Invalid config object, you must use a'\n                            'kivy.config.ConfigParser, not another one !')\n\n    def get_value(self, section, key):\n        '''Return the value of the section/key from the :attr:`config`\n        ConfigParser instance. This function is used by :class:`SettingItem` to\n        get the value for a given section/key.\n\n        If you don't want to use a ConfigParser instance, you might want to\n        override this function.\n        '''\n        config = self.config\n        if not config:\n            return\n        return config.get(section, key)\n\n    def set_value(self, section, key, value):\n        current = self.get_value(section, key)\n        if current == value:\n            return\n        config = self.config\n        if config:\n            config.set(section, key, value)\n            config.write()\n        settings = self.settings\n        if settings:\n            settings.dispatch('on_config_change',\n                              config, section, key, value)\n\n\nclass InterfaceWithSidebar(BoxLayout):\n    '''The default Settings interface class. It displays a sidebar menu\n    with names of available settings panels, which may be used to switch\n    which one is currently displayed.\n\n    See :meth:`~InterfaceWithSidebar.add_panel` for information on the\n    method you must implement if creating your own interface.\n\n    This class also dispatches an event 'on_close', which is triggered\n    when the sidebar menu's close button is released. If creating your\n    own interface widget, it should also dispatch such an event which\n    will automatically be caught by :class:`Settings` and used to\n    trigger its own 'on_close' event.\n\n    '''\n\n    menu = ObjectProperty()\n    '''(internal) A reference to the sidebar menu widget.\n\n    :attr:`menu` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    content = ObjectProperty()\n    '''(internal) A reference to the panel display widget (a\n    :class:`ContentPanel`).\n\n    :attr:`content` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n\n    '''\n\n    __events__ = ('on_close', )\n\n    def __init__(self, *args, **kwargs):\n        super(InterfaceWithSidebar, self).__init__(*args, **kwargs)\n        self.menu.close_button.bind(\n            on_release=lambda j: self.dispatch('on_close'))\n\n    def add_panel(self, panel, name, uid):\n        '''This method is used by Settings to add new panels for possible\n        display. Any replacement for ContentPanel *must* implement\n        this method.\n\n        :param panel: A :class:`SettingsPanel`. It should be stored\n                      and the interface should provide a way to switch\n                      between panels.\n\n        :param name: The name of the panel as a string. It\n                     may be used to represent the panel but isn't necessarily\n                     unique.\n\n        :param uid: A unique int identifying the panel. It should be\n                    used to identify and switch between panels.\n        '''\n        self.menu.add_item(name, uid)\n        self.content.add_panel(panel, name, uid)\n\n    def on_close(self, *args):\n        pass\n\n\nclass InterfaceWithSpinner(BoxLayout):\n    '''A settings interface that displays a spinner at the top for\n    switching between panels.\n\n    The workings of this class are considered internal and are not\n    documented. See :meth:`InterfaceWithSidebar` for\n    information on implementing your own interface class.\n\n    '''\n\n    __events__ = ('on_close', )\n\n    menu = ObjectProperty()\n    '''(internal) A reference to the sidebar menu widget.\n\n    :attr:`menu` is an :class:`~kivy.properties.ObjectProperty` and\n    defauls to None.\n    '''\n\n    content = ObjectProperty()\n    '''(internal) A reference to the panel display widget (a\n    :class:`ContentPanel`).\n\n    :attr:`menu` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n\n    '''\n\n    def __init__(self, *args, **kwargs):\n        super(InterfaceWithSpinner, self).__init__(*args, **kwargs)\n        self.menu.close_button.bind(\n            on_release=lambda j: self.dispatch('on_close'))\n\n    def add_panel(self, panel, name, uid):\n        '''This method is used by Settings to add new panels for possible\n        display. Any replacement for ContentPanel *must* implement\n        this method.\n\n        :param panel: A :class:`SettingsPanel`. It should be stored\n                      and the interface should provide a way to switch\n                      between panels.\n\n        :param name: The name of the panel as a string. It\n                     may be used to represent the panel but may not\n                     be unique.\n\n        :param uid: A unique int identifying the panel. It should be\n                    used to identify and switch between panels.\n\n        '''\n        self.content.add_panel(panel, name, uid)\n        self.menu.add_item(name, uid)\n\n    def on_close(self, *args):\n        pass\n\n\nclass ContentPanel(ScrollView):\n    '''A class for displaying settings panels. It displays a single\n    settings panel at a time, taking up the full size and shape of the\n    ContentPanel. It is used by :class:`InterfaceWithSidebar` and\n    :class:`InterfaceWithSpinner` to display settings.\n\n    '''\n\n    panels = DictProperty({})\n    '''(internal) Stores a dictionary mapping settings panels to their uids.\n\n    :attr:`panels` is a :class:`~kivy.properties.DictProperty` and\n    defaults to {}.\n\n    '''\n\n    container = ObjectProperty()\n    '''(internal) A reference to the GridLayout that contains the\n    settings panel.\n\n    :attr:`container` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n\n    '''\n\n    current_panel = ObjectProperty(None)\n    '''(internal) A reference to the current settings panel.\n\n    :attr:`current_panel` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n\n    '''\n\n    current_uid = NumericProperty(0)\n    '''(internal) A reference to the uid of the current settings panel.\n\n    :attr:`current_uid` is a\n    :class:`~kivy.properties.NumericProperty` and defaults to 0.\n\n    '''\n\n    def add_panel(self, panel, name, uid):\n        '''This method is used by Settings to add new panels for possible\n        display. Any replacement for ContentPanel *must* implement\n        this method.\n\n        :param panel: A :class:`SettingsPanel`. It should be stored\n                      and displayed when requested.\n\n        :param name: The name of the panel as a string. It\n                     may be used to represent the panel.\n\n        :param uid: A unique int identifying the panel. It should be\n                    stored and used to identify panels when switching.\n\n        '''\n        self.panels[uid] = panel\n        if not self.current_uid:\n            self.current_uid = uid\n\n    def on_current_uid(self, *args):\n        '''The uid of the currently displayed panel. Changing this will\n        automatically change the displayed panel.\n\n        :param uid: A panel uid. It should be used to retrieve and\n                    display a settings panel that has previously been\n                    added with :meth:`add_panel`.\n        '''\n        uid = self.current_uid\n        if uid in self.panels:\n            if self.current_panel is not None:\n                self.remove_widget(self.current_panel)\n            new_panel = self.panels[uid]\n            self.add_widget(new_panel)\n            self.current_panel = new_panel\n            return True\n        return False  # New uid doesn't exist\n\n    def add_widget(self, widget):\n        if self.container is None:\n            super(ContentPanel, self).add_widget(widget)\n        else:\n            self.container.add_widget(widget)\n\n    def remove_widget(self, widget):\n        self.container.remove_widget(widget)\n\n\nclass Settings(BoxLayout):\n\n    '''Settings UI. Check module documentation for more information on how\n    to use this class.\n\n    :Events:\n        `on_config_change`: ConfigParser instance, section, key, value\n            Fired when section/key/value of a ConfigParser changes.\n\n            .. warning:\n\n                value will be str/unicode type, regardless of the setting\n                type (numeric, boolean, etc)\n        `on_close`\n            Fired by the default panel when the Close button is pressed.\n\n        '''\n\n    interface = ObjectProperty(None)\n    '''(internal) Reference to the widget that will contain, organise and\n    display the panel configuration panel widgets.\n\n    :attr:`interface` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n\n    '''\n\n    interface_cls = ObjectProperty(InterfaceWithSidebar)\n    '''The widget class that will be used to display the graphical\n    interface for the settings panel. By default, it displays one Settings\n    panel at a time with a sidebar to switch between them.\n\n    :attr:`interface_cls` is an\n    :class:`~kivy.properties.ObjectProperty` and defaults to\n    :class`InterfaceWithSidebar`.\n\n    .. versionchanged:: 1.8.0\n        If you set a string, the :class:`~kivy.factory.Factory` will be used to\n        resolve the class.\n\n    '''\n\n    __events__ = ('on_close', 'on_config_change')\n\n    def __init__(self, *args, **kargs):\n        self._types = {}\n        super(Settings, self).__init__(*args, **kargs)\n        self.add_interface()\n        self.register_type('string', SettingString)\n        self.register_type('bool', SettingBoolean)\n        self.register_type('numeric', SettingNumeric)\n        self.register_type('options', SettingOptions)\n        self.register_type('title', SettingTitle)\n        self.register_type('path', SettingPath)\n\n    def on_touch_down(self, touch):\n        if self.collide_point(*touch.pos):\n            super(Settings, self).on_touch_down(touch)\n            return True\n\n    def register_type(self, tp, cls):\n        '''Register a new type that can be used in the JSON definition.\n        '''\n        self._types[tp] = cls\n\n    def on_close(self, *args):\n        pass\n\n    def add_interface(self):\n        '''(Internal) creates an instance of :attr:`Settings.interface_cls`,\n        and sets it to :attr:`~Settings.interface`. When json panels are\n        created, they will be added to this interface which will display them\n        to the user.\n        '''\n        cls = self.interface_cls\n        if isinstance(cls, string_types):\n            cls = Factory.get(cls)\n        interface = cls()\n        self.interface = interface\n        self.add_widget(interface)\n        self.interface.bind(on_close=lambda j: self.dispatch('on_close'))\n\n    def on_config_change(self, config, section, key, value):\n        pass\n\n    def add_json_panel(self, title, config, filename=None, data=None):\n        '''Create and add a new :class:`SettingsPanel` using the configuration\n        `config` with the JSON definition `filename`.\n\n        Check the :ref:`settings_json` section in the documentation for more\n        information about JSON format and the usage of this function.\n        '''\n        panel = self.create_json_panel(title, config, filename, data)\n        uid = panel.uid\n        if self.interface is not None:\n            self.interface.add_panel(panel, title, uid)\n\n    def create_json_panel(self, title, config, filename=None, data=None):\n        '''Create new :class:`SettingsPanel`.\n\n        .. versionadded:: 1.5.0\n\n        Check the documentation of :meth:`add_json_panel` for more information.\n        '''\n        if filename is None and data is None:\n            raise Exception('You must specify either the filename or data')\n        if filename is not None:\n            with open(filename, 'r') as fd:\n                data = json.loads(fd.read())\n        else:\n            data = json.loads(data)\n        if type(data) != list:\n            raise ValueError('The first element must be a list')\n        panel = SettingsPanel(title=title, settings=self, config=config)\n\n        for setting in data:\n            # determine the type and the class to use\n            if not 'type' in setting:\n                raise ValueError('One setting are missing the \"type\" element')\n            ttype = setting['type']\n            cls = self._types.get(ttype)\n            if cls is None:\n                raise ValueError(\n                    'No class registered to handle the <%s> type' %\n                    setting['type'])\n\n            # create a instance of the class, without the type attribute\n            del setting['type']\n            str_settings = {}\n            for key, item in setting.items():\n                str_settings[str(key)] = item\n\n            instance = cls(panel=panel, **str_settings)\n\n            # instance created, add to the panel\n            panel.add_widget(instance)\n\n        return panel\n\n    def add_kivy_panel(self):\n        '''Add a panel for configuring Kivy. This panel acts directly on the\n        kivy configuration. Feel free to include or exclude it in your\n        configuration.\n\n        See :meth:`~kivy.app.App.use_kivy_settings` for information on\n        enabling/disabling the automatic kivy panel.\n\n        '''\n        from kivy import kivy_data_dir\n        from kivy.config import Config\n        from os.path import join\n        self.add_json_panel('Kivy', Config,\n                            join(kivy_data_dir, 'settings_kivy.json'))\n\n\nclass SettingsWithSidebar(Settings):\n    '''A settings widget that displays settings panels with a sidebar to\n    switch between them. This is the default behaviour of\n    :class:`Settings`, and this widget is a trivial wrapper subclass.\n\n    '''\n\n\nclass SettingsWithSpinner(Settings):\n    '''A settings widget that displays one settings panel at a time with a\n    spinner at the top to switch between them.\n\n    '''\n    def __init__(self, *args, **kwargs):\n        self.interface_cls = InterfaceWithSpinner\n        super(SettingsWithSpinner, self).__init__(*args, **kwargs)\n\n\nclass SettingsWithTabbedPanel(Settings):\n    '''A settings widget that displays settings panels as pages in a\n    :class:`~kivy.uix.tabbedpanel.TabbedPanel`.\n    '''\n\n    __events__ = ('on_close', )\n\n    def __init__(self, *args, **kwargs):\n        self.interface_cls = InterfaceWithTabbedPanel\n        super(SettingsWithTabbedPanel, self).__init__(*args, **kwargs)\n\n    def on_close(self, *args):\n        pass\n\n\nclass SettingsWithNoMenu(Settings):\n    '''A settings widget that displays a single settings panel with *no*\n    Close button. It will not accept more than one Settings panel. It\n    is intended for use in programs with few enough settings that a\n    full panel switcher is not useful.\n\n    .. warning::\n\n        This Settings panel does *not* provide a Close\n        button, and so it is impossible to leave the settings screen\n        unless you also add other behaviour or override\n        :meth:`~kivy.app.App.display_settings` and\n        :meth:`~kivy.app.App.close_settings`.\n\n    '''\n    def __init__(self, *args, **kwargs):\n        self.interface_cls = InterfaceWithNoMenu\n        super(SettingsWithNoMenu, self).__init__(*args, **kwargs)\n\n\nclass InterfaceWithNoMenu(ContentPanel):\n    '''The interface widget used by :class:`SettingsWithNoMenu`. It\n    stores and displays a single settings panel.\n\n    This widget is considered internal and is not documented. See the\n    :class:`ContentPanel` for information on defining your own content\n    widget.\n\n    '''\n    def add_widget(self, widget):\n        if self.container is not None and len(self.container.children) > 0:\n            raise Exception(\n                'ContentNoMenu cannot accept more than one settings panel')\n        super(InterfaceWithNoMenu, self).add_widget(widget)\n\n\nclass InterfaceWithTabbedPanel(FloatLayout):\n    '''The content widget used by :class:`SettingsWithTabbedPanel`. It\n    stores and displays Settings panels in tabs of a TabbedPanel.\n\n    This widget is considered internal and is not documented. See\n    :class:`InterfaceWithSidebar` for information on defining your own\n    interface widget.\n\n    '''\n    tabbedpanel = ObjectProperty()\n    close_button = ObjectProperty()\n\n    __events__ = ('on_close', )\n\n    def __init__(self, *args, **kwargs):\n        super(InterfaceWithTabbedPanel, self).__init__(*args, **kwargs)\n        self.close_button.bind(on_release=lambda j: self.dispatch('on_close'))\n\n    def add_panel(self, panel, name, uid):\n        scrollview = ScrollView()\n        scrollview.add_widget(panel)\n        if not self.tabbedpanel.default_tab_content:\n            self.tabbedpanel.default_tab_text = name\n            self.tabbedpanel.default_tab_content = scrollview\n        else:\n            panelitem = TabbedPanelHeader(text=name, content=scrollview)\n            self.tabbedpanel.add_widget(panelitem)\n\n    def on_close(self, *args):\n        pass\n\n\nclass MenuSpinner(BoxLayout):\n    '''The menu class used by :class:`SettingsWithSpinner`. It provides a\n    sidebar with an entry for each settings panel.\n\n    This widget is considered internal and is not documented. See\n    :class:`MenuSidebar` for information on menus and creating your own menu\n    class.\n\n    '''\n    selected_uid = NumericProperty(0)\n    close_button = ObjectProperty(0)\n    spinner = ObjectProperty()\n    panel_names = DictProperty({})\n    spinner_text = StringProperty()\n    close_button = ObjectProperty()\n\n    def add_item(self, name, uid):\n        values = self.spinner.values\n        if name in values:\n            i = 2\n            while name + ' {}'.format(i) in values:\n                i += 1\n            name = name + ' {}'.format(i)\n        self.panel_names[name] = uid\n        self.spinner.values.append(name)\n        if not self.spinner.text:\n            self.spinner.text = name\n\n    def on_spinner_text(self, *args):\n        text = self.spinner_text\n        self.selected_uid = self.panel_names[text]\n\n\nclass MenuSidebar(FloatLayout):\n    '''The menu used by :class:`InterfaceWithSidebar`. It provides a\n    sidebar with an entry for each settings panel, which the user may\n    click to select.\n\n    '''\n\n    selected_uid = NumericProperty(0)\n    '''The uid of the currently selected panel. This may be used to switch\n    between displayed panels, e.g. by binding it to the\n    :attr:`~ContentPanel.current_uid` of a :class:`ContentPanel`.\n\n    :attr:`selected_uid` is a\n    :class`~kivy.properties.NumericProperty` and defaults to 0.\n\n    '''\n\n    buttons_layout = ObjectProperty(None)\n    '''(internal) Reference to the GridLayout that contains individual\n    settings panel menu buttons.\n\n    :attr:`buttons_layout` is an\n    :class:`~kivy.properties.ObjectProperty` and defaults to None.\n\n    '''\n\n    close_button = ObjectProperty(None)\n    '''(internal) Reference to the widget's Close button.\n\n    :attr:`buttons_layout` is an\n    :class:`~kivy.properties.ObjectProperty` and defaults to None.\n\n    '''\n\n    def add_item(self, name, uid):\n        '''This method is used to add new panels to the menu.\n\n        :param name: The name (a string) of the panel. It should be\n                     used to represent the panel in the menu.\n\n        :param uid: The name (an int) of the panel. It should be used\n                    internally to represent the panel and used to set\n                    self.selected_uid when the panel is changed.\n\n        '''\n\n        label = SettingSidebarLabel(text=name, uid=uid, menu=self)\n        if len(self.buttons_layout.children) == 0:\n            label.selected = True\n        if self.buttons_layout is not None:\n            self.buttons_layout.add_widget(label)\n\n    def on_selected_uid(self, *args):\n        '''(internal) unselects any currently selected menu buttons, unless\n        they represent the current panel.\n\n        '''\n        for button in self.buttons_layout.children:\n            if button.uid != self.selected_uid:\n                button.selected = False\n\n\nclass SettingSidebarLabel(Label):\n    # Internal class, not documented.\n    selected = BooleanProperty(False)\n    uid = NumericProperty(0)\n    menu = ObjectProperty(None)\n\n    def on_touch_down(self, touch):\n        if not self.collide_point(*touch.pos):\n            return\n        self.selected = True\n        self.menu.selected_uid = self.uid\n\n\nif __name__ == '__main__':\n    from kivy.app import App\n\n    class SettingsApp(App):\n\n        def build(self):\n            s = Settings()\n            s.add_kivy_panel()\n            s.bind(on_close=self.stop)\n            return s\n\n    SettingsApp().run()\n"
  },
  {
    "path": "tickeys/kivy/uix/slider.py",
    "content": "\"\"\"\nSlider\n======\n\n.. image:: images/slider.jpg\n\nThe :class:`Slider` widget looks like a scrollbar. It supports horizontal and\nvertical orientations, min/max values and a default value.\n\nTo create a slider from -100 to 100 starting from 25::\n\n    from kivy.uix.slider import Slider\n    s = Slider(min=-100, max=100, value=25)\n\nTo create a vertical slider::\n\n    from kivy.uix.slider import Slider\n    s = Slider(orientation='vertical')\n\n\"\"\"\n__all__ = ('Slider', )\n\nfrom kivy.uix.widget import Widget\nfrom kivy.properties import (NumericProperty, AliasProperty, OptionProperty,\n                             ReferenceListProperty, BoundedNumericProperty)\nfrom kivy.metrics import sp\n\n\nclass Slider(Widget):\n    \"\"\"Class for creating a Slider widget.\n\n    Check module documentation for more details.\n    \"\"\"\n\n    value = NumericProperty(0.)\n    '''Current value used for the slider.\n\n    :attr:`value` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 0.'''\n\n    min = NumericProperty(0.)\n    '''Minimum value allowed for :attr:`value`.\n\n    :attr:`min` is a :class:`~kivy.properties.NumericProperty` and defaults to\n    0.'''\n\n    max = NumericProperty(100.)\n    '''Maximum value allowed for :attr:`value`.\n\n    :attr:`max` is a :class:`~kivy.properties.NumericProperty` and defaults to\n    100.'''\n\n    padding = NumericProperty(sp(16))\n    '''Padding of the slider. The padding is used for graphical representation\n    and interaction. It prevents the cursor from going out of the bounds of the\n    slider bounding box.\n\n    By default, padding is sp(16). The range of the slider is reduced from\n    padding \\*2 on the screen. It allows drawing the default cursor of sp(32)\n    width without having the cursor go out of the widget.\n\n    :attr:`padding` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to sp(16).'''\n\n    orientation = OptionProperty('horizontal', options=(\n        'vertical', 'horizontal'))\n    '''Orientation of the slider.\n\n    :attr:`orientation` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to 'horizontal'. Can take a value of 'vertical' or 'horizontal'.\n    '''\n\n    range = ReferenceListProperty(min, max)\n    '''Range of the slider in the format (minimum value, maximum value)::\n\n        >>> slider = Slider(min=10, max=80)\n        >>> slider.range\n        [10, 80]\n        >>> slider.range = (20, 100)\n        >>> slider.min\n        20\n        >>> slider.max\n        100\n\n    :attr:`range` is a :class:`~kivy.properties.ReferenceListProperty` of\n    (:attr:`min`, :attr:`max`) properties.\n    '''\n\n    step = BoundedNumericProperty(0, min=0)\n    '''Step size of the slider.\n\n    .. versionadded:: 1.4.0\n\n    Determines the size of each interval or step the slider takes between\n    min and max. If the value range can't be evenly divisible by step the\n    last step will be capped by slider.max\n\n    :attr:`step` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 1.'''\n\n    # The following two methods constrain the slider's value\n    # to range(min,max). Otherwise it may happen that self.value < self.min\n    # at init.\n\n    def on_min(self, *largs):\n        self.value = min(self.max, max(self.min, self.value))\n\n    def on_max(self, *largs):\n        self.value = min(self.max, max(self.min, self.value))\n\n    def get_norm_value(self):\n        vmin = self.min\n        d = self.max - vmin\n        if d == 0:\n            return 0\n        return (self.value - vmin) / float(d)\n\n    def set_norm_value(self, value):\n        vmin = self.min\n        step = self.step\n        val = value * (self.max - vmin) + vmin\n        if step == 0:\n            self.value = val\n        else:\n            self.value = min(round((val - vmin) / step) * step + vmin,\n                             self.max)\n    value_normalized = AliasProperty(get_norm_value, set_norm_value,\n                                     bind=('value', 'min', 'max', 'step'))\n    '''Normalized value inside the :attr:`range` (min/max) to 0-1 range::\n\n        >>> slider = Slider(value=50, min=0, max=100)\n        >>> slider.value\n        50\n        >>> slider.value_normalized\n        0.5\n        >>> slider.value = 0\n        >>> slider.value_normalized\n        0\n        >>> slider.value = 100\n        >>> slider.value_normalized\n        1\n\n    You can also use it for setting the real value without knowing the minimum\n    and maximum::\n\n        >>> slider = Slider(min=0, max=200)\n        >>> slider.value_normalized = .5\n        >>> slider.value\n        100\n        >>> slider.value_normalized = 1.\n        >>> slider.value\n        200\n\n    :attr:`value_normalized` is an :class:`~kivy.properties.AliasProperty`.\n    '''\n\n    def get_value_pos(self):\n        padding = self.padding\n        x = self.x\n        y = self.y\n        nval = self.value_normalized\n        if self.orientation == 'horizontal':\n            return (x + padding + nval * (self.width - 2 * padding), y)\n        else:\n            return (x, y + padding + nval * (self.height - 2 * padding))\n\n    def set_value_pos(self, pos):\n        padding = self.padding\n        x = min(self.right - padding, max(pos[0], self.x + padding))\n        y = min(self.top - padding, max(pos[1], self.y + padding))\n        if self.orientation == 'horizontal':\n            if self.width == 0:\n                self.value_normalized = 0\n            else:\n                self.value_normalized = (x - self.x - padding\n                                         ) / float(self.width - 2 * padding)\n        else:\n            if self.height == 0:\n                self.value_normalized = 0\n            else:\n                self.value_normalized = (y - self.y - padding\n                                         ) / float(self.height - 2 * padding)\n    value_pos = AliasProperty(get_value_pos, set_value_pos,\n                              bind=('x', 'y', 'width', 'height', 'min',\n                                    'max', 'value_normalized', 'orientation'))\n    '''Position of the internal cursor, based on the normalized value.\n\n    :attr:`value_pos` is an :class:`~kivy.properties.AliasProperty`.\n    '''\n\n    def on_touch_down(self, touch):\n        if self.disabled or not self.collide_point(*touch.pos):\n            return\n        if touch.is_mouse_scrolling:\n            if 'down' in touch.button or 'left' in touch.button:\n                if self.step:\n                    self.value = min(self.max, self.value + self.step)\n                else:\n                    self.value = min(\n                        self.max,\n                        self.value + (self.max - self.min) / 20)\n            if 'up' in touch.button or 'right' in touch.button:\n                if self.step:\n                    self.value = max(self.min, self.value - self.step)\n                else:\n                    self.value = max(\n                        self.min,\n                        self.value - (self.max - self.min) / 20)\n        else:\n            touch.grab(self)\n            self.value_pos = touch.pos\n        return True\n\n    def on_touch_move(self, touch):\n        if touch.grab_current == self:\n            self.value_pos = touch.pos\n            return True\n\n    def on_touch_up(self, touch):\n        if touch.grab_current == self:\n            self.value_pos = touch.pos\n            return True\n\nif __name__ == '__main__':\n    from kivy.app import App\n\n    class SliderApp(App):\n        def build(self):\n            return Slider(padding=25)\n\n    SliderApp().run()\n"
  },
  {
    "path": "tickeys/kivy/uix/spinner.py",
    "content": "'''\nSpinner\n=======\n\n.. versionadded:: 1.4.0\n\n.. image:: images/spinner.jpg\n    :align: right\n\nSpinner is a widget that provides a quick way to select one value from a set.\nIn the default state, a spinner shows its currently selected value.\nTouching the spinner displays a dropdown menu with all the other available\nvalues from which the user can select a new one.\n\nExample::\n\n    from kivy.base import runTouchApp\n    from kivy.uix.spinner import Spinner\n\n    spinner = Spinner(\n        # default value shown\n        text='Home',\n        # available values\n        values=('Home', 'Work', 'Other', 'Custom'),\n        # just for positioning in our example\n        size_hint=(None, None),\n        size=(100, 44),\n        pos_hint={'center_x': .5, 'center_y': .5})\n\n    def show_selected_value(spinner, text):\n        print('The spinner', spinner, 'have text', text)\n\n    spinner.bind(text=show_selected_value)\n\n    runTouchApp(spinner)\n\n'''\n\n__all__ = ('Spinner', 'SpinnerOption')\n\nfrom kivy.compat import string_types\nfrom kivy.factory import Factory\nfrom kivy.properties import ListProperty, ObjectProperty, BooleanProperty\nfrom kivy.uix.button import Button\nfrom kivy.uix.dropdown import DropDown\n\n\nclass SpinnerOption(Button):\n    '''Special button used in the dropdown list. We just set the default\n    size_hint_y and height.\n    '''\n    pass\n\n\nclass Spinner(Button):\n    '''Spinner class, see module documentation for more information.\n    '''\n\n    values = ListProperty()\n    '''Values that can be selected by the user. It must be a list of strings.\n\n    :attr:`values` is a :class:`~kivy.properties.ListProperty` and defaults to\n    [].\n    '''\n\n    option_cls = ObjectProperty(SpinnerOption)\n    '''Class used to display the options within the dropdown list displayed\n    under the Spinner. The `text` property of the class will be used to\n    represent the value.\n\n    The option class requires at least:\n\n    - a `text` property, used to display the value.\n    - an `on_release` event, used to trigger the option when pressed/touched.\n\n    :attr:`option_cls` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to :class:`SpinnerOption`.\n\n    .. versionchanged:: 1.8.0\n        If you set a string, the :class:`~kivy.factory.Factory` will be used to\n        resolve the class.\n\n    '''\n\n    dropdown_cls = ObjectProperty(DropDown)\n    '''Class used to display the dropdown list when the Spinner is pressed.\n\n    :attr:`dropdown_cls` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to :class:`~kivy.uix.dropdown.DropDown`.\n\n    .. versionchanged:: 1.8.0\n        If you set a string, the :class:`~kivy.factory.Factory` will be used to\n        resolve the class.\n\n    '''\n\n    is_open = BooleanProperty(False)\n    '''By default, the spinner is not open. Set to True to open it.\n\n    :attr:`is_open` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n\n    .. versionadded:: 1.4.0\n    '''\n\n    def __init__(self, **kwargs):\n        self._dropdown = None\n        super(Spinner, self).__init__(**kwargs)\n        self.bind(\n            on_release=self._toggle_dropdown,\n            dropdown_cls=self._build_dropdown,\n            option_cls=self._build_dropdown,\n            values=self._update_dropdown)\n        self._build_dropdown()\n\n    def _build_dropdown(self, *largs):\n        if self._dropdown:\n            self._dropdown.unbind(on_select=self._on_dropdown_select)\n            self._dropdown.unbind(on_dismiss=self._close_dropdown)\n            self._dropdown.dismiss()\n            self._dropdown = None\n        cls = self.dropdown_cls\n        if isinstance(cls, string_types):\n            cls = Factory.get(cls)\n        self._dropdown = cls()\n        self._dropdown.bind(on_select=self._on_dropdown_select)\n        self._dropdown.bind(on_dismiss=self._close_dropdown)\n        self._update_dropdown()\n\n    def _update_dropdown(self, *largs):\n        dp = self._dropdown\n        cls = self.option_cls\n        if isinstance(cls, string_types):\n            cls = Factory.get(cls)\n        dp.clear_widgets()\n        for value in self.values:\n            item = cls(text=value)\n            item.bind(on_release=lambda option: dp.select(option.text))\n            dp.add_widget(item)\n\n    def _toggle_dropdown(self, *largs):\n        self.is_open = not self.is_open\n\n    def _close_dropdown(self, *largs):\n        self.is_open = False\n\n    def _on_dropdown_select(self, instance, data, *largs):\n        self.text = data\n        self.is_open = False\n\n    def on_is_open(self, instance, value):\n        if value:\n            self._dropdown.open(self)\n        else:\n            if self._dropdown.attach_to:\n                self._dropdown.dismiss()\n"
  },
  {
    "path": "tickeys/kivy/uix/splitter.py",
    "content": "'''Splitter\n======\n\n.. versionadded:: 1.5.0\n\n.. image:: images/splitter.jpg\n    :align: right\n\nThe :class:`Splitter` is a widget that helps you re-size it's child\nwidget/layout by letting you re-size it via dragging the boundary or\ndouble tapping the boundary. This widget is similar to the\n:class:`~kivy.uix.scrollview.ScrollView` in that it allows only one\nchild widget.\n\nUsage::\n\n    splitter = Splitter(sizable_from = 'right')\n    splitter.add_widget(layout_or_widget_instance)\n    splitter.min_size = 100\n    splitter.max_size = 250\n\nTo change the size of the strip/border used for resizing::\n\n    splitter.strip_size = '10pt'\n\nTo change its appearance::\n\n    splitter.strip_cls = your_custom_class\n\nYou can also change the appearance of the `strip_cls`, which defaults to\n:class:`SplitterStrip`, by overriding the `kv` rule in your app::\n\n    <SplitterStrip>:\n        horizontal: True if self.parent and self.parent.sizable_from[0] \\\nin ('t', 'b') else False\n        background_normal: 'path to normal horizontal image' \\\nif self.horizontal else 'path to vertical normal image'\n        background_down: 'path to pressed horizontal image' \\\nif self.horizontal else 'path to vertical pressed image'\n\n'''\n\n\n__all__ = ('Splitter', )\n\nfrom kivy.compat import string_types\nfrom kivy.factory import Factory\nfrom kivy.uix.button import Button\nfrom kivy.properties import (OptionProperty, NumericProperty, ObjectProperty,\n                             ListProperty, BooleanProperty)\nfrom kivy.uix.boxlayout import BoxLayout\n\n\nclass SplitterStrip(Button):\n    '''Class used for tbe graphical representation of a\n    :class:`kivy.uix.splitter.SplitterStripe`.\n    '''\n    pass\n\n\nclass Splitter(BoxLayout):\n    '''See module documentation.\n\n    :Events:\n        `on_press`:\n            Fired when the splitter is pressed.\n        `on_release`:\n            Fired when the splitter is released.\n\n    .. versionchanged:: 1.6.0\n        Added `on_press` and `on_release` events.\n\n    '''\n\n    border = ListProperty([4, 4, 4, 4])\n    '''Border used for the\n    :class:`~kivy.graphics.vertex_instructions.BorderImage`\n    graphics instruction.\n\n    This must be a list of four values: (top, right, bottom, left).\n    Read the BorderImage instructions for more information about how\n    to use it.\n\n    :attr:`border` is a :class:`~kivy.properties.ListProperty` and\n    defaults to (4, 4, 4, 4).\n    '''\n\n    strip_cls = ObjectProperty(SplitterStrip)\n    '''Specifies the class of the resize Strip.\n\n    :attr:`strip_cls` is an :class:`kivy.properties.ObjectProperty` and\n    defaults to :class:`~kivy.uix.splitter.SplitterStrip`, which is of type\n    :class:`~kivy.uix.button.Button`.\n\n    .. versionchanged:: 1.8.0\n        If you set a string, the :class:`~kivy.factory.Factory` will be used to\n        resolve the class.\n\n    '''\n\n    sizable_from = OptionProperty('left', options=(\n        'left', 'right', 'top', 'bottom'))\n    '''Specifies whether the widget is resizable. Options are::\n        `left`, `right`, `top` or `bottom`\n\n    :attr:`sizable_from` is an :class:`~kivy.properties.OptionProperty`\n    and defaults to `left`.\n    '''\n\n    strip_size = NumericProperty('10pt')\n    '''Specifies the size of resize strip\n\n    :attr:`strp_size` is a :class:`~kivy.properties.NumericProperty`\n    defaults to `10pt`\n    '''\n\n    min_size = NumericProperty('100pt')\n    '''Specifies the minimum size beyond which the widget is not resizable.\n\n    :attr:`min_size` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to `100pt`.\n    '''\n\n    max_size = NumericProperty('500pt')\n    '''Specifies the maximum size beyond which the widget is not resizable.\n\n    :attr:`max_size` is a :class:`~kivy.properties.NumericProperty`\n    and defaults to `500pt`.\n    '''\n\n    _parent_proportion = NumericProperty(0.)\n    '''(internal) Specifies the distance that the slider has travelled\n    across its parent, used to automatically maintain a sensible\n    position if the parent is resized.\n\n    :attr:`_parent_proportion` is a\n    :class:`~kivy.properties.NumericProperty` and defaults to 0.\n\n    .. versionadded:: 1.9.0\n    '''\n\n    _bound_parent = ObjectProperty(None, allownone=True)\n    '''(internal) References the widget whose size is currently being\n    tracked by :attr:`_parent_proportion`.\n\n    :attr:`_bound_parent` is a\n    :class:`~kivy.properties.ObjectProperty` and defaults to None.\n\n    .. versionadded:: 1.9.0\n    '''\n\n    keep_within_parent = BooleanProperty(False)\n    '''If True, will limit the splitter to stay within its parent widget.\n\n    :attr:`keep_within_parent` is a\n    :class:`~kivy.properties.BooleanProperty` and defaults to False.\n\n    .. versionadded:: 1.9.0\n    '''\n\n    rescale_with_parent = BooleanProperty(False)\n    '''If True, will automatically change size to take up the same\n    proportion of the parent widget when it is resized, while\n    staying within :attr:`min_size` and :attr:`max_size`. As long as\n    these attributes can be satisfied, this stops the\n    :class:`Splitter` from exceeding the parent size during rescaling.\n\n    :attr:`rescale_with_parent` is a\n    :class:`~kivy.properties.BooleanProperty` and defaults to False.\n\n    .. versionadded:: 1.9.0\n    '''\n\n    __events__ = ('on_press', 'on_release')\n\n    def __init__(self, **kwargs):\n        self._container = None\n        self._strip = None\n        super(Splitter, self).__init__(**kwargs)\n        self.bind(max_size=self._do_size,\n                  min_size=self._do_size,\n                  parent=self._rebind_parent)\n\n    def on_sizable_from(self, instance, sizable_from):\n        if not instance._container:\n            return\n\n        sup = super(Splitter, instance)\n        _strp = instance._strip\n        if _strp:\n            # remove any previous binds\n            _strp.unbind(on_touch_down=instance.strip_down)\n            _strp.unbind(on_touch_move=instance.strip_move)\n            _strp.unbind(on_touch_up=instance.strip_up)\n            self.unbind(disabled=_strp.setter('disabled'))\n\n            sup.remove_widget(instance._strip)\n        else:\n            cls = instance.strip_cls\n            if isinstance(cls, string_types):\n                cls = Factory.get(cls)\n            instance._strip = _strp = cls()\n\n        sz_frm = instance.sizable_from[0]\n        if sz_frm in ('l', 'r'):\n            _strp.size_hint = None, 1\n            _strp.width = instance.strip_size\n            instance.orientation = 'horizontal'\n            instance.unbind(strip_size=_strp.setter('width'))\n            instance.bind(strip_size=_strp.setter('width'))\n        else:\n            _strp.size_hint = 1, None\n            _strp.height = instance.strip_size\n            instance.orientation = 'vertical'\n            instance.unbind(strip_size=_strp.setter('height'))\n            instance.bind(strip_size=_strp.setter('height'))\n\n        index = 1\n        if sz_frm in ('r', 'b'):\n            index = 0\n        sup.add_widget(_strp, index)\n\n        _strp.bind(on_touch_down=instance.strip_down)\n        _strp.bind(on_touch_move=instance.strip_move)\n        _strp.bind(on_touch_up=instance.strip_up)\n        _strp.disabled = self.disabled\n        self.bind(disabled=_strp.setter('disabled'))\n\n    def add_widget(self, widget, index=0):\n        if self._container or not widget:\n            return Exception('Splitter accepts only one Child')\n        self._container = widget\n        sz_frm = self.sizable_from[0]\n        if sz_frm in ('l', 'r'):\n            widget.size_hint_x = 1\n        else:\n            widget.size_hint_y = 1\n\n        index = 0\n        if sz_frm in ('r', 'b'):\n            index = 1\n        super(Splitter, self).add_widget(widget, index)\n        self.on_sizable_from(self, self.sizable_from)\n\n    def remove_widget(self, widget, *largs):\n        super(Splitter, self).remove_widget(widget)\n        if widget == self._container:\n            self._container = None\n\n    def clear_widgets(self):\n        self.remove_widget(self._container)\n\n    def strip_down(self, instance, touch):\n        if not instance.collide_point(*touch.pos):\n            return False\n        touch.grab(self)\n        self.dispatch('on_press')\n\n    def on_press(self):\n        pass\n\n    def _rebind_parent(self, instance, new_parent):\n        if self._bound_parent is not None:\n            self._bound_parent.unbind(size=self.rescale_parent_proportion)\n        if self.parent is not None:\n            new_parent.bind(size=self.rescale_parent_proportion)\n        self._bound_parent = new_parent\n        self.rescale_parent_proportion()\n\n    def rescale_parent_proportion(self, *args):\n        if self.rescale_with_parent:\n            parent_proportion = self._parent_proportion\n            if self.sizable_from in ('top', 'bottom'):\n                new_height = parent_proportion * self.parent.height\n                self.height = max(self.min_size, min(new_height, self.max_size))\n            else:\n                new_width = parent_proportion * self.parent.width\n                self.width = max(self.min_size, min(new_width, self.max_size))\n\n    def _do_size(self, instance, value):\n        if self.sizable_from[0] in ('l', 'r'):\n            self.width = max(self.min_size, min(self.width, self.max_size))\n        else:\n            self.height = max(self.min_size, min(self.height, self.max_size))\n\n    def strip_move(self, instance, touch):\n        if touch.grab_current is not instance:\n            return False\n        max_size = self.max_size\n        min_size = self.min_size\n        sz_frm = self.sizable_from[0]\n\n        if sz_frm in ('t', 'b'):\n            diff_y = (touch.dy)\n            if self.keep_within_parent:\n                if sz_frm == 't' and (self.top + diff_y) > self.parent.top:\n                    diff_y = self.parent.top - self.top\n                elif sz_frm == 'b' and (self.y + diff_y) < self.parent.y:\n                    diff_y = self.parent.y - self.y\n            if sz_frm == 'b':\n                diff_y *= -1\n            if self.size_hint_y:\n                self.size_hint_y = None\n            if self.height > 0:\n                self.height += diff_y\n            else:\n                self.height = 1\n\n            height = self.height\n            self.height = max(min_size, min(height, max_size))\n\n            self._parent_proportion = self.height / self.parent.height\n        else:\n            diff_x = (touch.dx)\n            if self.keep_within_parent:\n                if sz_frm == 'l' and (self.x + diff_x) < self.parent.x:\n                    diff_x = self.parent.x - self.x\n                elif (sz_frm == 'r' and\n                      (self.right + diff_x) > self.parent.right):\n                    diff_x = self.parent.right - self.right\n            if sz_frm == 'l':\n                diff_x *= -1\n            if self.size_hint_x:\n                self.size_hint_x = None\n            if self.width > 0:\n                self.width += diff_x\n            else:\n                self.width = 1\n\n            width = self.width\n            self.width = max(min_size, min(width, max_size))\n\n            self._parent_proportion = self.width / self.parent.width\n\n    def strip_up(self, instance, touch):\n        if touch.grab_current is not instance:\n            return\n\n        if touch.is_double_tap:\n            max_size = self.max_size\n            min_size = self.min_size\n            sz_frm = self.sizable_from[0]\n            s = self.size\n\n            if sz_frm in ('t', 'b'):\n                if self.size_hint_y:\n                    self.size_hint_y = None\n                if s[1] - min_size <= max_size - s[1]:\n                    self.height = max_size\n                else:\n                    self.height = min_size\n            else:\n                if self.size_hint_x:\n                    self.size_hint_x = None\n                if s[0] - min_size <= max_size - s[0]:\n                    self.width = max_size\n                else:\n                    self.width = min_size\n        touch.ungrab(instance)\n        self.dispatch('on_release')\n\n    def on_release(self):\n        pass\n\n\nif __name__ == '__main__':\n    from kivy.app import App\n    from kivy.uix.button import Button\n    from kivy.uix.floatlayout import FloatLayout\n\n    class SplitterApp(App):\n\n        def build(self):\n            root = FloatLayout()\n            bx = BoxLayout()\n            bx.add_widget(Button())\n            bx.add_widget(Button())\n            bx2 = BoxLayout()\n            bx2.add_widget(Button())\n            bx2.add_widget(Button())\n            bx2.add_widget(Button())\n            spl = Splitter(\n                size_hint=(1, .25),\n                pos_hint = {'top': 1},\n                sizable_from = 'bottom')\n            spl1 = Splitter(\n                sizable_from='left',\n                size_hint=(None, 1), width=90)\n            spl1.add_widget(Button())\n            bx.add_widget(spl1)\n            spl.add_widget(bx)\n\n            spl2 = Splitter(size_hint=(.25, 1))\n            spl2.add_widget(bx2)\n            spl2.sizable_from = 'right'\n            root.add_widget(spl)\n            root.add_widget(spl2)\n            return root\n\n    SplitterApp().run()\n"
  },
  {
    "path": "tickeys/kivy/uix/stacklayout.py",
    "content": "'''\nStack Layout\n============\n\n.. only:: html\n\n    .. image:: images/stacklayout.gif\n        :align: right\n\n.. only:: latex\n\n    .. image:: images/stacklayout.png\n        :align: right\n\n.. versionadded:: 1.0.5\n\nThe :class:`StackLayout` arranges children vertically or horizontally, as many\nas the layout can fit. The size of the individual children widgets do not\nhave to be uniform.\n\nFor example, to display widgets that get progressively larger in width::\n\n    root = StackLayout()\n    for i in range(25):\n        btn = Button(text=str(i), width=40 + i * 5, size_hint=(None, 0.15))\n        root.add_widget(btn)\n\n.. image:: images/stacklayout_sizing.png\n    :align: left\n'''\n\n__all__ = ('StackLayout', )\n\nfrom kivy.uix.layout import Layout\nfrom kivy.properties import NumericProperty, OptionProperty, \\\n    ReferenceListProperty, VariableListProperty\n\n\nclass StackLayout(Layout):\n    '''Stack layout class. See module documentation for more information.\n    '''\n\n    spacing = VariableListProperty([0, 0], length=2)\n    '''Spacing between children: [spacing_horizontal, spacing_vertical].\n\n    spacing also accepts a single argument form [spacing].\n\n    :attr:`spacing` is a\n    :class:`~kivy.properties.VariableListProperty` and defaults to [0, 0].\n\n    '''\n\n    padding = VariableListProperty([0, 0, 0, 0])\n    '''Padding between the layout box and it's children: [padding_left,\n    padding_top, padding_right, padding_bottom].\n\n    padding also accepts a two argument form [padding_horizontal,\n    padding_vertical] and a single argument form [padding].\n\n    .. versionchanged:: 1.7.0\n        Replaced the NumericProperty with a VariableListProperty.\n\n    :attr:`padding` is a\n    :class:`~kivy.properties.VariableListProperty` and defaults to\n    [0, 0, 0, 0].\n\n    '''\n\n    orientation = OptionProperty('lr-tb', options=(\n        'lr-tb', 'tb-lr', 'rl-tb', 'tb-rl', 'lr-bt', 'bt-lr', 'rl-bt',\n        'bt-rl'))\n    '''Orientation of the layout.\n\n    :attr:`orientation` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to 'lr-tb'.\n\n    Valid orientations are 'lr-tb', 'tb-lr', 'rl-tb', 'tb-rl', 'lr-bt',\n    'bt-lr', 'rl-bt' and 'bt-rl'.\n\n    .. versionchanged:: 1.5.0\n        :attr:`orientation` now correctly handles all valid combinations of\n        'lr','rl','tb','bt'. Before this version only 'lr-tb' and\n        'tb-lr' were supported, and 'tb-lr' was misnamed and placed\n        widgets from bottom to top and from right to left (reversed compared\n        to what was expected).\n\n    .. note::\n\n        'lr' means Left to Right.\n        'rl' means Right to Left.\n        'tb' means Top to Bottom.\n        'bt' means Bottom to Top.\n    '''\n\n    minimum_width = NumericProperty(0)\n    '''Minimum width needed to contain all children. It is automatically set\n    by the layout.\n\n    .. versionadded:: 1.0.8\n\n    :attr:`minimum_width` is a :class:`kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    minimum_height = NumericProperty(0)\n    '''Minimum height needed to contain all children. It is automatically set\n    by the layout.\n\n    .. versionadded:: 1.0.8\n\n    :attr:`minimum_height` is a :class:`kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    minimum_size = ReferenceListProperty(minimum_width, minimum_height)\n    '''Minimum size needed to contain all children. It is automatically set\n    by the layout.\n\n    .. versionadded:: 1.0.8\n\n    :attr:`minimum_size` is a\n    :class:`~kivy.properties.ReferenceListProperty` of\n    (:attr:`minimum_width`, :attr:`minimum_height`) properties.\n    '''\n\n    def __init__(self, **kwargs):\n        super(StackLayout, self).__init__(**kwargs)\n        self.bind(\n            padding=self._trigger_layout,\n            spacing=self._trigger_layout,\n            children=self._trigger_layout,\n            orientation=self._trigger_layout,\n            size=self._trigger_layout,\n            pos=self._trigger_layout)\n\n    def do_layout(self, *largs):\n        if not self.children:\n            return\n\n        # optimize layout by preventing looking at the same attribute in a loop\n        selfpos = self.pos\n        selfsize = self.size\n        orientation = self.orientation.split('-')\n        padding_left = self.padding[0]\n        padding_top = self.padding[1]\n        padding_right = self.padding[2]\n        padding_bottom = self.padding[3]\n\n        padding_x = padding_left + padding_right\n        padding_y = padding_top + padding_bottom\n        spacing_x, spacing_y = self.spacing\n\n        lc = []\n\n        # Determine which direction and in what order to place the widgets\n        posattr = [0] * 2\n        posdelta = [0] * 2\n        posstart = [0] * 2\n        for i in (0, 1):\n            posattr[i] = 1 * (orientation[i] in ('tb', 'bt'))\n            k = posattr[i]\n            if orientation[i] == 'lr':\n                # left to right\n                posdelta[i] = 1\n                posstart[i] = selfpos[k] + padding_left\n            elif orientation[i] == 'bt':\n                # bottom to top\n                posdelta[i] = 1\n                posstart[i] = selfpos[k] + padding_bottom\n            elif orientation[i] == 'rl':\n                # right to left\n                posdelta[i] = -1\n                posstart[i] = selfpos[k] + selfsize[k] - padding_right\n            else:\n                # top to bottom\n                posdelta[i] = -1\n                posstart[i] = selfpos[k] + selfsize[k] - padding_top\n\n        innerattr, outerattr = posattr\n        ustart, vstart = posstart\n        deltau, deltav = posdelta\n        del posattr, posdelta, posstart\n\n        u = ustart  # inner loop position variable\n        v = vstart  # outer loop position variable\n\n        # space calculation, used for determining when a row or column is full\n\n        if orientation[0] in ('lr', 'rl'):\n            sv = padding_y  # size in v-direction, for minimum_size property\n            su = padding_x  # size in h-direction\n            spacing_u = spacing_x\n            spacing_v = spacing_y\n            padding_u = padding_x\n            padding_v = padding_y\n        else:\n            sv = padding_x  # size in v-direction, for minimum_size property\n            su = padding_y  # size in h-direction\n            spacing_u = spacing_y\n            spacing_v = spacing_x\n            padding_u = padding_y\n            padding_v = padding_x\n\n        # space calculation, row height or column width, for arranging widgets\n        lv = 0\n\n        urev = (deltau < 0)\n        vrev = (deltav < 0)\n        firstchild = self.children[0]\n        sizes = []\n        for c in reversed(self.children):\n            if c.size_hint[outerattr]:\n                c.size[outerattr] = max(1,\n                    c.size_hint[outerattr] * (selfsize[outerattr] - padding_v))\n\n            # does the widget fit in the row/column?\n            ccount = len(lc)\n            totalsize = availsize = max(\n                0, selfsize[innerattr] - padding_u - spacing_u * ccount)\n            if not lc:\n                if c.size_hint[innerattr]:\n                    childsize = max(1, c.size_hint[innerattr] * totalsize)\n                else:\n                    childsize = max(0, c.size[innerattr])\n                availsize = selfsize[innerattr] - padding_u - childsize\n                testsizes = [childsize]\n            else:\n                testsizes = [0] * (ccount + 1)\n                for i, child in enumerate(lc):\n                    if availsize <= 0:\n                        # no space left but we're trying to add another widget.\n                        availsize = -1\n                        break\n                    if child.size_hint[innerattr]:\n                        testsizes[i] = childsize = max(\n                            1, child.size_hint[innerattr] * totalsize)\n                    else:\n                        testsizes[i] = childsize = max(0, child.size[innerattr])\n                    availsize -= childsize\n                if c.size_hint[innerattr]:\n                    testsizes[-1] = max(1, c.size_hint[innerattr] * totalsize)\n                else:\n                    testsizes[-1] = max(0, c.size[innerattr])\n                availsize -= testsizes[-1]\n\n            if availsize >= 0 or not lc:\n                # even if there's no space, we always add one widget to a row\n                lc.append(c)\n                sizes = testsizes\n                lv = max(lv, c.size[outerattr])\n                continue\n\n            # apply the sizes\n            for i, child in enumerate(lc):\n                if child.size_hint[innerattr]:\n                    child.size[innerattr] = sizes[i]\n\n            # push the line\n            sv += lv + spacing_v\n            for c2 in lc:\n                if urev:\n                    u -= c2.size[innerattr]\n                c2.pos[innerattr] = u\n                pos_outer = v\n                if vrev:\n                    # v position is actually the top/right side of the widget\n                    # when going from high to low coordinate values,\n                    # we need to subtract the height/width from the position.\n                    pos_outer -= c2.size[outerattr]\n                c2.pos[outerattr] = pos_outer\n                if urev:\n                    u -= spacing_u\n                else:\n                    u += c2.size[innerattr] + spacing_u\n\n            v += deltav * lv\n            v += deltav * spacing_v\n            lc = [c]\n            lv = c.size[outerattr]\n            if c.size_hint[innerattr]:\n                sizes = [max(1, c.size_hint[innerattr] *\n                             (selfsize[innerattr] - padding_u))]\n            else:\n                sizes = [max(0, c.size[innerattr])]\n            u = ustart\n\n        if lc:\n            # apply the sizes\n            for i, child in enumerate(lc):\n                if child.size_hint[innerattr]:\n                    child.size[innerattr] = sizes[i]\n\n            # push the last (incomplete) line\n            sv += lv + spacing_v\n            for c2 in lc:\n                if urev:\n                    u -= c2.size[innerattr]\n                c2.pos[innerattr] = u\n                pos_outer = v\n                if vrev:\n                    pos_outer -= c2.size[outerattr]\n                c2.pos[outerattr] = pos_outer\n                if urev:\n                    u -= spacing_u\n                else:\n                    u += c2.size[innerattr] + spacing_u\n\n        self.minimum_size[outerattr] = sv\n"
  },
  {
    "path": "tickeys/kivy/uix/stencilview.py",
    "content": "'''\nStencil View\n============\n\n.. versionadded:: 1.0.4\n\n:class:`StencilView` limits the drawing of child widgets to the StencilView's\nbounding box. Any drawing outside the bounding box will be clipped (trashed).\n\nThe StencilView uses the stencil graphics instructions under the hood. It\nprovides an efficient way to clip the drawing area of children.\n\n.. note::\n\n    As with the stencil graphics instructions, you cannot stack more than 8\n    stencil-aware widgets.\n\n.. note::\n\n    StencilView is not a layout. Consequently, you have to manage the size and\n    position of its children directly. You can combine (subclass both)\n    a StencilView and a Layout in order to achieve a layout's behavior.\n    For example::\n\n        class BoxStencil(BoxLayout, StencilView):\n            pass\n'''\n\n__all__ = ('StencilView', )\n\nfrom kivy.uix.widget import Widget\n\n\nclass StencilView(Widget):\n    '''StencilView class. See module documentation for more information.\n    '''\n    pass\n"
  },
  {
    "path": "tickeys/kivy/uix/switch.py",
    "content": "'''\nSwitch\n======\n\n.. versionadded:: 1.0.7\n\n.. image:: images/switch-on.jpg\n    :align: right\n\n.. image:: images/switch-off.jpg\n    :align: right\n\nThe :class:`Switch` widget is active or inactive, like a mechanical light\nswitch. The user can swipe to the left/right to activate/deactivate it::\n\n    switch = Switch(active=True)\n\nTo attach a callback that listens to the activation state::\n\n    def callback(instance, value):\n        print('the switch', instance, 'is', value)\n\n    switch = Switch()\n    switch.bind(active=callback)\n\nBy default, the representation of the widget is static. The minimum size\nrequired is 83x32 pixels (defined by the background image). The image is\ncentered within the widget.\n\nThe entire widget is active, not just the part with graphics. As long as you\nswipe over the widget's bounding box, it will work.\n\n.. note::\n\n    If you want to control the state with a single touch instead of a swipe,\n    use the :class:`ToggleButton` instead.\n'''\n\n\nfrom kivy.uix.widget import Widget\nfrom kivy.animation import Animation\nfrom kivy.properties import BooleanProperty, ObjectProperty, NumericProperty\n\n\nclass Switch(Widget):\n    '''Switch class. See module documentation for more information.\n    '''\n    active = BooleanProperty(False)\n    '''Indicate whether the switch is active or inactive.\n\n    :attr:`active` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    touch_control = ObjectProperty(None, allownone=True)\n    '''(internal) Contains the touch that currently interacts with the switch.\n\n    :attr:`touch_control` is an :class:`~kivy.properties.ObjectProperty`\n    and defaults to None.\n    '''\n\n    touch_distance = NumericProperty(0)\n    '''(internal) Contains the distance between the initial position of the\n    touch and the current position to determine if the swipe is from the left\n    or right.\n\n    :attr:`touch_distance` is a :class:`~kivy.properties.NumericProperty`\n    and defaults to 0.\n    '''\n\n    active_norm_pos = NumericProperty(0)\n    '''(internal) Contains the normalized position of the movable element\n    inside the switch, in the 0-1 range.\n\n    :attr:`active_norm_pos` is a :class:`~kivy.properties.NumericProperty`\n    and defaults to 0.\n    '''\n\n    def on_touch_down(self, touch):\n        if self.disabled or self.touch_control is not None:\n            return\n        if not self.collide_point(*touch.pos):\n            return\n        touch.grab(self)\n        self.touch_distance = 0\n        self.touch_control = touch\n        return True\n\n    def on_touch_move(self, touch):\n        if touch.grab_current is not self:\n            return\n        self.touch_distance = touch.x - touch.ox\n        return True\n\n    def on_touch_up(self, touch):\n        if touch.grab_current is not self:\n            return\n        touch.ungrab(self)\n        # depending of the distance, activate by norm pos or invert\n        if abs(touch.ox - touch.x) < 5:\n            self.active = not self.active\n        else:\n            self.active = self.active_norm_pos > 0.5\n        Animation(active_norm_pos=int(self.active), t='out_quad',\n                  d=.2).start(self)\n        self.touch_control = None\n        return True\n\nif __name__ == '__main__':\n    from kivy.base import runTouchApp\n    runTouchApp(Switch())\n"
  },
  {
    "path": "tickeys/kivy/uix/tabbedpanel.py",
    "content": "'''\nTabbedPanel\n===========\n\n.. image:: images/tabbed_panel.jpg\n    :align: right\n\n.. versionadded:: 1.3.0\n\n\nThe `TabbedPanel` widget manages different widgets in tabs, with a header area\nfor the actual tab buttons and a content area for showing the current tab\ncontent.\n\nThe :class:`TabbedPanel` provides one default tab.\n\nSimple example\n--------------\n\n.. include:: ../../examples/widgets/tabbedpanel.py\n    :literal:\n\n.. note::\n\n    A new class :class:`TabbedPanelItem` has been introduced in 1.5.0 for\n    convenience. So now one can simply add a :class:`TabbedPanelItem` to a\n    :class:`TabbedPanel` and `content` to the :class:`TabbedPanelItem`\n    as in the example provided above.\n\nCustomize the Tabbed Panel\n--------------------------\n\nYou can choose the position in which the tabs are displayed::\n\n    tab_pos = 'top_mid'\n\nAn individual tab is called a TabbedPanelHeader. It is a special button\ncontaining a `content` property. You add the TabbedPanelHeader first, and set\nits `content` property separately::\n\n    tp = TabbedPanel()\n    th = TabbedPanelHeader(text='Tab2')\n    tp.add_widget(th)\n\nAn individual tab, represented by a TabbedPanelHeader, needs its content set.\nThis content can be any widget. It could be a layout with a deep\nhierarchy of widgets, or it could be an individual widget, such as a label or a\nbutton::\n\n    th.content = your_content_instance\n\nThere is one \"shared\" main content area active at any given time, for all\nthe tabs. Your app is responsible for adding the content of individual tabs\nand for managing them, but it's not responsible for content switching. The\ntabbed panel handles switching of the main content object as per user action.\n\nThere is a default tab added when the tabbed panel is instantiated.\nTabs that you add individually as above, are added in addition to the default\ntab. Thus, depending on your needs and design, you will want to customize the\ndefault tab::\n\n    tp.default_tab_text = 'Something Specific To Your Use'\n\n\nThe default tab machinery requires special consideration and management.\nAccordingly, an `on_default_tab` event is provided for associating a callback::\n\n    tp.bind(default_tab = my_default_tab_callback)\n\nIt's important to note that by default, :attr:`default_tab_cls` is of type\n:class:`TabbedPanelHeader` and thus has the same properties as other tabs.\n\nSince 1.5.0, it is now possible to disable the creation of the\n:attr:`default_tab` by setting :attr:`do_default_tab` to False.\n\nTabs and content can be removed in several ways::\n\n    tp.remove_widget(widget/tabbed_panel_header)\n    or\n    tp.clear_widgets() # to clear all the widgets in the content area\n    or\n    tp.clear_tabs() # to remove the TabbedPanelHeaders\n\nTo access the children of the tabbed panel, use content.children::\n\n    tp.content.children\n\nTo access the list of tabs::\n\n    tp.tab_list\n\nTo change the appearance of the main tabbed panel content::\n\n    background_color = (1, 0, 0, .5) #50% translucent red\n    border = [0, 0, 0, 0]\n    background_image = 'path/to/background/image'\n\nTo change the background of a individual tab, use these two properties::\n\n    tab_header_instance.background_normal = 'path/to/tab_head/img'\n    tab_header_instance.background_down = 'path/to/tab_head/img_pressed'\n\nA TabbedPanelStrip contains the individual tab headers. To change the\nappearance of this tab strip, override the canvas of TabbedPanelStrip.\nFor example, in the kv language::\n\n    <TabbedPanelStrip>\n        canvas:\n            Color:\n                rgba: (0, 1, 0, 1) # green\n            Rectangle:\n                size: self.size\n                pos: self.pos\n\nBy default the tabbed panel strip takes its background image and color from the\ntabbed panel's background_image and background_color.\n\n'''\n\n__all__ = ('StripLayout', 'TabbedPanel', 'TabbedPanelContent',\n           'TabbedPanelHeader', 'TabbedPanelItem', 'TabbedPanelStrip',\n           'TabbedPanelException')\n\nfrom functools import partial\nfrom kivy.clock import Clock\nfrom kivy.compat import string_types\nfrom kivy.factory import Factory\nfrom kivy.uix.togglebutton import ToggleButton\nfrom kivy.uix.widget import Widget\nfrom kivy.uix.scatter import Scatter\nfrom kivy.uix.scrollview import ScrollView\nfrom kivy.uix.gridlayout import GridLayout\nfrom kivy.uix.floatlayout import FloatLayout\nfrom kivy.logger import Logger\nfrom kivy.metrics import dp\nfrom kivy.properties import ObjectProperty, StringProperty, OptionProperty, \\\n    ListProperty, NumericProperty, AliasProperty, BooleanProperty\n\n\nclass TabbedPanelException(Exception):\n    '''The TabbedPanelException class.\n    '''\n    pass\n\n\nclass TabbedPanelHeader(ToggleButton):\n    '''A Base for implementing a Tabbed Panel Head. A button intended to be\n    used as a Heading/Tab for a TabbedPanel widget.\n\n    You can use this TabbedPanelHeader widget to add a new tab to a\n    TabbedPanel.\n    '''\n\n    content = ObjectProperty(None, allownone=True)\n    '''Content to be loaded when this tab header is selected.\n\n    :attr:`content` is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    # only allow selecting the tab if not already selected\n    def on_touch_down(self, touch):\n        if self.state == 'down':\n            #dispatch to children, not to self\n            for child in self.children:\n                child.dispatch('on_touch_down', touch)\n            return\n        else:\n            super(TabbedPanelHeader, self).on_touch_down(touch)\n\n    def on_release(self, *largs):\n        # Tabbed panel header is a child of tab_strib which has a\n        # `tabbed_panel` property\n        if self.parent:\n            self.parent.tabbed_panel.switch_to(self)\n        else:\n            # tab removed before we could switch to it. Switch back to\n            # previous tab\n            self.panel.switch_to(self.panel.current_tab)\n\n\nclass TabbedPanelItem(TabbedPanelHeader):\n    '''This is a convenience class that provides a header of type\n    TabbedPanelHeader and links it with the content automatically. Thus\n    facilitating you to simply do the following in kv language::\n\n        <TabbedPanel>:\n            ...other settings\n            TabbedPanelItem:\n                BoxLayout:\n                    Label:\n                        text: 'Second tab content area'\n                    Button:\n                        text: 'Button that does nothing'\n\n    .. versionadded:: 1.5.0\n    '''\n\n    def add_widget(self, widget, index=0):\n        self.content = widget\n        if not self.parent:\n            return\n        panel = self.parent.tabbed_panel\n        if panel.current_tab == self:\n            panel.switch_to(self)\n\n    def remove_widget(self, widget):\n        self.content = None\n        if not self.parent:\n            return\n        panel = self.parent.tabbed_panel\n        if panel.current_tab == self:\n            panel.remove_widget(widget)\n\n\nclass TabbedPanelStrip(GridLayout):\n    '''A strip intended to be used as background for Heading/Tab.\n    This does not cover the blank areas in case the tabs don't cover\n    the entire width/height of the TabbedPanel(use StripLayout for that).\n    '''\n    tabbed_panel = ObjectProperty(None)\n    '''Link to the panel that the tab strip is a part of.\n\n    :attr:`tabbed_panel` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None .\n    '''\n\n\nclass StripLayout(GridLayout):\n    ''' The main layout that is used to house the entire tabbedpanel strip\n    including the blank areas in case the tabs don't cover the entire\n    width/height.\n\n    .. versionadded:: 1.8.0\n\n    '''\n\n    border = ListProperty([4, 4, 4, 4])\n    '''Border property for the :attr:`background_image`.\n\n    :attr:`border` is a :class:`~kivy.properties.ListProperty` and defaults\n    to [4, 4, 4, 4]\n    '''\n\n    background_image = StringProperty(\n        'atlas://data/images/defaulttheme/action_view')\n    '''Background image to be used for the Strip layout of the TabbedPanel.\n\n    :attr:`background_image` is a :class:`~kivy.properties.StringProperty` and\n     defaults to a transparent image.\n    '''\n\n\nclass TabbedPanelContent(FloatLayout):\n    '''The TabbedPanelContent class.\n    '''\n    pass\n\n\nclass TabbedPanel(GridLayout):\n    '''The TabbedPanel class. See module documentation for more information.\n    '''\n\n    background_color = ListProperty([1, 1, 1, 1])\n    '''Background color, in the format (r, g, b, a).\n\n    :attr:`background_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [1, 1, 1, 1].\n    '''\n\n    border = ListProperty([16, 16, 16, 16])\n    '''Border used for :class:`~kivy.graphics.vertex_instructions.BorderImage`\n    graphics instruction, used itself for :attr:`background_image`.\n    Can be changed for a custom background.\n\n    It must be a list of four values: (top, right, bottom, left). Read the\n    BorderImage instructions for more information.\n\n    :attr:`border` is a :class:`~kivy.properties.ListProperty` and\n    defaults to (16, 16, 16, 16)\n    '''\n\n    background_image = StringProperty('atlas://data/images/defaulttheme/tab')\n    '''Background image of the main shared content object.\n\n    :attr:`background_image` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/tab'.\n    '''\n\n    background_disabled_image = StringProperty(\n        'atlas://data/images/defaulttheme/tab_disabled')\n    '''Background image of the main shared content object when disabled.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`background_disabled_image` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/tab'.\n    '''\n\n    strip_image = StringProperty(\n        'atlas://data/images/defaulttheme/action_view')\n    '''Background image of the tabbed strip.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`strip_image` is a :class:`~kivy.properties.StringProperty`\n    and defaults to a empty image.\n    '''\n\n    strip_border = ListProperty([4, 4, 4, 4])\n    '''Border to be used on :attr:`strip_image`.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`strip_border` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [4, 4, 4, 4].\n    '''\n\n    _current_tab = ObjectProperty(None)\n\n    def get_current_tab(self):\n        return self._current_tab\n\n    current_tab = AliasProperty(get_current_tab, None, bind=('_current_tab', ))\n    '''Links to the currently selected or active tab.\n\n    .. versionadded:: 1.4.0\n\n    :attr:`current_tab` is an :class:`~kivy.AliasProperty`, read-only.\n    '''\n\n    tab_pos = OptionProperty(\n        'top_left',\n        options=('left_top', 'left_mid', 'left_bottom', 'top_left',\n                 'top_mid', 'top_right', 'right_top', 'right_mid',\n                 'right_bottom', 'bottom_left', 'bottom_mid', 'bottom_right'))\n    '''Specifies the position of the tabs relative to the content.\n    Can be one of: `left_top`, `left_mid`, `left_bottom`, `top_left`,\n    `top_mid`, `top_right`, `right_top`, `right_mid`, `right_bottom`,\n    `bottom_left`, `bottom_mid`, `bottom_right`.\n\n    :attr:`tab_pos` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to 'top_left'.\n    '''\n\n    tab_height = NumericProperty('40dp')\n    '''Specifies the height of the tab header.\n\n    :attr:`tab_height` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 40.\n    '''\n\n    tab_width = NumericProperty('100dp', allownone=True)\n    '''Specifies the width of the tab header.\n\n    :attr:`tab_width` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 100.\n    '''\n\n    do_default_tab = BooleanProperty(True)\n    '''Specifies whether a default_tab head is provided.\n\n    .. versionadded:: 1.5.0\n\n    :attr:`do_default_tab` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to 'True'.\n    '''\n\n    default_tab_text = StringProperty('Default tab')\n    '''Specifies the text displayed on the default tab header.\n\n    :attr:`default_tab_text` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'default tab'.\n    '''\n\n    default_tab_cls = ObjectProperty(TabbedPanelHeader)\n    '''Specifies the class to use for the styling of the default tab.\n\n    .. versionadded:: 1.4.0\n\n    .. warning::\n        `default_tab_cls` should be subclassed from `TabbedPanelHeader`\n\n    :attr:`default_tab_cls` is an :class:`~kivy.properties.ObjectProperty`\n    and defaults to `TabbedPanelHeader`. If you set a string, the\n    :class:`~kivy.factory.Factory` will be used to resolve the class.\n\n    .. versionchanged:: 1.8.0\n        The :class:`~kivy.factory.Factory` will resolve the class if a string is\n        set.\n    '''\n\n    def get_tab_list(self):\n        if self._tab_strip:\n            return self._tab_strip.children\n        return 1.\n\n    tab_list = AliasProperty(get_tab_list, None)\n    '''List of all the tab headers.\n\n    :attr:`tab_list` is an :class:`~kivy.properties.AliasProperty` and is\n    read-only.\n    '''\n\n    content = ObjectProperty(None)\n    '''This is the object holding (current_tab's content is added to this)\n    the content of the current tab. To Listen to the changes in the content\n    of the current tab, you should bind to current_tabs `content` property.\n\n    :attr:`content` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to 'None'.\n    '''\n\n    _default_tab = ObjectProperty(None, allow_none=True)\n\n    def get_def_tab(self):\n        return self._default_tab\n\n    def set_def_tab(self, new_tab):\n        if not issubclass(new_tab.__class__, TabbedPanelHeader):\n            raise TabbedPanelException('`default_tab_class` should be\\\n                subclassed from `TabbedPanelHeader`')\n        if self._default_tab == new_tab:\n            return\n        oltab = self._default_tab\n        self._default_tab = new_tab\n        self.remove_widget(oltab)\n        self._original_tab = None\n        self.switch_to(new_tab)\n        new_tab.state = 'down'\n\n    default_tab = AliasProperty(get_def_tab, set_def_tab,\n                                bind=('_default_tab', ))\n    '''Holds the default tab.\n\n    .. Note:: For convenience, the automatically provided default tab is\n              deleted when you change default_tab to something else.\n              As of 1.5.0, this behaviour has been extended to every\n              `default_tab` for consistency and not just the automatically\n              provided one.\n\n    :attr:`default_tab` is an :class:`~kivy.properties.AliasProperty`.\n    '''\n\n    def get_def_tab_content(self):\n        return self.default_tab.content\n\n    def set_def_tab_content(self, *l):\n        self.default_tab.content = l[0]\n\n    default_tab_content = AliasProperty(get_def_tab_content,\n                                        set_def_tab_content)\n    '''Holds the default tab content.\n\n    :attr:`default_tab_content` is an :class:`~kivy.properties.AliasProperty`.\n    '''\n\n    def __init__(self, **kwargs):\n        # these variables need to be initialized before the kv lang is\n        # processed setup the base layout for the tabbed panel\n        self._childrens = []\n        self._tab_layout = StripLayout(rows=1)\n        self.rows = 1\n        self._tab_strip = TabbedPanelStrip(\n            tabbed_panel=self,\n            rows=1, cols=99, size_hint=(None, None),\n            height=self.tab_height, width=self.tab_width)\n\n        self._partial_update_scrollview = None\n        self.content = TabbedPanelContent()\n        self._current_tab = self._original_tab \\\n            = self._default_tab = TabbedPanelHeader()\n\n        super(TabbedPanel, self).__init__(**kwargs)\n\n        self.bind(size=self._reposition_tabs)\n        if not self.do_default_tab:\n            Clock.schedule_once(self._switch_to_first_tab)\n            return\n        self._setup_default_tab()\n        self.switch_to(self.default_tab)\n\n    def switch_to(self, header):\n        '''Switch to a specific panel header.\n        '''\n        header_content = header.content\n        self._current_tab.state = 'normal'\n        header.state = 'down'\n        self._current_tab = header\n        self.clear_widgets()\n        if header_content is None:\n            return\n        # if content has a previous parent remove it from that parent\n        parent = header_content.parent\n        if parent:\n            parent.remove_widget(header_content)\n        self.add_widget(header_content)\n\n    def clear_tabs(self, *l):\n        self_tabs = self._tab_strip\n        self_tabs.clear_widgets()\n        if self.do_default_tab:\n            self_default_tab = self._default_tab\n            self_tabs.add_widget(self_default_tab)\n            self_tabs.width = self_default_tab.width\n        self._reposition_tabs()\n\n    def add_widget(self, widget, index=0):\n        content = self.content\n        if content is None:\n            return\n        parent = widget.parent\n        if parent:\n            parent.remove_widget(widget)\n        if widget in (content, self._tab_layout):\n            super(TabbedPanel, self).add_widget(widget, index)\n        elif isinstance(widget, TabbedPanelHeader):\n            self_tabs = self._tab_strip\n            self_tabs.add_widget(widget, index)\n            widget.group = '__tab%r__' % self_tabs.uid\n            self.on_tab_width()\n        else:\n            widget.pos_hint = {'x': 0, 'top': 1}\n            self._childrens.append(widget)\n            content.disabled = self.current_tab.disabled\n            content.add_widget(widget, index)\n\n    def remove_widget(self, widget):\n        content = self.content\n        if content is None:\n            return\n        if widget in (content, self._tab_layout):\n            super(TabbedPanel, self).remove_widget(widget)\n        elif isinstance(widget, TabbedPanelHeader):\n            if not (self.do_default_tab and widget is self._default_tab):\n                self_tabs = self._tab_strip\n                self_tabs.width -= widget.width\n                self_tabs.remove_widget(widget)\n                if widget.state == 'down' and self.do_default_tab:\n                    self._default_tab.on_release()\n                self._reposition_tabs()\n            else:\n                Logger.info('TabbedPanel: default tab! can\\'t be removed.\\n' +\n                            'Change `default_tab` to a different tab.')\n        else:\n            self._childrens.pop(widget, None)\n            if widget in content.children:\n                content.remove_widget(widget)\n\n    def clear_widgets(self, **kwargs):\n        content = self.content\n        if content is None:\n            return\n        if kwargs.get('do_super', False):\n            super(TabbedPanel, self).clear_widgets()\n        else:\n            content.clear_widgets()\n\n    def on_strip_image(self, instance, value):\n        if not self._tab_layout:\n            return\n        self._tab_layout.background_image = value\n\n    def on_strip_border(self, instance, value):\n        if not self._tab_layout:\n            return\n        self._tab_layout.border = value\n\n    def on_do_default_tab(self, instance, value):\n        if not value:\n            dft = self.default_tab\n            if dft in self.tab_list:\n                self.remove_widget(dft)\n                self._switch_to_first_tab()\n                self._default_tab = self._current_tab\n        else:\n            self._current_tab.state = 'normal'\n            self._setup_default_tab()\n\n    def on_default_tab_text(self, *args):\n        self._default_tab.text = self.default_tab_text\n\n    def on_tab_width(self, *l):\n        Clock.unschedule(self._update_tab_width)\n        Clock.schedule_once(self._update_tab_width, 0)\n\n    def on_tab_height(self, *l):\n        self._tab_layout.height = self._tab_strip.height = self.tab_height\n        self._reposition_tabs()\n\n    def on_tab_pos(self, *l):\n        # ensure canvas\n        self._reposition_tabs()\n\n    def _setup_default_tab(self):\n        if self._default_tab in self.tab_list:\n            return\n        content = self._default_tab.content\n        _tabs = self._tab_strip\n        cls = self.default_tab_cls\n\n        if isinstance(cls, string_types):\n            cls = Factory.get(cls)\n\n        if not issubclass(cls, TabbedPanelHeader):\n            raise TabbedPanelException('`default_tab_class` should be\\\n                subclassed from `TabbedPanelHeader`')\n\n        # no need to instanciate if class is TabbedPanelHeader\n        if cls != TabbedPanelHeader:\n            self._current_tab = self._original_tab = self._default_tab = cls()\n\n        default_tab = self.default_tab\n        if self._original_tab == self.default_tab:\n            default_tab.text = self.default_tab_text\n\n        default_tab.height = self.tab_height\n        default_tab.group = '__tab%r__' % _tabs.uid\n        default_tab.state = 'down'\n        default_tab.width = self.tab_width if self.tab_width else 100\n        default_tab.content = content\n\n        tl = self.tab_list\n        if default_tab not in tl:\n            _tabs.add_widget(default_tab, len(tl))\n\n        if default_tab.content:\n            self.clear_widgets()\n            self.add_widget(self.default_tab.content)\n        else:\n            Clock.schedule_once(self._load_default_tab_content)\n        self._current_tab = default_tab\n\n    def _switch_to_first_tab(self, *l):\n        ltl = len(self.tab_list) - 1\n        if ltl > -1:\n            self._current_tab = dt = self._original_tab \\\n                = self.tab_list[ltl]\n            self.switch_to(dt)\n\n    def _load_default_tab_content(self, dt):\n        if self.default_tab:\n            self.switch_to(self.default_tab)\n\n    def _reposition_tabs(self, *l):\n        Clock.unschedule(self._update_tabs)\n        Clock.schedule_once(self._update_tabs, 0)\n\n    def _update_tabs(self, *l):\n        self_content = self.content\n        if not self_content:\n            return\n        # cache variables for faster access\n        tab_pos = self.tab_pos\n        tab_layout = self._tab_layout\n        tab_layout.clear_widgets()\n        scrl_v = ScrollView(size_hint=(None, 1))\n        tabs = self._tab_strip\n        parent = tabs.parent\n        if parent:\n            parent.remove_widget(tabs)\n        scrl_v.add_widget(tabs)\n        scrl_v.pos = (0, 0)\n        self_update_scrollview = self._update_scrollview\n\n        # update scrlv width when tab width changes depends on tab_pos\n        if self._partial_update_scrollview is not None:\n            tabs.unbind(width=self._partial_update_scrollview)\n        self._partial_update_scrollview = partial(\n            self_update_scrollview, scrl_v)\n        tabs.bind(width=self._partial_update_scrollview)\n\n        # remove all widgets from the tab_strip\n        self.clear_widgets(do_super=True)\n        tab_height = self.tab_height\n\n        widget_list = []\n        tab_list = []\n        pos_letter = tab_pos[0]\n        if pos_letter == 'b' or pos_letter == 't':\n            # bottom or top positions\n            # one col containing the tab_strip and the content\n            self.cols = 1\n            self.rows = 2\n            # tab_layout contains the scrollview containing tabs and two blank\n            # dummy widgets for spacing\n            tab_layout.rows = 1\n            tab_layout.cols = 3\n            tab_layout.size_hint = (1, None)\n            tab_layout.height = (tab_height + tab_layout.padding[1] +\n                                 tab_layout.padding[3] + dp(2))\n            self_update_scrollview(scrl_v)\n\n            if pos_letter == 'b':\n                # bottom\n                if tab_pos == 'bottom_mid':\n                    tab_list = (Widget(), scrl_v, Widget())\n                    widget_list = (self_content, tab_layout)\n                else:\n                    if tab_pos == 'bottom_left':\n                        tab_list = (scrl_v, Widget(), Widget())\n                    elif tab_pos == 'bottom_right':\n                        #add two dummy widgets\n                        tab_list = (Widget(), Widget(), scrl_v)\n                    widget_list = (self_content, tab_layout)\n            else:\n                # top\n                if tab_pos == 'top_mid':\n                    tab_list = (Widget(), scrl_v, Widget())\n                elif tab_pos == 'top_left':\n                    tab_list = (scrl_v, Widget(), Widget())\n                elif tab_pos == 'top_right':\n                    tab_list = (Widget(), Widget(), scrl_v)\n                widget_list = (tab_layout, self_content)\n        elif pos_letter == 'l' or pos_letter == 'r':\n            # left ot right positions\n            # one row containing the tab_strip and the content\n            self.cols = 2\n            self.rows = 1\n            # tab_layout contains two blank dummy widgets for spacing\n            # \"vertically\" and the scatter containing scrollview\n            # containing tabs\n            tab_layout.rows = 3\n            tab_layout.cols = 1\n            tab_layout.size_hint = (None, 1)\n            tab_layout.width = tab_height\n            scrl_v.height = tab_height\n            self_update_scrollview(scrl_v)\n\n            # rotate the scatter for vertical positions\n            rotation = 90 if tab_pos[0] == 'l' else -90\n            sctr = Scatter(do_translation=False,\n                           rotation=rotation,\n                           do_rotation=False,\n                           do_scale=False,\n                           size_hint=(None, None),\n                           auto_bring_to_front=False,\n                           size=scrl_v.size)\n            sctr.add_widget(scrl_v)\n\n            lentab_pos = len(tab_pos)\n\n            # Update scatter's top when it's pos changes.\n            # Needed for repositioning scatter to the correct place after its\n            # added to the parent. Use clock_schedule_once to ensure top is\n            # calculated after the parent's pos on canvas has been calculated.\n            # This is needed for when tab_pos changes to correctly position\n            # scatter. Without clock.schedule_once the positions would look\n            # fine but touch won't translate to the correct position\n\n            if tab_pos[lentab_pos - 4:] == '_top':\n                #on positions 'left_top' and 'right_top'\n                sctr.bind(pos=partial(self._update_top, sctr, 'top', None))\n                tab_list = (sctr, )\n            elif tab_pos[lentab_pos - 4:] == '_mid':\n                #calculate top of scatter\n                sctr.bind(pos=partial(self._update_top, sctr, 'mid',\n                                      scrl_v.width))\n                tab_list = (Widget(), sctr, Widget())\n            elif tab_pos[lentab_pos - 7:] == '_bottom':\n                tab_list = (Widget(), Widget(), sctr)\n\n            if pos_letter == 'l':\n                widget_list = (tab_layout, self_content)\n            else:\n                widget_list = (self_content, tab_layout)\n\n        # add widgets to tab_layout\n        add = tab_layout.add_widget\n        for widg in tab_list:\n            add(widg)\n\n        # add widgets to self\n        add = self.add_widget\n        for widg in widget_list:\n            add(widg)\n\n    def _update_tab_width(self, *l):\n        if self.tab_width:\n            for tab in self.tab_list:\n                tab.size_hint_x = 1\n            tsw = self.tab_width * len(self._tab_strip.children)\n        else:\n            # tab_width = None\n            tsw = 0\n            for tab in self.tab_list:\n                if tab.size_hint_x:\n                    # size_hint_x: x/.xyz\n                    tab.size_hint_x = 1\n                    #drop to default tab_width\n                    tsw += 100\n                else:\n                    # size_hint_x: None\n                    tsw += tab.width\n        self._tab_strip.width = tsw\n        self._reposition_tabs()\n\n    def _update_top(self, *args):\n        sctr, top, scrl_v_width, x, y = args\n        Clock.unschedule(partial(self._updt_top, sctr, top, scrl_v_width))\n        Clock.schedule_once(\n            partial(self._updt_top, sctr, top, scrl_v_width), 0)\n\n    def _updt_top(self, sctr, top, scrl_v_width, *args):\n        if top[0] == 't':\n            sctr.top = self.top\n        else:\n            sctr.top = self.top - (self.height - scrl_v_width) / 2\n\n    def _update_scrollview(self, scrl_v, *l):\n        self_tab_pos = self.tab_pos\n        self_tabs = self._tab_strip\n        if self_tab_pos[0] == 'b' or self_tab_pos[0] == 't':\n            #bottom or top\n            scrl_v.width = min(self.width, self_tabs.width)\n            #required for situations when scrl_v's pos is calculated\n            #when it has no parent\n            scrl_v.top += 1\n            scrl_v.top -= 1\n        else:\n            # left or right\n            scrl_v.width = min(self.height, self_tabs.width)\n            self_tabs.pos = (0, 0)\n"
  },
  {
    "path": "tickeys/kivy/uix/textinput.py",
    "content": "# -*- encoding: utf-8 -*-\n'''\nText Input\n==========\n\n.. versionadded:: 1.0.4\n\n.. image:: images/textinput-mono.jpg\n.. image:: images/textinput-multi.jpg\n\nThe :class:`TextInput` widget provides a box of editable plain text.\n\nUnicode, multiline, cursor navigation, selection and clipboard features\nare supported.\n\n.. note::\n\n    Two different coordinate systems are used with TextInput:\n\n        - (x, y) - coordinates in pixels, mostly used for rendering on screen.\n        - (row, col) - cursor index in characters / lines, used for selection\n          and cursor movement.\n\n\nUsage example\n-------------\n\nTo create a multiline textinput ('enter' key adds a new line)::\n\n    from kivy.uix.textinput import TextInput\n    textinput = TextInput(text='Hello world')\n\nTo create a singleline textinput, set the multiline property to False ('enter'\nkey will defocus the textinput and emit on_text_validate event)::\n\n    def on_enter(instance, value):\n        print('User pressed enter in', instance)\n\n    textinput = TextInput(text='Hello world', multiline=False)\n    textinput.bind(on_text_validate=on_enter)\n\nThe textinput's text is stored on its :attr:`TextInput.text` property. To run a\ncallback when the text changes::\n\n    def on_text(instance, value):\n        print('The widget', instance, 'have:', value)\n\n    textinput = TextInput()\n    textinput.bind(text=on_text)\n\nYou can 'focus' a textinput, meaning that the input box will be highlighted\nand keyboard focus will be requested::\n\n    textinput = TextInput(focus=True)\n\nThe textinput is defocused if the 'escape' key is pressed, or if another\nwidget requests the keyboard. You can bind a callback to the focus property to\nget notified of focus changes::\n\n    def on_focus(instance, value):\n        if value:\n            print('User focused', instance)\n        else:\n            print('User defocused', instance)\n\n    textinput = TextInput()\n    textinput.bind(focus=on_focus)\n\nSee :class:`~kivy.uix.behaviors.FocusBehavior` from which :class:`TextInput`\ninherits for more details.\n\n\nSelection\n---------\n\nThe selection is automatically updated when the cursor position changes.\nYou can get the currently selected text from the\n:attr:`TextInput.selection_text` property.\n\nFiltering\n---------\n\nYou can control which text can be added to the :class:`TextInput` by\noverwriting :meth:`TextInput.insert_text`.Every string that is typed, pasted\nor inserted by any other means to the :class:`TextInput` is passed through\nthis function. By overwriting it you can reject or change unwanted characters.\n\nFor example, to write only in capitalized characters::\n\n    class CapitalInput(TextInput):\n\n        def insert_text(self, substring, from_undo=False):\n            s = substring.upper()\n            return super(CapitalInput, self).insert_text(s,\\\n from_undo=from_undo)\n\nOr to only allow floats (0 - 9 and a single period)::\n\n    class FloatInput(TextInput):\n\n        pat = re.compile('[^0-9]')\n        def insert_text(self, substring, from_undo=False):\n            pat = self.pat\n            if '.' in self.text:\n                s = re.sub(pat, '', substring)\n            else:\n                s = '.'.join([re.sub(pat, '', s) for s in\\\n substring.split('.', 1)])\n            return super(FloatInput, self).insert_text(s, from_undo=from_undo)\n\nDefault shortcuts\n-----------------\n\n=============== ========================================================\n   Shortcuts    Description\n--------------- --------------------------------------------------------\nLeft            Move cursor to left\nRight           Move cursor to right\nUp              Move cursor to up\nDown            Move cursor to down\nHome            Move cursor at the beginning of the line\nEnd             Move cursor at the end of the line\nPageUp          Move cursor to 3 lines before\nPageDown        Move cursor to 3 lines after\nBackspace       Delete the selection or character before the cursor\nDel             Delete the selection of character after the cursor\nShift + <dir>   Start a text selection. Dir can be Up, Down, Left, Right\nControl + c     Copy selection\nControl + x     Cut selection\nControl + p     Paste selection\nControl + a     Select all the content\nControl + z     undo\nControl + r     redo\n=============== ========================================================\n\n'''\n\n\n__all__ = ('TextInput', )\n\n\nimport re\nimport sys\nfrom functools import partial\nfrom os import environ\nfrom weakref import ref\n\nfrom kivy.animation import Animation\nfrom kivy.base import EventLoop\nfrom kivy.cache import Cache\nfrom kivy.clock import Clock\nfrom kivy.config import Config\nfrom kivy.compat import PY2\nfrom kivy.logger import Logger\nfrom kivy.metrics import inch\nfrom kivy.utils import boundary, platform\nfrom kivy.uix.behaviors import FocusBehavior\n\nfrom kivy.core.text import Label\nfrom kivy.graphics import Color, Rectangle, PushMatrix, PopMatrix, Callback\nfrom kivy.graphics.context_instructions import Transform\nfrom kivy.graphics.texture import Texture\n\nfrom kivy.uix.widget import Widget\nfrom kivy.uix.bubble import Bubble\nfrom kivy.uix.behaviors import ButtonBehavior\nfrom kivy.uix.image import Image\n\nfrom kivy.properties import StringProperty, NumericProperty, \\\n    BooleanProperty, AliasProperty, \\\n    ListProperty, ObjectProperty, VariableListProperty, OptionProperty\n\nCache_register = Cache.register\nCache_append = Cache.append\nCache_get = Cache.get\nCache_remove = Cache.remove\nCache_register('textinput.label', timeout=60.)\nCache_register('textinput.width', timeout=60.)\n\nFL_IS_NEWLINE = 0x01\n\n# late binding\nClipboard = None\nMarkupLabel = None\n_platform = platform\n\n# for reloading, we need to keep a list of textinput to retrigger the rendering\n_textinput_list = []\n\n# cache the result\n_is_osx = sys.platform == 'darwin'\n\n# When we are generating documentation, Config doesn't exist\n_is_desktop = False\nif Config:\n    _is_desktop = Config.getboolean('kivy', 'desktop')\n\n# register an observer to clear the textinput cache when OpenGL will reload\nif 'KIVY_DOC' not in environ:\n\n    def _textinput_clear_cache(*l):\n        Cache_remove('textinput.label')\n        Cache_remove('textinput.width')\n        for wr in _textinput_list[:]:\n            textinput = wr()\n            if textinput is None:\n                _textinput_list.remove(wr)\n            else:\n                textinput._trigger_refresh_text()\n                textinput._refresh_hint_text()\n\n    from kivy.graphics.context import get_context\n    get_context().add_reload_observer(_textinput_clear_cache, True)\n\n\nclass Selector(ButtonBehavior, Image):\n    # Internal class for managing the selection Handles.\n\n    window = ObjectProperty()\n    target = ObjectProperty()\n    matrix = ObjectProperty()\n\n    def __init__(self, **kwargs):\n        super(Selector, self).__init__(**kwargs)\n        self.window.bind(on_touch_down=self.on_window_touch_down)\n        self.matrix = self.target.get_window_matrix()\n\n        with self.canvas.before:\n            Callback(self.update_transform)\n            PushMatrix()\n            self.transform = Transform()\n\n        with self.canvas.after:\n            PopMatrix()\n\n    def update_transform(self, cb):\n        m = self.target.get_window_matrix()\n        if self.matrix != m:\n            self.matrix = m\n            self.transform.identity()\n            self.transform.transform(self.matrix)\n\n    def transform_touch(self, touch):\n        matrix = self.matrix.inverse()\n        touch.apply_transform_2d(\n            lambda x, y: matrix.transform_point(x, y, 0)[:2])\n\n    def on_window_touch_down(self, win, touch):\n        if self.parent is not win:\n            return\n\n        try:\n            touch.push()\n            self.transform_touch(touch)\n            self._touch_diff = self.top - touch.y\n            if self.collide_point(*touch.pos):\n                FocusBehavior.ignored_touch.append(touch)\n            return super(Selector, self).on_touch_down(touch)\n        finally:\n            touch.pop()\n\n\nclass TextInputCutCopyPaste(Bubble):\n    # Internal class used for showing the little bubble popup when\n    # copy/cut/paste happen.\n\n    textinput = ObjectProperty(None)\n    ''' Holds a reference to the TextInput this Bubble belongs to.\n    '''\n\n    but_cut = ObjectProperty(None)\n    but_copy = ObjectProperty(None)\n    but_paste = ObjectProperty(None)\n    but_selectall = ObjectProperty(None)\n\n    matrix = ObjectProperty(None)\n\n    def __init__(self, **kwargs):\n        self.mode = 'normal'\n        super(TextInputCutCopyPaste, self).__init__(**kwargs)\n        Clock.schedule_interval(self._check_parent, .5)\n        self.matrix = self.textinput.get_window_matrix()\n\n        with self.canvas.before:\n            Callback(self.update_transform)\n            PushMatrix()\n            self.transform = Transform()\n\n        with self.canvas.after:\n            PopMatrix()\n\n    def update_transform(self, cb):\n        m = self.textinput.get_window_matrix()\n        if self.matrix != m:\n            self.matrix = m\n            self.transform.identity()\n            self.transform.transform(self.matrix)\n\n    def transform_touch(self, touch):\n        matrix = self.matrix.inverse()\n        touch.apply_transform_2d(\n            lambda x, y: matrix.transform_point(x, y, 0)[:2])\n\n    def on_touch_down(self, touch):\n        try:\n            touch.push()\n            self.transform_touch(touch)\n            if self.collide_point(*touch.pos):\n                FocusBehavior.ignored_touch.append(touch)\n            return super(TextInputCutCopyPaste, self).on_touch_down(touch)\n        finally:\n            touch.pop()\n\n    def on_textinput(self, instance, value):\n        global Clipboard\n        if value and not Clipboard and not _is_desktop:\n            value._ensure_clipboard()\n\n    def _check_parent(self, dt):\n        # this is a prevention to get the Bubble staying on the screen, if the\n        # attached textinput is not on the screen anymore.\n        parent = self.textinput\n        while parent is not None:\n            if parent == parent.parent:\n                break\n            parent = parent.parent\n        if parent is None:\n            Clock.unschedule(self._check_parent)\n            if self.textinput:\n                self.textinput._hide_cut_copy_paste()\n\n    def on_parent(self, instance, value):\n        parent = self.textinput\n        mode = self.mode\n\n        if parent:\n            self.clear_widgets()\n            if mode == 'paste':\n                # show only paste on long touch\n                self.but_selectall.opacity = 1\n                widget_list = [self.but_selectall, ]\n                if not parent.readonly:\n                    widget_list.append(self.but_paste)\n            elif parent.readonly:\n                # show only copy for read only text input\n                widget_list = (self.but_copy, )\n            else:\n                # normal mode\n                widget_list = (self.but_cut, self.but_copy, self.but_paste)\n\n            for widget in widget_list:\n                self.add_widget(widget)\n\n    def do(self, action):\n        textinput = self.textinput\n\n        if action == 'cut':\n            textinput._cut(textinput.selection_text)\n        elif action == 'copy':\n            textinput.copy()\n        elif action == 'paste':\n            textinput.paste()\n        elif action == 'selectall':\n            textinput.select_all()\n            self.mode = ''\n            anim = Animation(opacity=0, d=.333)\n            anim.bind(on_complete=lambda *args:\n                      self.on_parent(self, self.parent))\n            anim.start(self.but_selectall)\n            return\n\n        self.hide()\n\n    def hide(self):\n        parent = self.parent\n        if not parent:\n            return\n\n        anim = Animation(opacity=0, d=.225)\n        anim.bind(on_complete=lambda *args: parent.remove_widget(self))\n        anim.start(self)\n\n\nclass TextInput(FocusBehavior, Widget):\n    '''TextInput class. See module documentation for more information.\n\n    :Events:\n        `on_text_validate`\n            Fired only in multiline=False mode when the user hits 'enter'.\n            This will also unfocus the textinput.\n        `on_double_tap`\n            Fired when a double tap happens in the text input. The default\n            behavior selects the text around the cursor position. More info at\n            :meth:`on_double_tap`.\n        `on_triple_tap`\n            Fired when a triple tap happens in the text input. The default\n            behavior selects the line around the cursor position. More info at\n            :meth:`on_triple_tap`.\n        `on_quad_touch`\n            Fired when four fingers are touching the text input. The default\n            behavior selects the whole text. More info at\n            :meth:`on_quad_touch`.\n\n    .. warning::\n        When changing a :class:`TextInput` property that requires re-drawing,\n        e.g. modifying the :attr:`text`, the updates occur on the next\n        clock cycle and not instantly. This might cause any changes to the\n        :class:`TextInput` that occur between the modification and the next\n        cycle to be ignored, or to use previous values. For example, after\n        a update to the :attr:`text`, changing the cursor in the same clock\n        frame will move it using the previous text and will likely end up in an\n        incorrect position. The solution is to schedule any updates to occur\n        on the next clock cycle using\n        :meth:`~kivy.clock.ClockBase.schedule_once`.\n\n    .. Note::\n        Selection is cancelled when TextInput is focused. If you need to\n        show selection when TextInput is focused, you should delay\n        (use Clock.schedule) the call to the functions for selecting\n        text (select_all, select_text).\n\n    .. versionchanged:: 1.9.0\n        :class:`TextInput` now inherits from\n        :class:`~kivy.uix.behaviors.FocusBehavior`.\n\n        :attr:`~kivy.uix.behaviors.FocusBehavior.keyboard_mode`,\n        :meth:`~kivy.uix.behaviors.FocusBehavior.show_keyboard`,\n        :meth:`~kivy.uix.behaviors.FocusBehavior.hide_keyboard`,\n        :meth:`~kivy.uix.behaviors.FocusBehavior.focus`,\n        and :attr:`~kivy.uix.behaviors.FocusBehavior.input_type`,\n        have been removed from :class:`TextInput` since they already inherit\n        them from :class:`~kivy.uix.behaviors.FocusBehavior`.\n\n    .. versionchanged:: 1.7.0\n        `on_double_tap`, `on_triple_tap` and `on_quad_touch` events added.\n    '''\n\n    __events__ = ('on_text_validate', 'on_double_tap', 'on_triple_tap',\n                  'on_quad_touch')\n\n    def __init__(self, **kwargs):\n        self.is_focusable = kwargs.get('is_focusable', True)\n        self._cursor_blink_time = Clock.get_time()\n        self._cursor = [0, 0]\n        self._selection = False\n        self._selection_finished = True\n        self._selection_touch = None\n        self.selection_text = u''\n        self._selection_from = None\n        self._selection_to = None\n        self._handle_left = None\n        self._handle_right = None\n        self._handle_middle = None\n        self._bubble = None\n        self._lines_flags = []\n        self._lines_labels = []\n        self._lines_rects = []\n        self._hint_text_flags = []\n        self._hint_text_labels = []\n        self._hint_text_rects = []\n        self._label_cached = None\n        self._line_options = None\n        self._keyboard_mode = Config.get('kivy', 'keyboard_mode')\n        self._command_mode = False\n        self._command = ''\n        self.reset_undo()\n        self._touch_count = 0\n        self.interesting_keys = {\n            8: 'backspace',\n            13: 'enter',\n            127: 'del',\n            271: 'enter',\n            273: 'cursor_up',\n            274: 'cursor_down',\n            275: 'cursor_right',\n            276: 'cursor_left',\n            278: 'cursor_home',\n            279: 'cursor_end',\n            280: 'cursor_pgup',\n            281: 'cursor_pgdown',\n            303: 'shift_L',\n            304: 'shift_R'}\n\n        super(TextInput, self).__init__(**kwargs)\n\n        self.bind(font_size=self._trigger_refresh_line_options,\n                  font_name=self._trigger_refresh_line_options)\n\n        def handle_readonly(instance, value):\n            if value and (not _is_desktop or not self.allow_copy):\n                self.is_focusable = False\n\n        self.bind(padding=self._update_text_options,\n                  tab_width=self._update_text_options,\n                  font_size=self._update_text_options,\n                  font_name=self._update_text_options,\n                  size=self._update_text_options,\n                  password=self._update_text_options)\n\n        self.bind(pos=self._trigger_update_graphics,\n                  readonly=handle_readonly, focus=self._on_textinput_focused)\n        handle_readonly(self, self.readonly)\n\n        self._trigger_position_handles = Clock.create_trigger(\n            self._position_handles)\n        self._trigger_show_handles = Clock.create_trigger(\n            self._show_handles, .05)\n        self._trigger_refresh_line_options()\n        self._trigger_refresh_text()\n\n        self.bind(pos=self._trigger_position_handles,\n                  size=self._trigger_position_handles)\n\n        # when the gl context is reloaded, trigger the text rendering again.\n        _textinput_list.append(ref(self, TextInput._reload_remove_observer))\n\n    def on_text_validate(self):\n        pass\n\n    def cursor_index(self, cursor=None):\n        '''Return the cursor index in the text/value.\n        '''\n        if not cursor:\n            cursor = self.cursor\n        try:\n            l = self._lines\n            if len(l) == 0:\n                return 0\n            lf = self._lines_flags\n            index, cr = cursor\n            for row in range(cr):\n                if row >= len(l):\n                    continue\n                index += len(l[row])\n                if lf[row] & FL_IS_NEWLINE:\n                    index += 1\n            if lf[cr] & FL_IS_NEWLINE:\n                index += 1\n            return index\n        except IndexError:\n            return 0\n\n    def cursor_offset(self):\n        '''Get the cursor x offset on the current line.\n        '''\n        offset = 0\n        row = self.cursor_row\n        col = self.cursor_col\n        _lines = self._lines\n        if col and row < len(_lines):\n            offset = self._get_text_width(\n                _lines[row][:col], self.tab_width,\n                self._label_cached)\n        return offset\n\n    def get_cursor_from_index(self, index):\n        '''Return the (row, col) of the cursor from text index.\n        '''\n        index = boundary(index, 0, len(self.text))\n        if index <= 0:\n            return 0, 0\n        lf = self._lines_flags\n        l = self._lines\n        i = 0\n        for row in range(len(l)):\n            ni = i + len(l[row])\n            if lf[row] & FL_IS_NEWLINE:\n                ni += 1\n                i += 1\n            if ni >= index:\n                return index - i, row\n            i = ni\n        return index, row\n\n    def select_text(self, start, end):\n        ''' Select a portion of text displayed in this TextInput.\n\n        .. versionadded:: 1.4.0\n\n        :Parameters:\n            `start`\n                Index of textinput.text from where to start selection\n            `end`\n                Index of textinput.text till which the selection should be\n                displayed\n        '''\n        if end < start:\n            raise Exception('end must be superior to start')\n        m = len(self.text)\n        self._selection_from = boundary(start, 0, m)\n        self._selection_to = boundary(end, 0, m)\n        self._selection_finished = True\n        self._update_selection(True)\n        self._update_graphics_selection()\n\n    def select_all(self):\n        ''' Select all of the text displayed in this TextInput.\n\n        .. versionadded:: 1.4.0\n        '''\n        self.select_text(0, len(self.text))\n\n    re_indent = re.compile('^(\\s*|)')\n\n    def _auto_indent(self, substring):\n        index = self.cursor_index()\n        _text = self._get_text(encode=False)\n        if index > 0:\n            line_start = _text.rfind('\\n', 0, index)\n            if line_start > -1:\n                line = _text[line_start + 1:index]\n                indent = self.re_indent.match(line).group()\n                substring += indent\n        return substring\n\n    def insert_text(self, substring, from_undo=False):\n        '''Insert new text at the current cursor position. Override this\n        function in order to pre-process text for input validation.\n        '''\n        if self.readonly or not substring:\n            return\n\n        mode = self.input_filter\n        if mode is not None:\n            chr = type(substring)\n            if chr is bytes:\n                int_pat = self._insert_int_patb\n            else:\n                int_pat = self._insert_int_patu\n\n            if mode == 'int':\n                substring = re.sub(int_pat, chr(''), substring)\n            elif mode == 'float':\n                if '.' in self.text:\n                    substring = re.sub(int_pat, chr(''), substring)\n                else:\n                    substring = '.'.join([re.sub(int_pat, chr(''), k) for k\n                                          in substring.split(chr('.'), 1)])\n            else:\n                substring = mode(substring, from_undo)\n            if not substring:\n                return\n\n        self._hide_handles(EventLoop.window)\n\n        if not from_undo and self.multiline and self.auto_indent \\\n                and substring == u'\\n':\n            substring = self._auto_indent(substring)\n\n        cc, cr = self.cursor\n        sci = self.cursor_index\n        ci = sci()\n        text = self._lines[cr]\n        len_str = len(substring)\n        new_text = text[:cc] + substring + text[cc:]\n        self._set_line_text(cr, new_text)\n\n        wrap = (self._get_text_width(\n            new_text,\n            self.tab_width,\n            self._label_cached) > self.width)\n        if len_str > 1 or substring == u'\\n' or wrap:\n            # Avoid refreshing text on every keystroke.\n            # Allows for faster typing of text when the amount of text in\n            # TextInput gets large.\n\n            start, finish, lines,\\\n                lineflags, len_lines = self._get_line_from_cursor(cr, new_text)\n            # calling trigger here could lead to wrong cursor positioning\n            # and repeating of text when keys are added rapidly in a automated\n            # fashion. From Android Keyboard for example.\n            self._refresh_text_from_property('insert', start, finish, lines,\n                                             lineflags, len_lines)\n\n        self.cursor = self.get_cursor_from_index(ci + len_str)\n        # handle undo and redo\n        self._set_unredo_insert(ci, ci + len_str, substring, from_undo)\n\n    def _get_line_from_cursor(self, start, new_text):\n        # get current paragraph from cursor position\n        finish = start\n        lines = self._lines\n        linesflags = self._lines_flags\n        if start and not linesflags[start]:\n            start -= 1\n            new_text = u''.join((lines[start], new_text))\n        try:\n            while not linesflags[finish + 1]:\n                new_text = u''.join((new_text, lines[finish + 1]))\n                finish += 1\n        except IndexError:\n            pass\n        lines, lineflags = self._split_smart(new_text)\n        len_lines = max(1, len(lines))\n        return start, finish, lines, lineflags, len_lines\n\n    def _set_unredo_insert(self, ci, sci, substring, from_undo):\n        # handle undo and redo\n        if from_undo:\n            return\n        self._undo.append({'undo_command': ('insert', ci, sci),\n                           'redo_command': (ci, substring)})\n        # reset redo when undo is appended to\n        self._redo = []\n\n    def reset_undo(self):\n        '''Reset undo and redo lists from memory.\n\n        .. versionadded:: 1.3.0\n\n        '''\n        self._redo = self._undo = []\n\n    def do_redo(self):\n        '''Do redo operation.\n\n        .. versionadded:: 1.3.0\n\n        This action re-does any command that has been un-done by\n        do_undo/ctrl+z. This function is automatically called when\n        `ctrl+r` keys are pressed.\n        '''\n        try:\n            x_item = self._redo.pop()\n            undo_type = x_item['undo_command'][0]\n            _get_cusror_from_index = self.get_cursor_from_index\n\n            if undo_type == 'insert':\n                ci, substring = x_item['redo_command']\n                self.cursor = _get_cusror_from_index(ci)\n                self.insert_text(substring, True)\n            elif undo_type == 'bkspc':\n                self.cursor = _get_cusror_from_index(x_item['redo_command'])\n                self.do_backspace(from_undo=True)\n            else:\n                # delsel\n                ci, sci = x_item['redo_command']\n                self._selection_from = ci\n                self._selection_to = sci\n                self._selection = True\n                self.delete_selection(True)\n                self.cursor = _get_cusror_from_index(ci)\n            self._undo.append(x_item)\n        except IndexError:\n            # reached at top of undo list\n            pass\n\n    def do_undo(self):\n        '''Do undo operation.\n\n        .. versionadded:: 1.3.0\n\n        This action un-does any edits that have been made since the last\n        call to reset_undo().\n        This function is automatically called when `ctrl+z` keys are pressed.\n        '''\n        try:\n            x_item = self._undo.pop()\n            undo_type = x_item['undo_command'][0]\n            self.cursor = self.get_cursor_from_index(x_item['undo_command'][1])\n\n            if undo_type == 'insert':\n                ci, sci = x_item['undo_command'][1:]\n                self._selection_from = ci\n                self._selection_to = sci\n                self._selection = True\n                self.delete_selection(True)\n            elif undo_type == 'bkspc':\n                substring = x_item['undo_command'][2:][0]\n                self.insert_text(substring, True)\n            else:\n                # delsel\n                substring = x_item['undo_command'][2:][0]\n                self.insert_text(substring, True)\n            self._redo.append(x_item)\n        except IndexError:\n            # reached at top of undo list\n            pass\n\n    def do_backspace(self, from_undo=False, mode='bkspc'):\n        '''Do backspace operation from the current cursor position.\n        This action might do several things:\n\n            - removing the current selection if available.\n            - removing the previous char and move the cursor back.\n            - do nothing, if we are at the start.\n\n        '''\n        if self.readonly:\n            return\n        cc, cr = self.cursor\n        _lines = self._lines\n        text = _lines[cr]\n        cursor_index = self.cursor_index()\n        text_last_line = _lines[cr - 1]\n\n        if cc == 0 and cr == 0:\n            return\n        _lines_flags = self._lines_flags\n        start = cr\n        if cc == 0:\n            substring = u'\\n' if _lines_flags[cr] else u' '\n            new_text = text_last_line + text\n            self._set_line_text(cr - 1, new_text)\n            self._delete_line(cr)\n            start = cr - 1\n        else:\n            #ch = text[cc-1]\n            substring = text[cc - 1]\n            new_text = text[:cc - 1] + text[cc:]\n            self._set_line_text(cr, new_text)\n\n        # refresh just the current line instead of the whole text\n        start, finish, lines, lineflags, len_lines =\\\n            self._get_line_from_cursor(start, new_text)\n        # avoid trigger refresh, leads to issue with\n        # keys/text send rapidly through code.\n        self._refresh_text_from_property('del', start, finish, lines,\n                                         lineflags, len_lines)\n\n        self.cursor = self.get_cursor_from_index(cursor_index - 1)\n        # handle undo and redo\n        self._set_undo_redo_bkspc(\n            cursor_index,\n            cursor_index - 1,\n            substring, from_undo)\n\n    def _set_undo_redo_bkspc(self, ol_index, new_index, substring, from_undo):\n        # handle undo and redo for backspace\n        if from_undo:\n            return\n        self._undo.append({\n            'undo_command': ('bkspc', new_index, substring),\n            'redo_command': ol_index})\n        #reset redo when undo is appended to\n        self._redo = []\n\n    def do_cursor_movement(self, action):\n        '''Move the cursor relative to it's current position.\n        Action can be one of :\n\n            - cursor_left: move the cursor to the left\n            - cursor_right: move the cursor to the right\n            - cursor_up: move the cursor on the previous line\n            - cursor_down: move the cursor on the next line\n            - cursor_home: move the cursor at the start of the current line\n            - cursor_end: move the cursor at the end of current line\n            - cursor_pgup: move one \"page\" before\n            - cursor_pgdown: move one \"page\" after\n\n        '''\n        pgmove_speed = int(self.height /\n            (self.line_height + self.line_spacing) - 1)\n        col, row = self.cursor\n        if action == 'cursor_up':\n            row = max(row - 1, 0)\n            col = min(len(self._lines[row]), col)\n        elif action == 'cursor_down':\n            row = min(row + 1, len(self._lines) - 1)\n            col = min(len(self._lines[row]), col)\n        elif action == 'cursor_left':\n            if col == 0:\n                if row:\n                    row -= 1\n                    col = len(self._lines[row])\n            else:\n                col, row = col - 1, row\n        elif action == 'cursor_right':\n            if col == len(self._lines[row]):\n                if row < len(self._lines) - 1:\n                    col = 0\n                    row += 1\n            else:\n                col, row = col + 1, row\n        elif action == 'cursor_home':\n            col = 0\n        elif action == 'cursor_end':\n            col = len(self._lines[row])\n        elif action == 'cursor_pgup':\n            row = max(0, row - pgmove_speed)\n            col = min(len(self._lines[row]), col)\n        elif action == 'cursor_pgdown':\n            row = min(row + pgmove_speed, len(self._lines) - 1)\n            col = min(len(self._lines[row]), col)\n        self.cursor = (col, row)\n\n    def get_cursor_from_xy(self, x, y):\n        '''Return the (row, col) of the cursor from an (x, y) position.\n        '''\n        padding_left = self.padding[0]\n        padding_top = self.padding[1]\n        l = self._lines\n        dy = self.line_height + self.line_spacing\n        cx = x - self.x\n        scrl_y = self.scroll_y\n        scrl_x = self.scroll_x\n        scrl_y = scrl_y / dy if scrl_y > 0 else 0\n        cy = (self.top - padding_top + scrl_y * dy) - y\n        cy = int(boundary(round(cy / dy - 0.5), 0, len(l) - 1))\n        dcx = 0\n        _get_text_width = self._get_text_width\n        _tab_width = self.tab_width\n        _label_cached = self._label_cached\n        for i in range(1, len(l[cy]) + 1):\n            if _get_text_width(l[cy][:i],\n                               _tab_width,\n                               _label_cached) + padding_left >= cx + scrl_x:\n                break\n            dcx = i\n        cx = dcx\n        return cx, cy\n\n    #\n    # Selection control\n    #\n    def cancel_selection(self):\n        '''Cancel current selection (if any).\n        '''\n        self._selection_from = self._selection_to = self.cursor_index()\n        self._selection = False\n        self._selection_finished = True\n        self._selection_touch = None\n        self._trigger_update_graphics()\n\n    def delete_selection(self, from_undo=False):\n        '''Delete the current text selection (if any).\n        '''\n        if self.readonly:\n            return\n        self._hide_handles(EventLoop.window)\n        scrl_x = self.scroll_x\n        scrl_y = self.scroll_y\n        cc, cr = self.cursor\n        if not self._selection:\n            return\n        v = self._get_text(encode=False)\n        a, b = self._selection_from, self._selection_to\n        if a > b:\n            a, b = b, a\n        self.cursor = cursor = self.get_cursor_from_index(a)\n        start = cursor\n        finish = self.get_cursor_from_index(b)\n        cur_line = self._lines[start[1]][:start[0]] +\\\n            self._lines[finish[1]][finish[0]:]\n        lines, lineflags = self._split_smart(cur_line)\n        len_lines = len(lines)\n        if start[1] == finish[1]:\n            self._set_line_text(start[1], cur_line)\n        else:\n            self._refresh_text_from_property('del', start[1], finish[1], lines,\n                                             lineflags, len_lines)\n        self.scroll_x = scrl_x\n        self.scroll_y = scrl_y\n        # handle undo and redo for delete selecttion\n        self._set_unredo_delsel(a, b, v[a:b], from_undo)\n        self.cancel_selection()\n\n    def _set_unredo_delsel(self, a, b, substring, from_undo):\n        # handle undo and redo for backspace\n        if from_undo:\n            return\n\n        self._undo.append({\n            'undo_command': ('delsel', a, substring),\n            'redo_command': (a, b)})\n        # reset redo when undo is appended to\n        self._redo = []\n\n    def _update_selection(self, finished=False):\n        '''Update selection text and order of from/to if finished is True.\n        Can be called multiple times until finished is True.\n        '''\n        a, b = self._selection_from, self._selection_to\n        if a > b:\n            a, b = b, a\n        self._selection_finished = finished\n        _selection_text = self._get_text(encode=False)[a:b]\n        self.selection_text = (\"\" if not self.allow_copy else\n                               (('*' * (b - a)) if self.password else\n                                _selection_text))\n        if not finished:\n            self._selection = True\n        else:\n            self._selection = bool(len(_selection_text))\n            self._selection_touch = None\n        if a == 0:\n            # update graphics only on new line\n            # allows smoother scrolling, noticeably\n            # faster when dealing with large text.\n            self._update_graphics_selection()\n            #self._trigger_update_graphics()\n\n    #\n    # Touch control\n    #\n    def long_touch(self, dt):\n        if self._selection_to == self._selection_from:\n            pos = self.to_local(*self._long_touch_pos, relative=True)\n            self._show_cut_copy_paste(\n                pos, EventLoop.window, mode='paste')\n\n    def on_double_tap(self):\n        '''This event is dispatched when a double tap happens\n        inside TextInput. The default behavior is to select the\n        word around the current cursor position. Override this to provide\n        different behavior. Alternatively, you can bind to this\n        event to provide additional functionality.\n        '''\n        ci = self.cursor_index()\n        cc = self.cursor_col\n        line = self._lines[self.cursor_row]\n        len_line = len(line)\n        start = max(0, len(line[:cc]) - line[:cc].rfind(u' ') - 1)\n        end = line[cc:].find(u' ')\n        end = end if end > - 1 else (len_line - cc)\n        Clock.schedule_once(lambda dt: self.select_text(ci - start, ci + end))\n\n    def on_triple_tap(self):\n        '''This event is dispatched when a triple tap happens\n        inside TextInput. The default behavior is to select the\n        line around current cursor position. Override this to provide\n        different behavior. Alternatively, you can bind to this\n        event to provide additional functionality.\n        '''\n        ci = self.cursor_index()\n        cc = self.cursor_col\n        line = self._lines[self.cursor_row]\n        len_line = len(line)\n        Clock.schedule_once(lambda dt:\n                            self.select_text(ci - cc, ci + (len_line - cc)))\n\n    def on_quad_touch(self):\n        '''This event is dispatched when four fingers are touching\n        inside TextInput. The default behavior is to select all text.\n        Override this to provide different behavior. Alternatively,\n        you can bind to this event to provide additional functionality.\n        '''\n        Clock.schedule_once(lambda dt: self.select_all())\n\n    def on_touch_down(self, touch):\n        if self.disabled:\n            return\n\n        touch_pos = touch.pos\n        if not self.collide_point(*touch_pos):\n            return False\n        if super(TextInput, self).on_touch_down(touch):\n            return True\n\n        # Check for scroll wheel\n        if 'button' in touch.profile and touch.button.startswith('scroll'):\n            scroll_type = touch.button[6:]\n            if scroll_type == 'down':\n                if self.multiline:\n                    if self.scroll_y <= 0:\n                        return\n                    self.scroll_y -= self.line_height\n                else:\n                    if self.scroll_x <= 0:\n                        return\n                    self.scroll_x -= self.line_height\n            if scroll_type == 'up':\n                if self.multiline:\n                    if (self._lines_rects[-1].pos[1] > self.y +\n                        self.line_height):\n                        return\n                    self.scroll_y += self.line_height\n                else:\n                    if (self.scroll_x + self.width >=\n                        self._lines_rects[-1].texture.size[0]):\n                        return\n                    self.scroll_x += self.line_height\n\n        touch.grab(self)\n        self._touch_count += 1\n        if touch.is_double_tap:\n            self.dispatch('on_double_tap')\n        if touch.is_triple_tap:\n            self.dispatch('on_triple_tap')\n        if self._touch_count == 4:\n            self.dispatch('on_quad_touch')\n\n        self._hide_cut_copy_paste(EventLoop.window)\n        # schedule long touch for paste\n        self._long_touch_pos = touch.pos\n        Clock.schedule_once(self.long_touch, .5)\n\n        self.cursor = self.get_cursor_from_xy(*touch_pos)\n        if not self._selection_touch:\n            self.cancel_selection()\n            self._selection_touch = touch\n            self._selection_from = self._selection_to = self.cursor_index()\n            self._update_selection()\n        return False\n\n    def on_touch_move(self, touch):\n        if touch.grab_current is not self:\n            return\n        if not self.focus:\n            touch.ungrab(self)\n            if self._selection_touch is touch:\n                self._selection_touch = None\n            return False\n        if self._selection_touch is touch:\n            self.cursor = self.get_cursor_from_xy(touch.x, touch.y)\n            self._selection_to = self.cursor_index()\n            self._update_selection()\n            return True\n\n    def on_touch_up(self, touch):\n        if touch.grab_current is not self:\n            return\n        touch.ungrab(self)\n        self._touch_count -= 1\n\n        # schedule long touch for paste\n        Clock.unschedule(self.long_touch)\n\n        if not self.focus:\n            return False\n\n        if self._selection_touch is touch:\n            self._selection_to = self.cursor_index()\n            self._update_selection(True)\n            # show Bubble\n            win = EventLoop.window\n            if self._selection_to != self._selection_from:\n                self._show_cut_copy_paste(touch.pos, win)\n            elif self.use_handles:\n                self._hide_handles()\n                handle_middle = self._handle_middle\n                if handle_middle is None:\n                    self._handle_middle = handle_middle = Selector(\n                        source=self.handle_image_middle,\n                        window=win,\n                        target=self,\n                        size_hint=(None, None),\n                        size=('45dp', '45dp'))\n                    handle_middle.bind(on_press=self._handle_pressed,\n                                       on_touch_move=self._handle_move,\n                                       on_release=self._handle_released)\n                if not self._handle_middle.parent and self.text:\n                    EventLoop.window.add_widget(handle_middle, canvas='after')\n                self._position_handles(mode='middle')\n            return True\n\n    def _handle_pressed(self, instance):\n        self._hide_cut_copy_paste()\n        sf, st = self._selection_from, self.selection_to\n        if sf > st:\n            self._selection_from, self._selection_to = st, sf\n\n    def _handle_released(self, instance):\n        sf, st = self._selection_from, self.selection_to\n        if sf == st:\n            return\n\n        self._update_selection()\n        self._show_cut_copy_paste(\n            (instance.right if instance is self._handle_left else instance.x,\n             instance.top + self.line_height),\n            EventLoop.window)\n\n    def _handle_move(self, instance, touch):\n        if touch.grab_current != instance:\n            return\n        get_cursor = self.get_cursor_from_xy\n        handle_right = self._handle_right\n        handle_left = self._handle_left\n        handle_middle = self._handle_middle\n\n        try:\n            touch.push()\n            touch.apply_transform_2d(self.to_widget)\n            x, y = touch.pos\n        finally:\n            touch.pop()\n\n        cursor = get_cursor(\n            x,\n            y + instance._touch_diff + (self.line_height / 2))\n\n        if instance != touch.grab_current:\n            return\n\n        if instance == handle_middle:\n            self.cursor = cursor\n            self._position_handles(mode='middle')\n            return\n\n        ci = self.cursor_index(cursor=cursor)\n        sf, st = self._selection_from, self.selection_to\n\n        if instance == handle_left:\n            self._selection_from = ci\n        elif instance == handle_right:\n            self._selection_to = ci\n        self._trigger_update_graphics()\n        self._trigger_position_handles()\n\n    def _position_handles(self, *args, **kwargs):\n        if not self.text:\n            return\n        mode = kwargs.get('mode', 'both')\n\n        lh = self.line_height\n\n        handle_middle = self._handle_middle\n        if handle_middle:\n            hp_mid = self.cursor_pos\n            pos = self.to_local(*hp_mid, relative=True)\n            handle_middle.x = pos[0] - handle_middle.width / 2\n            handle_middle.top = pos[1] - lh\n        if mode[0] == 'm':\n            return\n\n        group = self.canvas.get_group('selection')\n        if not group:\n            return\n\n        EventLoop.window.remove_widget(self._handle_middle)\n\n        handle_left = self._handle_left\n        if not handle_left:\n            return\n        hp_left = group[2].pos\n        handle_left.pos = self.to_local(*hp_left, relative=True)\n        handle_left.x -= handle_left.width\n        handle_left.y -= handle_left.height\n\n        handle_right = self._handle_right\n        last_rect = group[-1]\n        hp_right = last_rect.pos[0], last_rect.pos[1]\n        x, y = self.to_local(*hp_right, relative=True)\n        handle_right.x = x + last_rect.size[0]\n        handle_right.y = y - handle_right.height\n\n    def _hide_handles(self, win=None):\n        win = win or EventLoop.window\n        if win is None:\n            return\n        win.remove_widget(self._handle_right)\n        win.remove_widget(self._handle_left)\n        win.remove_widget(self._handle_middle)\n\n    def _show_handles(self, dt):\n        if not self.use_handles or not self.text:\n            return\n\n        win = EventLoop.window\n\n        handle_right = self._handle_right\n        handle_left = self._handle_left\n        if self._handle_left is None:\n            self._handle_left = handle_left = Selector(\n                source=self.handle_image_left,\n                target=self,\n                window=win,\n                size_hint=(None, None),\n                size=('45dp', '45dp'))\n            handle_left.bind(on_press=self._handle_pressed,\n                             on_touch_move=self._handle_move,\n                             on_release=self._handle_released)\n            self._handle_right = handle_right = Selector(\n                source=self.handle_image_right,\n                target=self,\n                window=win,\n                size_hint=(None, None),\n                size=('45dp', '45dp'))\n            handle_right.bind(on_press=self._handle_pressed,\n                              on_touch_move=self._handle_move,\n                              on_release=self._handle_released)\n        else:\n            if self._handle_left.parent:\n                self._position_handles()\n                return\n            if not self.parent:\n                return\n\n        self._trigger_position_handles()\n        if self.selection_from != self.selection_to:\n            self._handle_left.opacity = self._handle_right.opacity = 0\n            win.add_widget(self._handle_left, canvas='after')\n            win.add_widget(self._handle_right, canvas='after')\n            anim = Animation(opacity=1, d=.4)\n            anim.start(self._handle_right)\n            anim.start(self._handle_left)\n\n    def _show_cut_copy_paste(self, pos, win, parent_changed=False,\n                             mode='', pos_in_window=False, *l):\n        # Show a bubble with cut copy and paste buttons\n        if not self.use_bubble:\n            return\n\n        bubble = self._bubble\n        if bubble is None:\n            self._bubble = bubble = TextInputCutCopyPaste(textinput=self)\n            self.bind(parent=partial(self._show_cut_copy_paste,\n                                     pos, win, True))\n            win.bind(\n                size=lambda *args: self._hide_cut_copy_paste(win))\n            self.bind(cursor_pos=lambda *args: self._hide_cut_copy_paste(win))\n        else:\n            win.remove_widget(bubble)\n            if not self.parent:\n                return\n        if parent_changed:\n            return\n\n        # Search the position from the touch to the window\n        lh, ls = self.line_height, self.line_spacing\n\n        x, y = pos\n        t_pos = (x, y) if pos_in_window else self.to_window(x, y)\n        bubble_size = bubble.size\n        bubble_hw = bubble_size[0] / 2.\n        win_size = win.size\n        bubble_pos = (t_pos[0], t_pos[1] + inch(.25))\n\n        if (bubble_pos[0] - bubble_hw) < 0:\n            # bubble beyond left of window\n            if bubble_pos[1] > (win_size[1] - bubble_size[1]):\n                # bubble above window height\n                bubble_pos = (bubble_hw, (t_pos[1]) - (lh + ls + inch(.25)))\n                bubble.arrow_pos = 'top_left'\n            else:\n                bubble_pos = (bubble_hw, bubble_pos[1])\n                bubble.arrow_pos = 'bottom_left'\n        elif (bubble_pos[0] + bubble_hw) > win_size[0]:\n            # bubble beyond right of window\n            if bubble_pos[1] > (win_size[1] - bubble_size[1]):\n                # bubble above window height\n                bubble_pos = (win_size[0] - bubble_hw,\n                             (t_pos[1]) - (lh + ls + inch(.25)))\n                bubble.arrow_pos = 'top_right'\n            else:\n                bubble_pos = (win_size[0] - bubble_hw, bubble_pos[1])\n                bubble.arrow_pos = 'bottom_right'\n        else:\n            if bubble_pos[1] > (win_size[1] - bubble_size[1]):\n                # bubble above window height\n                bubble_pos = (bubble_pos[0],\n                             (t_pos[1]) - (lh + ls + inch(.25)))\n                bubble.arrow_pos = 'top_mid'\n            else:\n                bubble.arrow_pos = 'bottom_mid'\n\n        bubble_pos = self.to_widget(*bubble_pos)\n        bubble.center_x = bubble_pos[0]\n        if bubble.arrow_pos[0] == 't':\n            bubble.top = bubble_pos[1]\n        else:\n            bubble.y = bubble_pos[1]\n        bubble.mode = mode\n        Animation.cancel_all(bubble)\n        bubble.opacity = 0\n        win.add_widget(bubble, canvas='after')\n        Animation(opacity=1, d=.225).start(bubble)\n\n    def _hide_cut_copy_paste(self, win=None):\n        bubble = self._bubble\n        if not bubble:\n            return\n\n        bubble.hide()\n\n    #\n    # Private\n    #\n\n    @staticmethod\n    def _reload_remove_observer(wr):\n        # called when the textinput is deleted\n        if wr in _textinput_list:\n            _textinput_list.remove(wr)\n\n    def _on_textinput_focused(self, instance, value, *largs):\n        self.focus = value\n\n        win = EventLoop.window\n        self.cancel_selection()\n        self._hide_cut_copy_paste(win)\n\n        if value:\n            if (not (self.readonly or self.disabled) or _is_desktop and\n                self._keyboard_mode == 'system'):\n                Clock.schedule_interval(self._do_blink_cursor, 1 / 2.)\n                self._editable = True\n            else:\n                self._editable = False\n        else:\n            Clock.unschedule(self._do_blink_cursor)\n            self._hide_handles(win)\n\n    def _ensure_clipboard(self):\n        global Clipboard\n        if not Clipboard:\n            from kivy.core.clipboard import Clipboard\n\n    def cut(self):\n        ''' Copy current selection to clipboard then delete it from TextInput.\n\n        .. versionadded:: 1.8.0\n\n        '''\n        self._cut(self.selection_text)\n\n    def _cut(self, data):\n        self._ensure_clipboard()\n        Clipboard.copy(data)\n        self.delete_selection()\n\n    def copy(self, data=''):\n        ''' Copy the value provided in argument `data` into current clipboard.\n        If data is not of type string it will be converted to string.\n        If no data is provided then current selection if present is copied.\n\n        .. versionadded:: 1.8.0\n\n        '''\n        self._ensure_clipboard()\n        if data:\n            return Clipboard.copy(data)\n        if self.selection_text:\n            return Clipboard.copy(self.selection_text)\n\n    def paste(self):\n        ''' Insert text from system :class:`~kivy.core.clipboard.Clipboard`\n        into the :class:`~kivy.uix.textinput.TextInput` at current cursor\n        position.\n\n        .. versionadded:: 1.8.0\n\n        '''\n        self._ensure_clipboard()\n        data = Clipboard.paste()\n        self.delete_selection()\n        self.insert_text(data)\n\n    def _get_text_width(self, text, tab_width, _label_cached):\n        # Return the width of a text, according to the current line options\n        kw = self._get_line_options()\n\n        try:\n            cid = u'{}\\0{}\\0{}'.format(text, self.password, kw)\n        except UnicodeDecodeError:\n            cid = '{}\\0{}\\0{}'.format(text, self.password, kw)\n\n        width = Cache_get('textinput.width', cid)\n        if width:\n            return width\n        if not _label_cached:\n            _label_cached = self._label_cached\n        text = text.replace('\\t', ' ' * tab_width)\n        if not self.password:\n            width = _label_cached.get_extents(text)[0]\n        else:\n            width = _label_cached.get_extents('*' * len(text))[0]\n        Cache_append('textinput.width', cid, width)\n        return width\n\n    def _do_blink_cursor(self, dt):\n        # Callback called by the timer to blink the cursor, according to the\n        # last activity in the widget\n        b = (Clock.get_time() - self._cursor_blink_time)\n        self.cursor_blink = int(b * 2) % 2\n\n    def on_cursor(self, instance, value):\n        # When the cursor is moved, reset the activity timer, and update all\n        # the graphics.\n        self._cursor_blink_time = Clock.get_time()\n        self._trigger_update_graphics()\n\n    def _delete_line(self, idx):\n        # Delete current line, and fix cursor position\n        assert(idx < len(self._lines))\n        self._lines_flags.pop(idx)\n        self._lines_labels.pop(idx)\n        self._lines.pop(idx)\n        self.cursor = self.cursor\n\n    def _set_line_text(self, line_num, text):\n        # Set current line with other text than the default one.\n        self._lines_labels[line_num] = self._create_line_label(text)\n        self._lines[line_num] = text\n\n    def _trigger_refresh_line_options(self, *largs):\n        Clock.unschedule(self._refresh_line_options)\n        Clock.schedule_once(self._refresh_line_options, 0)\n\n    def _refresh_line_options(self, *largs):\n        self._line_options = None\n        self._get_line_options()\n        self._refresh_text_from_property()\n        self._refresh_hint_text()\n        self.cursor = self.get_cursor_from_index(len(self.text))\n\n    def _trigger_refresh_text(self, *largs):\n        if len(largs) and largs[0] == self:\n            largs = ()\n        Clock.unschedule(lambda dt: self._refresh_text_from_property(*largs))\n        Clock.schedule_once(lambda dt:\n                            self._refresh_text_from_property(*largs))\n\n    def _update_text_options(self, *largs):\n        Cache_remove('textinput.width')\n        self._trigger_refresh_text()\n\n    def _refresh_text_from_trigger(self, dt, *largs):\n        self._refresh_text_from_property(*largs)\n\n    def _refresh_text_from_property(self, *largs):\n        self._refresh_text(self._get_text(encode=False), *largs)\n\n    def _refresh_text(self, text, *largs):\n        # Refresh all the lines from a new text.\n        # By using cache in internal functions, this method should be fast.\n        mode = 'all'\n        if len(largs) > 1:\n            mode, start, finish, _lines, _lines_flags, len_lines = largs\n            #start = max(0, start)\n            cursor = None\n        else:\n            cursor = self.cursor_index()\n            _lines, self._lines_flags = self._split_smart(text)\n        _lines_labels = []\n        _line_rects = []\n        _create_label = self._create_line_label\n\n        for x in _lines:\n            lbl = _create_label(x)\n            _lines_labels.append(lbl)\n            _line_rects.append(Rectangle(size=lbl.size))\n\n        if mode == 'all':\n            self._lines_labels = _lines_labels\n            self._lines_rects = _line_rects\n            self._lines = _lines\n        elif mode == 'del':\n            if finish > start:\n                self._insert_lines(start,\n                                   finish if start == finish else (finish + 1),\n                                   len_lines, _lines_flags,\n                                   _lines, _lines_labels, _line_rects)\n        elif mode == 'insert':\n            self._insert_lines(\n                start,\n                finish if (start == finish and not len_lines)\n                else (finish + 1),\n                len_lines, _lines_flags, _lines, _lines_labels,\n                _line_rects)\n\n        min_line_ht = self._label_cached.get_extents('_')[1]\n        # with markup texture can be of height `1`\n        self.line_height = max(_lines_labels[0].height, min_line_ht)\n        #self.line_spacing = 2\n        # now, if the text change, maybe the cursor is not at the same place as\n        # before. so, try to set the cursor on the good place\n        row = self.cursor_row\n        self.cursor = self.get_cursor_from_index(self.cursor_index()\n                                                 if cursor is None else cursor)\n        # if we back to a new line, reset the scroll, otherwise, the effect is\n        # ugly\n        if self.cursor_row != row:\n            self.scroll_x = 0\n        # with the new text don't forget to update graphics again\n        self._trigger_update_graphics()\n\n    def _insert_lines(self, start, finish, len_lines, _lines_flags,\n                      _lines, _lines_labels, _line_rects):\n            self_lines_flags = self._lines_flags\n            _lins_flags = []\n            _lins_flags.extend(self_lines_flags[:start])\n            if len_lines:\n                # if not inserting at first line then\n                if start:\n                    # make sure line flags restored for first line\n                    # _split_smart assumes first line to be not a new line\n                    _lines_flags[0] = self_lines_flags[start]\n                _lins_flags.extend(_lines_flags)\n            _lins_flags.extend(self_lines_flags[finish:])\n            self._lines_flags = _lins_flags\n\n            _lins_lbls = []\n            _lins_lbls.extend(self._lines_labels[:start])\n            if len_lines:\n                _lins_lbls.extend(_lines_labels)\n            _lins_lbls.extend(self._lines_labels[finish:])\n            self._lines_labels = _lins_lbls\n\n            _lins_rcts = []\n            _lins_rcts.extend(self._lines_rects[:start])\n            if len_lines:\n                _lins_rcts.extend(_line_rects)\n            _lins_rcts.extend(self._lines_rects[finish:])\n            self._lines_rects = _lins_rcts\n\n            _lins = []\n            _lins.extend(self._lines[:start])\n            if len_lines:\n                _lins.extend(_lines)\n            _lins.extend(self._lines[finish:])\n            self._lines = _lins\n\n    def _trigger_update_graphics(self, *largs):\n        Clock.unschedule(self._update_graphics)\n        Clock.schedule_once(self._update_graphics, -1)\n\n    def _update_graphics(self, *largs):\n        # Update all the graphics according to the current internal values.\n        #\n        # This is a little bit complex, cause we have to :\n        #     - handle scroll_x\n        #     - handle padding\n        #     - create rectangle for the lines matching the viewport\n        #     - crop the texture coordinates to match the viewport\n        #\n        # This is the first step of graphics, the second is the selection.\n\n        self.canvas.clear()\n        add = self.canvas.add\n\n        lh = self.line_height\n        dy = lh + self.line_spacing\n\n        # adjust view if the cursor is going outside the bounds\n        sx = self.scroll_x\n        sy = self.scroll_y\n\n        # draw labels\n        if not self.focus and (not self._lines or (\n                not self._lines[0] and len(self._lines) == 1)):\n            rects = self._hint_text_rects\n            labels = self._hint_text_labels\n            lines = self._hint_text_lines\n        else:\n            rects = self._lines_rects\n            labels = self._lines_labels\n            lines = self._lines\n        padding_left, padding_top, padding_right, padding_bottom = self.padding\n        x = self.x + padding_left\n        y = self.top - padding_top + sy\n        miny = self.y + padding_bottom\n        maxy = self.top - padding_top\n        for line_num, value in enumerate(lines):\n            if miny <= y <= maxy + dy:\n                texture = labels[line_num]\n                size = list(texture.size)\n                texc = texture.tex_coords[:]\n\n                # calcul coordinate\n                viewport_pos = sx, 0\n                vw = self.width - padding_left - padding_right\n                vh = self.height - padding_top - padding_bottom\n                tw, th = list(map(float, size))\n                oh, ow = tch, tcw = texc[1:3]\n                tcx, tcy = 0, 0\n\n                # adjust size/texcoord according to viewport\n                if viewport_pos:\n                    tcx, tcy = viewport_pos\n                    tcx = tcx / tw * (ow)\n                    tcy = tcy / th * oh\n                if tw - viewport_pos[0] < vw:\n                    tcw = tcw - tcx\n                    size[0] = tcw * size[0]\n                elif vw < tw:\n                    tcw = (vw / tw) * tcw\n                    size[0] = vw\n                if vh < th:\n                    tch = (vh / th) * tch\n                    size[1] = vh\n\n                # cropping\n                mlh = lh\n                if y > maxy:\n                    vh = (maxy - y + lh)\n                    tch = (vh / float(lh)) * oh\n                    tcy = oh - tch\n                    size[1] = vh\n                if y - lh < miny:\n                    diff = miny - (y - lh)\n                    y += diff\n                    vh = lh - diff\n                    tch = (vh / float(lh)) * oh\n                    size[1] = vh\n\n                texc = (\n                    tcx,\n                    tcy + tch,\n                    tcx + tcw,\n                    tcy + tch,\n                    tcx + tcw,\n                    tcy,\n                    tcx,\n                    tcy)\n\n                # add rectangle.\n                r = rects[line_num]\n                r.pos = int(x), int(y - mlh)\n                r.size = size\n                r.texture = texture\n                r.tex_coords = texc\n                add(r)\n\n            y -= dy\n\n        self._update_graphics_selection()\n\n    def _update_graphics_selection(self):\n        if not self._selection:\n            return\n        self.canvas.remove_group('selection')\n        dy = self.line_height + self.line_spacing\n        rects = self._lines_rects\n        padding_top = self.padding[1]\n        padding_bottom = self.padding[3]\n        _top = self.top\n        y = _top - padding_top + self.scroll_y\n        miny = self.y + padding_bottom\n        maxy = _top - padding_top\n        draw_selection = self._draw_selection\n        a, b = self._selection_from, self._selection_to\n        if a > b:\n            a, b = b, a\n        get_cursor_from_index = self.get_cursor_from_index\n        s1c, s1r = get_cursor_from_index(a)\n        s2c, s2r = get_cursor_from_index(b)\n        s2r += 1\n        # pass only the selection lines[]\n        # passing all the lines can get slow when dealing with a lot of text\n        y -= s1r * dy\n        _lines = self._lines\n        _get_text_width = self._get_text_width\n        tab_width = self.tab_width\n        _label_cached = self._label_cached\n        width = self.width\n        padding_left = self.padding[0]\n        padding_right = self.padding[2]\n        x = self.x\n        canvas_add = self.canvas.add\n        selection_color = self.selection_color\n        for line_num, value in enumerate(_lines[s1r:s2r], start=s1r):\n            if miny <= y <= maxy + dy:\n                r = rects[line_num]\n                draw_selection(r.pos, r.size, line_num, (s1c, s1r),\n                               (s2c, s2r - 1), _lines, _get_text_width,\n                               tab_width, _label_cached, width,\n                               padding_left, padding_right, x,\n                               canvas_add, selection_color)\n            y -= dy\n        self._position_handles('both')\n\n    def _draw_selection(self, *largs):\n        pos, size, line_num, (s1c, s1r), (s2c, s2r),\\\n            _lines, _get_text_width, tab_width, _label_cached, width,\\\n            padding_left, padding_right, x, canvas_add, selection_color = largs\n        # Draw the current selection on the widget.\n        if line_num < s1r or line_num > s2r:\n            return\n        x, y = pos\n        w, h = size\n        x1 = x\n        x2 = x + w\n        if line_num == s1r:\n            lines = _lines[line_num]\n            x1 -= self.scroll_x\n            x1 += _get_text_width(lines[:s1c], tab_width, _label_cached)\n        if line_num == s2r:\n            lines = _lines[line_num]\n            x2 = (x - self.scroll_x) + _get_text_width(lines[:s2c],\n                                                       tab_width,\n                                                       _label_cached)\n        width_minus_padding = width - (padding_right + padding_left)\n        maxx = x + width_minus_padding\n        if x1 > maxx:\n            return\n        x1 = max(x1, x)\n        x2 = min(x2, x + width_minus_padding)\n        canvas_add(Color(*selection_color, group='selection'))\n        canvas_add(Rectangle(\n            pos=(x1, pos[1]), size=(x2 - x1, size[1]), group='selection'))\n\n    def on_size(self, instance, value):\n        # if the size change, we might do invalid scrolling / text split\n        # size the text maybe be put after size_hint have been resolved.\n        self._trigger_refresh_text()\n        self._refresh_hint_text()\n        self.scroll_x = self.scroll_y = 0\n\n    def _get_cursor_pos(self):\n        # return the current cursor x/y from the row/col\n        dy = self.line_height + self.line_spacing\n        padding_left = self.padding[0]\n        padding_top = self.padding[1]\n        left = self.x + padding_left\n        top = self.top - padding_top\n        y = top + self.scroll_y\n        y -= self.cursor_row * dy\n        x, y = left + self.cursor_offset() - self.scroll_x, y\n        if x < left:\n            self.scroll_x = 0\n            x = left\n        if y > top:\n            y = top\n            self.scroll_y = 0\n        return x, y\n\n    def _get_line_options(self):\n        # Get or create line options, to be used for Label creation\n        if self._line_options is None:\n            self._line_options = kw = {\n                'font_size': self.font_size,\n                'font_name': self.font_name,\n                'anchor_x': 'left',\n                'anchor_y': 'top',\n                'padding_x': 0,\n                'padding_y': 0,\n                'padding': (0, 0)}\n            self._label_cached = Label(**kw)\n        return self._line_options\n\n    def _create_line_label(self, text, hint=False):\n        # Create a label from a text, using line options\n        ntext = text.replace(u'\\n', u'').replace(u'\\t', u' ' * self.tab_width)\n        if self.password and not hint:  # Don't replace hint_text with *\n            ntext = u'*' * len(ntext)\n        kw = self._get_line_options()\n        cid = '%s\\0%s' % (ntext, str(kw))\n        texture = Cache_get('textinput.label', cid)\n\n        if texture is None:\n            # FIXME right now, we can't render very long line...\n            # if we move on \"VBO\" version as fallback, we won't need to\n            # do this. try to found the maximum text we can handle\n            label = None\n            label_len = len(ntext)\n            ld = None\n\n            # check for blank line\n            if not ntext:\n                texture = Texture.create(size=(1, 1))\n                Cache_append('textinput.label', cid, texture)\n                return texture\n\n            while True:\n                try:\n                    label = Label(text=ntext[:label_len], **kw)\n                    label.refresh()\n                    if ld is not None and ld > 2:\n                        ld = int(ld / 2)\n                        label_len += ld\n                    else:\n                        break\n                except:\n                    # exception happen when we tried to render the text\n                    # reduce it...\n                    if ld is None:\n                        ld = len(ntext)\n                    ld = int(ld / 2)\n                    if ld < 2 and label_len:\n                        label_len -= 1\n                    label_len -= ld\n                    continue\n\n            # ok, we found it.\n            texture = label.texture\n            Cache_append('textinput.label', cid, texture)\n        return texture\n\n    def _tokenize(self, text):\n        # Tokenize a text string from some delimiters\n        if text is None:\n            return\n        delimiters = u' ,\\'\".;:\\n\\r\\t'\n        oldindex = 0\n        for index, char in enumerate(text):\n            if char not in delimiters:\n                continue\n            if oldindex != index:\n                yield text[oldindex:index]\n            yield text[index:index + 1]\n            oldindex = index + 1\n        yield text[oldindex:]\n\n    def _split_smart(self, text):\n        # Do a \"smart\" split. If autowidth or autosize is set,\n        # we are not doing smart split, just a split on line break.\n        # Otherwise, we are trying to split as soon as possible, to prevent\n        # overflow on the widget.\n\n        # depend of the options, split the text on line, or word\n        if not self.multiline:\n            lines = text.split(u'\\n')\n            lines_flags = [0] + [FL_IS_NEWLINE] * (len(lines) - 1)\n            return lines, lines_flags\n\n        # no autosize, do wordwrap.\n        x = flags = 0\n        line = []\n        lines = []\n        lines_flags = []\n        _join = u''.join\n        lines_append, lines_flags_append = lines.append, lines_flags.append\n        padding_left = self.padding[0]\n        padding_right = self.padding[2]\n        width = self.width - padding_left - padding_right\n        text_width = self._get_text_width\n        _tab_width, _label_cached = self.tab_width, self._label_cached\n\n        # try to add each word on current line.\n        for word in self._tokenize(text):\n            is_newline = (word == u'\\n')\n            w = text_width(word, _tab_width, _label_cached)\n            # if we have more than the width, or if it's a newline,\n            # push the current line, and create a new one\n            if (x + w > width and line) or is_newline:\n                lines_append(_join(line))\n                lines_flags_append(flags)\n                flags = 0\n                line = []\n                x = 0\n            if is_newline:\n                flags |= FL_IS_NEWLINE\n            else:\n                x += w\n                line.append(word)\n        if line or flags & FL_IS_NEWLINE:\n            lines_append(_join(line))\n            lines_flags_append(flags)\n\n        return lines, lines_flags\n\n    def _key_down(self, key, repeat=False):\n        displayed_str, internal_str, internal_action, scale = key\n        if internal_action is None:\n            if self._selection:\n                self.delete_selection()\n            self.insert_text(displayed_str)\n        elif internal_action in ('shift', 'shift_L', 'shift_R'):\n            if not self._selection:\n                self._selection_from = self._selection_to = self.cursor_index()\n                self._selection = True\n            self._selection_finished = False\n        elif internal_action.startswith('cursor_'):\n            cc, cr = self.cursor\n            self.do_cursor_movement(internal_action)\n            if self._selection and not self._selection_finished:\n                self._selection_to = self.cursor_index()\n                self._update_selection()\n            else:\n                self.cancel_selection()\n        elif self._selection and internal_action in ('del', 'backspace'):\n            self.delete_selection()\n        elif internal_action == 'del':\n            # Move cursor one char to the right. If that was successful,\n            # do a backspace (effectively deleting char right of cursor)\n            cursor = self.cursor\n            self.do_cursor_movement('cursor_right')\n            if cursor != self.cursor:\n                self.do_backspace(mode='del')\n        elif internal_action == 'backspace':\n            self.do_backspace()\n        elif internal_action == 'enter':\n            if self.multiline:\n                self.insert_text(u'\\n')\n            else:\n                self.dispatch('on_text_validate')\n                self.focus = False\n        elif internal_action == 'escape':\n            self.focus = False\n        if internal_action != 'escape':\n            #self._recalc_size()\n            pass\n\n    def _key_up(self, key, repeat=False):\n        displayed_str, internal_str, internal_action, scale = key\n        if internal_action in ('shift', 'shift_L', 'shift_R'):\n            if self._selection:\n                self._update_selection(True)\n\n    def keyboard_on_key_down(self, window, keycode, text, modifiers):\n        # Keycodes on OSX:\n        ctrl, cmd = 64, 1024\n        key, key_str = keycode\n        win = EventLoop.window\n\n        # This allows *either* ctrl *or* cmd, but not both.\n        is_shortcut = (modifiers == ['ctrl'] or (\n            _is_osx and modifiers == ['meta']))\n        is_interesting_key = key in (list(self.interesting_keys.keys()) + [27])\n\n        if not self.write_tab and super(TextInput,\n            self).keyboard_on_key_down(window, keycode, text, modifiers):\n            return True\n\n        if not self._editable:\n            # duplicated but faster testing for non-editable keys\n            if text and not is_interesting_key:\n                if is_shortcut and key == ord('c'):\n                    self.copy()\n            elif key == 27:\n                self.focus = False\n            return True\n\n        if text and not is_interesting_key:\n\n            self._hide_handles(win)\n            self._hide_cut_copy_paste(win)\n            win.remove_widget(self._handle_middle)\n\n            # check for command modes\n            # we use \\x01INFO\\x02 to get info from IME on mobiles\n            # pygame seems to pass \\x01 as the unicode for ctrl+a\n            # checking for modifiers ensures conflict resolution.\n\n            first_char = ord(text[0])\n            if not modifiers and first_char == 1:\n                self._command_mode = True\n                self._command = ''\n            if not modifiers and first_char == 2:\n                self._command_mode = False\n                self._command = self._command[1:]\n\n            if self._command_mode:\n                self._command += text\n                return\n\n            _command = self._command\n            if _command and first_char == 2:\n                from_undo = True\n                _command, data = _command.split(':')\n                self._command = ''\n                if self._selection:\n                    self.delete_selection()\n                if _command == 'DEL':\n                    count = int(data)\n                    if not count:\n                        self.delete_selection(from_undo=True)\n                    end = self.cursor_index()\n                    self._selection_from = max(end - count, 0)\n                    self._selection_to = end\n                    self._selection = True\n                    self.delete_selection(from_undo=True)\n                    return\n                elif _command == 'INSERT':\n                    self.insert_text(data, from_undo)\n                elif _command == 'INSERTN':\n                    from_undo = False\n                    self.insert_text(data, from_undo)\n                elif _command == 'SELWORD':\n                    self.dispatch('on_double_tap')\n                elif _command == 'SEL':\n                    if data == '0':\n                        Clock.schedule_once(lambda dt: self.cancel_selection())\n                elif _command == 'CURCOL':\n                    self.cursor = int(data), self.cursor_row\n                return\n\n            if is_shortcut:\n                if key == ord('x'):  # cut selection\n                    self._cut(self.selection_text)\n                elif key == ord('c'):  # copy selection\n                    self.copy()\n                elif key == ord('v'):  # paste selection\n                    self.paste()\n                elif key == ord('a'):  # select all\n                    self.select_all()\n                elif key == ord('z'):  # undo\n                    self.do_undo()\n                elif key == ord('r'):  # redo\n                    self.do_redo()\n            else:\n                if EventLoop.window.__class__.__module__ == \\\n                    'kivy.core.window.window_sdl2':\n                    return\n                if self._selection:\n                    self.delete_selection()\n                self.insert_text(text)\n            #self._recalc_size()\n            return\n\n        if is_interesting_key:\n            self._hide_cut_copy_paste(win)\n            self._hide_handles(win)\n\n        if key == 27:  # escape\n            self.focus = False\n            return True\n        elif key == 9:  # tab\n            self.insert_text(u'\\t')\n            return True\n\n        k = self.interesting_keys.get(key)\n        if k:\n            key = (None, None, k, 1)\n            self._key_down(key)\n\n    def keyboard_on_key_up(self, window, keycode):\n        key, key_str = keycode\n        k = self.interesting_keys.get(key)\n        if k:\n            key = (None, None, k, 1)\n            self._key_up(key)\n\n    def keyboard_on_textinput(self, window, text):\n        if self._selection:\n            self.delete_selection()\n        self.insert_text(text, False)\n\n    def on_hint_text(self, instance, value):\n        self._refresh_hint_text()\n\n    def _refresh_hint_text(self):\n        _lines, self._hint_text_flags = self._split_smart(self.hint_text)\n        _hint_text_labels = []\n        _hint_text_rects = []\n        _create_label = self._create_line_label\n\n        for x in _lines:\n            lbl = _create_label(x, hint=True)\n            _hint_text_labels.append(lbl)\n            _hint_text_rects.append(Rectangle(size=lbl.size))\n\n        self._hint_text_lines = _lines\n        self._hint_text_labels = _hint_text_labels\n        self._hint_text_rects = _hint_text_rects\n\n        # Remember to update graphics\n        self._trigger_update_graphics()\n\n    #\n    # Properties\n    #\n\n    _lines = ListProperty([])\n    _hint_text_lines = ListProperty([])\n    _editable = BooleanProperty(True)\n    _insert_int_patu = re.compile(u'[^0-9]')\n    _insert_int_patb = re.compile(b'[^0-9]')\n\n    readonly = BooleanProperty(False)\n    '''If True, the user will not be able to change the content of a textinput.\n\n    .. versionadded:: 1.3.0\n\n    :attr:`readonly` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    multiline = BooleanProperty(True)\n    '''If True, the widget will be able show multiple lines of text. If False,\n    the \"enter\" keypress will defocus the textinput instead of adding a new\n    line.\n\n    :attr:`multiline` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n\n    password = BooleanProperty(False)\n    '''If True, the widget will display its characters as the character '*'.\n\n    .. versionadded:: 1.2.0\n\n    :attr:`password` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    keyboard_suggestions = BooleanProperty(True)\n    '''If True provides auto suggestions on top of keyboard.\n    This will only work if :attr:`input_type` is set to `text`.\n\n     .. versionadded:: 1.8.0\n\n     :attr:`keyboard_suggestions` is a\n     :class:`~kivy.properties.BooleanProperty` defaults to True.\n    '''\n\n    cursor_blink = BooleanProperty(False)\n    '''This property is used to blink the cursor graphic. The value of\n    :attr:`cursor_blink` is automatically computed. Setting a value on it will\n    have no impact.\n\n    :attr:`cursor_blink` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    def _get_cursor(self):\n        return self._cursor\n\n    def _set_cursor(self, pos):\n        if not self._lines:\n            self._trigger_refresh_text()\n            return\n        l = self._lines\n        cr = boundary(pos[1], 0, len(l) - 1)\n        cc = boundary(pos[0], 0, len(l[cr]))\n        cursor = cc, cr\n        if self._cursor == cursor:\n            return\n\n        self._cursor = cursor\n\n        # adjust scrollview to ensure that the cursor will be always inside our\n        # viewport.\n        padding_left = self.padding[0]\n        padding_right = self.padding[2]\n        viewport_width = self.width - padding_left - padding_right\n        sx = self.scroll_x\n        offset = self.cursor_offset()\n\n        # if offset is outside the current bounds, reajust\n        if offset > viewport_width + sx:\n            self.scroll_x = offset - viewport_width\n        if offset < sx:\n            self.scroll_x = offset\n\n        # do the same for Y\n        # this algo try to center the cursor as much as possible\n        dy = self.line_height + self.line_spacing\n        offsety = cr * dy\n        sy = self.scroll_y\n        padding_top = self.padding[1]\n        padding_bottom = self.padding[3]\n        viewport_height = self.height - padding_top - padding_bottom - dy\n        if offsety > viewport_height + sy:\n            sy = offsety - viewport_height\n        if offsety < sy:\n            sy = offsety\n        self.scroll_y = sy\n\n        return True\n\n    cursor = AliasProperty(_get_cursor, _set_cursor)\n    '''Tuple of (row, col) values indicating the current cursor position.\n    You can set a new (row, col) if you want to move the cursor. The scrolling\n    area will be automatically updated to ensure that the cursor is\n    visible inside the viewport.\n\n    :attr:`cursor` is an :class:`~kivy.properties.AliasProperty`.\n    '''\n\n    def _get_cursor_col(self):\n        return self._cursor[0]\n\n    cursor_col = AliasProperty(_get_cursor_col, None, bind=('cursor', ))\n    '''Current column of the cursor.\n\n    :attr:`cursor_col` is an :class:`~kivy.properties.AliasProperty` to\n    cursor[0], read-only.\n    '''\n\n    def _get_cursor_row(self):\n        return self._cursor[1]\n\n    cursor_row = AliasProperty(_get_cursor_row, None, bind=('cursor', ))\n    '''Current row of the cursor.\n\n    :attr:`cursor_row` is an :class:`~kivy.properties.AliasProperty` to\n    cursor[1], read-only.\n    '''\n\n    cursor_pos = AliasProperty(_get_cursor_pos, None, bind=(\n        'cursor', 'padding', 'pos', 'size', 'focus',\n        'scroll_x', 'scroll_y'))\n    '''Current position of the cursor, in (x, y).\n\n    :attr:`cursor_pos` is an :class:`~kivy.properties.AliasProperty`,\n    read-only.\n    '''\n\n    cursor_color = ListProperty([1, 0, 0, 1])\n    '''Current color of the cursor, in (r, g, b, a) format.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`cursor_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [1, 0, 0, 1].\n    '''\n\n    line_height = NumericProperty(1)\n    '''Height of a line. This property is automatically computed from the\n    :attr:`font_name`, :attr:`font_size`. Changing the line_height will have\n    no impact.\n\n    .. note::\n\n        :attr:`line_height` is the height of a single line of text.\n        Use :attr:`minimum_height`, which also includes padding, to\n        get the height required to display the text properly.\n\n    :attr:`line_height` is a :class:`~kivy.properties.NumericProperty`,\n    read-only.\n    '''\n\n    tab_width = NumericProperty(4)\n    '''By default, each tab will be replaced by four spaces on the text\n    input widget. You can set a lower or higher value.\n\n    :attr:`tab_width` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 4.\n    '''\n\n    padding_x = VariableListProperty([0, 0], length=2)\n    '''Horizontal padding of the text: [padding_left, padding_right].\n\n    padding_x also accepts a one argument form [padding_horizontal].\n\n    :attr:`padding_x` is a :class:`~kivy.properties.VariableListProperty` and\n    defaults to [0, 0]. This might be changed by the current theme.\n\n    .. deprecated:: 1.7.0\n        Use :attr:`padding` instead.\n    '''\n\n    def on_padding_x(self, instance, value):\n        self.padding[0] = value[0]\n        self.padding[2] = value[1]\n\n    padding_y = VariableListProperty([0, 0], length=2)\n    '''Vertical padding of the text: [padding_top, padding_bottom].\n\n    padding_y also accepts a one argument form [padding_vertical].\n\n    :attr:`padding_y` is a :class:`~kivy.properties.VariableListProperty` and\n    defaults to [0, 0]. This might be changed by the current theme.\n\n    .. deprecated:: 1.7.0\n        Use :attr:`padding` instead.\n    '''\n\n    def on_padding_y(self, instance, value):\n        self.padding[1] = value[0]\n        self.padding[3] = value[1]\n\n    padding = VariableListProperty([6, 6, 6, 6])\n    '''Padding of the text: [padding_left, padding_top, padding_right,\n    padding_bottom].\n\n    padding also accepts a two argument form [padding_horizontal,\n    padding_vertical] and a one argument form [padding].\n\n    .. versionchanged:: 1.7.0\n        Replaced AliasProperty with VariableListProperty.\n\n    :attr:`padding` is a :class:`~kivy.properties.VariableListProperty` and\n    defaults to [6, 6, 6, 6].\n    '''\n\n    scroll_x = NumericProperty(0)\n    '''X scrolling value of the viewport. The scrolling is automatically\n    updated when the cursor is moved or text changed. If there is no\n    user input, the scroll_x and scroll_y properties may be changed.\n\n    :attr:`scroll_x` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    scroll_y = NumericProperty(0)\n    '''Y scrolling value of the viewport. See :attr:`scroll_x` for more\n    information.\n\n    :attr:`scroll_y` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    selection_color = ListProperty([0.1843, 0.6549, 0.8313, .5])\n    '''Current color of the selection, in (r, g, b, a) format.\n\n    .. warning::\n\n        The color should always have an \"alpha\" component less than 1\n        since the selection is drawn after the text.\n\n    :attr:`selection_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [0.1843, 0.6549, 0.8313, .5].\n    '''\n\n    border = ListProperty([4, 4, 4, 4])\n    '''Border used for :class:`~kivy.graphics.vertex_instructions.BorderImage`\n    graphics instruction. Used with :attr:`background_normal` and\n    :attr:`background_active`. Can be used for a custom background.\n\n    .. versionadded:: 1.4.1\n\n    It must be a list of four values: (top, right, bottom, left). Read the\n    BorderImage instruction for more information about how to use it.\n\n    :attr:`border` is a :class:`~kivy.properties.ListProperty` and defaults\n    to (4, 4, 4, 4).\n    '''\n\n    background_normal = StringProperty(\n        'atlas://data/images/defaulttheme/textinput')\n    '''Background image of the TextInput when it's not in focus.\n\n    .. versionadded:: 1.4.1\n\n    :attr:`background_normal` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/textinput'.\n    '''\n\n    background_disabled_normal = StringProperty(\n        'atlas://data/images/defaulttheme/textinput_disabled')\n    '''Background image of the TextInput when disabled.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`background_disabled_normal` is a\n    :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/textinput_disabled'.\n    '''\n\n    background_active = StringProperty(\n        'atlas://data/images/defaulttheme/textinput_active')\n    '''Background image of the TextInput when it's in focus.\n\n    .. versionadded:: 1.4.1\n\n    :attr:`background_active` is a\n    :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/textinput_active'.\n    '''\n\n    background_disabled_active = StringProperty(\n        'atlas://data/images/defaulttheme/textinput_disabled_active')\n    '''Background image of the TextInput when it's in focus and disabled.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`background_disabled_active` is a\n    :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/textinput_disabled_active'.\n    '''\n\n    background_color = ListProperty([1, 1, 1, 1])\n    '''Current color of the background, in (r, g, b, a) format.\n\n    .. versionadded:: 1.2.0\n\n    :attr:`background_color` is a :class:`~kivy.properties.ListProperty`\n    and defaults to [1, 1, 1, 1] (white).\n    '''\n\n    foreground_color = ListProperty([0, 0, 0, 1])\n    '''Current color of the foreground, in (r, g, b, a) format.\n\n    .. versionadded:: 1.2.0\n\n    :attr:`foreground_color` is a :class:`~kivy.properties.ListProperty`\n    and defaults to [0, 0, 0, 1] (black).\n    '''\n\n    disabled_foreground_color = ListProperty([0, 0, 0, .5])\n    '''Current color of the foreground when disabled, in (r, g, b, a) format.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`disabled_foreground_color` is a\n    :class:`~kivy.properties.ListProperty` and\n    defaults to [0, 0, 0, 5] (50% transparent black).\n    '''\n\n    use_bubble = BooleanProperty(not _is_desktop)\n    '''Indicates whether the cut/copy/paste bubble is used.\n\n    .. versionadded:: 1.7.0\n\n    :attr:`use_bubble` is a :class:`~kivy.properties.BooleanProperty`\n    and defaults to True on mobile OS's, False on desktop OS's.\n    '''\n\n    use_handles = BooleanProperty(not _is_desktop)\n    '''Indicates whether the selection handles are displayed.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`use_handles` is a :class:`~kivy.properties.BooleanProperty`\n    and defaults to True on mobile OS's, False on desktop OS's.\n    '''\n\n    suggestion_text = StringProperty('')\n    '''Shows a suggestion text/word from currentcursor position onwards,\n    that can be used as a possible completion. Usefull for suggesting completion\n    text. This can also be used by the IME to setup the current word being\n    edited\n\n    ..versionadded:: 1.9.0\n\n    :attr:`suggestion_text` is a :class:`~kivy.properties.StringProperty`\n    defaults to `''`\n    '''\n\n    def on_suggestion_text(self, instance, value):\n        global MarkupLabel\n        if not MarkupLabel:\n            from kivy.core.text.markup import MarkupLabel\n\n        cursor_pos = self.cursor_pos\n        txt = self._lines[self.cursor_row]\n        cr = self.cursor_row\n        kw = self._get_line_options()\n        rct = self._lines_rects[cr]\n\n        lbl = text = None\n        if value:\n            lbl = MarkupLabel(\n                text=txt + \"[b]{}[/b]\".format(value), **kw)\n        else:\n            lbl = Label(**kw)\n            text = txt\n\n        lbl.refresh()\n\n        self._lines_labels[cr] = lbl.texture\n        rct.size = lbl.size\n        self._update_graphics()\n\n    def get_sel_from(self):\n        return self._selection_from\n\n    selection_from = AliasProperty(get_sel_from, None)\n    '''If a selection is in progress or complete, this property will represent\n    the cursor index where the selection started.\n\n    .. versionchanged:: 1.4.0\n        :attr:`selection_from` is an :class:`~kivy.properties.AliasProperty`\n        and defaults to None, readonly.\n    '''\n\n    def get_sel_to(self):\n        return self._selection_to\n\n    selection_to = AliasProperty(get_sel_to, None)\n    '''If a selection is in progress or complete, this property will represent\n    the cursor index where the selection started.\n\n    .. versionchanged:: 1.4.0\n        :attr:`selection_to` is an :class:`~kivy.properties.AliasProperty` and\n        defaults to None, readonly.\n    '''\n\n    selection_text = StringProperty(u'')\n    '''Current content selection.\n\n    :attr:`selection_text` is a :class:`~kivy.properties.StringProperty`\n    and defaults to '', readonly.\n    '''\n\n    def on_selection_text(self, instance, value):\n        if value and self.use_handles:\n            self._trigger_show_handles()\n\n    def _get_text(self, encode=True):\n        lf = self._lines_flags\n        l = self._lines\n        len_l = len(l)\n\n        if len(lf) < len_l:\n            lf.append(1)\n\n        text = u''.join([(u'\\n' if (lf[i] & FL_IS_NEWLINE) else u'') + l[i]\n                        for i in range(len_l)])\n\n        if PY2 and encode and type(text) is not str:\n            text = text.encode('utf-8')\n        return text\n\n    def _set_text(self, text):\n        if PY2 and type(text) is str:\n            text = text.decode('utf-8')\n\n        if self._get_text(encode=False) == text:\n            return\n\n        self._refresh_text(text)\n        self.cursor = self.get_cursor_from_index(len(text))\n\n    text = AliasProperty(_get_text, _set_text, bind=('_lines', ))\n    '''Text of the widget.\n\n    Creation of a simple hello world::\n\n        widget = TextInput(text='Hello world')\n\n    If you want to create the widget with an unicode string, use::\n\n        widget = TextInput(text=u'My unicode string')\n\n    :attr:`text` a :class:`~kivy.properties.StringProperty`.\n    '''\n\n    font_name = StringProperty('DroidSans')\n    '''Filename of the font to use. The path can be absolute or relative.\n    Relative paths are resolved by the :func:`~kivy.resources.resource_find`\n    function.\n\n    .. warning::\n\n        Depending on your text provider, the font file may be ignored. However,\n        you can mostly use this without problems.\n\n        If the font used lacks the glyphs for the particular language/symbols\n        you are using, you will see '[]' blank box characters instead of the\n        actual glyphs. The solution is to use a font that has the glyphs you\n        need to display. For example, to display |unicodechar|, use a font like\n        freesans.ttf that has the glyph.\n\n        .. |unicodechar| image:: images/unicode-char.png\n\n    :attr:`font_name` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'DroidSans'.\n    '''\n\n    font_size = NumericProperty('15sp')\n    '''Font size of the text in pixels.\n\n    :attr:`font_size` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 10.\n    '''\n\n    hint_text = StringProperty('')\n    '''Hint text of the widget.\n\n    Shown if text is '' and focus is False.\n\n    .. versionadded:: 1.6.0\n\n    :attr:`hint_text` a :class:`~kivy.properties.StringProperty` and defaults\n    to ''.\n    '''\n\n    hint_text_color = ListProperty([0.5, 0.5, 0.5, 1.0])\n    '''Current color of the hint_text text, in (r, g, b, a) format.\n\n    .. versionadded:: 1.6.0\n\n    :attr:`hint_text_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [0.5, 0.5, 0.5, 1.0] (grey).\n    '''\n\n    auto_indent = BooleanProperty(False)\n    '''Automatically indent multiline text.\n\n    .. versionadded:: 1.7.0\n\n    :attr:`auto_indent` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    allow_copy = BooleanProperty(True)\n    '''Decides whether to allow copying the text.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`allow_copy` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n\n    def _get_min_height(self):\n        return (len(self._lines) * (self.line_height + self.line_spacing)\n                + self.padding[1] + self.padding[3])\n\n    minimum_height = AliasProperty(_get_min_height, None,\n                                   bind=('_lines', 'line_spacing', 'padding',\n                                         'font_size', 'font_name', 'password',\n                                         'hint_text', 'line_height'))\n    '''Minimum height of the content inside the TextInput.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`minimum_height` is a readonly\n    :class:`~kivy.properties.AliasProperty`.\n    '''\n\n    line_spacing = NumericProperty(0)\n    '''Space taken up between the lines.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`line_spacing` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    input_filter = ObjectProperty(None, allownone=True)\n    ''' Filters the input according to the specified mode, if not None. If\n    None, no filtering is applied.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`input_filter` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to `None`. Can be one of `None`, `'int'` (string), or `'float'`\n    (string), or a callable. If it is `'int'`, it will only accept numbers.\n    If it is `'float'` it will also accept a single period. Finally, if it is\n    a callable it will be called with two parameter; the string to be added\n    and a bool indicating whether the string is a result of undo (True). The\n    callable should return a new substring that will be used instead.\n    '''\n\n    handle_image_middle = StringProperty(\n        'atlas://data/images/defaulttheme/selector_middle')\n    '''Image used to display the middle handle on the TextInput for cursor\n    positioning.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`handle_image_middle` is a :class:`~kivy.properties.StringProperty`\n    and defaults to 'atlas://data/images/defaulttheme/selector_middle'.\n    '''\n\n    def on_handle_image_middle(self, instance, value):\n        if self._handle_middle:\n            self._handle_middle.source = value\n\n    handle_image_left = StringProperty(\n        'atlas://data/images/defaulttheme/selector_left')\n    '''Image used to display the Left handle on the TextInput for selection.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`handle_image_left` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/selector_left'.\n    '''\n\n    def on_handle_image_left(self, instance, value):\n        if self._handle_left:\n            self._handle_left.source = value\n\n    handle_image_right = StringProperty(\n        'atlas://data/images/defaulttheme/selector_right')\n    '''Image used to display the Right handle on the TextInput for selection.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`handle_image_right` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/selector_right'.\n    '''\n\n    def on_handle_image_right(self, instance, value):\n        if self._handle_right:\n            self._handle_right.source = value\n\n    write_tab = BooleanProperty(True)\n    '''Whether the tab key should move focus to the next widget or if it should\n    enter a tab in the :class:`TextInput`. If `True` a tab will be written,\n    otherwise, focus will move to the next widget.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`write_tab` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to `True`.\n    '''\n\n\nif __name__ == '__main__':\n    from kivy.app import App\n    from kivy.uix.boxlayout import BoxLayout\n    from kivy.lang import Builder\n\n    class TextInputApp(App):\n\n        def build(self):\n\n            Builder.load_string('''\n<TextInput>\n    on_text:\n        self.suggestion_text = ''\n        self.suggestion_text = 'ion_text'\n\n''')\n            root = BoxLayout(orientation='vertical')\n            textinput = TextInput(multiline=True, use_bubble=True,\n                                  use_handles=True)\n            #textinput.text = __doc__\n            root.add_widget(textinput)\n            textinput2 = TextInput(multiline=False, text='monoline textinput',\n                                   size_hint=(1, None), height=30)\n            root.add_widget(textinput2)\n            return root\n\n    TextInputApp().run()\n"
  },
  {
    "path": "tickeys/kivy/uix/togglebutton.py",
    "content": "'''\nToggle button\n=============\n\nThe :class:`ToggleButton` widget acts like a checkbox. When you touch/click it,\nthe state toggles between 'normal' and 'down' (as opposed to a :class:`Button`\nthat is only 'down' as long as it is pressed).\n\nToggle buttons can also be grouped to make radio buttons - only one button in\na group can be in a 'down' state. The group name can be a string or any other\nhashable Python object::\n\n    btn1 = ToggleButton(text='Male', group='sex',)\n    btn2 = ToggleButton(text='Female', group='sex', state='down')\n    btn3 = ToggleButton(text='Mixed', group='sex')\n\nOnly one of the buttons can be 'down'/checked at the same time.\n\nTo configure the ToggleButton, you can use the same properties that you can use\nfor a :class:`~kivy.uix.button.Button` class.\n\n'''\n\n__all__ = ('ToggleButton', )\n\nfrom kivy.uix.button import Button\nfrom kivy.uix.behaviors import ToggleButtonBehavior\n\n\nclass ToggleButton(ToggleButtonBehavior, Button):\n    '''Toggle button class, see module documentation for more information.\n    '''\n\n    pass\n"
  },
  {
    "path": "tickeys/kivy/uix/treeview.py",
    "content": "'''\nTree View\n=========\n\n.. versionadded:: 1.0.4\n\n\n:class:`TreeView` is a widget used to represent a tree structure. It is\ncurrently very basic, supporting a minimal feature set.\n\nIntroduction\n------------\n\nA :class:`TreeView` is populated with :class:`TreeViewNode` instances, but you\ncannot use a :class:`TreeViewNode` directly. You must combine it with another\nwidget, such as :class:`~kivy.uix.label.Label`,\n:class:`~kivy.uix.button.Button` or even your own widget. The TreeView\nalways creates a default root node, based on :class:`TreeViewLabel`.\n\n:class:`TreeViewNode` is a class object containing needed properties for\nserving as a tree node. Extend :class:`TreeViewNode` to create custom node\ntypes for use with a :class:`TreeView`.\n\nFor constructing your own subclass, follow the pattern of TreeViewLabel which\ncombines a Label and a TreeViewNode, producing a :class:`TreeViewLabel` for\ndirect use in a TreeView instance.\n\nTo use the TreeViewLabel class, you could create two nodes directly attached\nto root::\n\n    tv = TreeView()\n    tv.add_node(TreeViewLabel(text='My first item'))\n    tv.add_node(TreeViewLabel(text='My second item'))\n\nOr, create two nodes attached to a first::\n\n    tv = TreeView()\n    n1 = tv.add_node(TreeViewLabel(text='Item 1'))\n    tv.add_node(TreeViewLabel(text='SubItem 1'), n1)\n    tv.add_node(TreeViewLabel(text='SubItem 2'), n1)\n\nIf you have a large tree structure, perhaps you would need a utility function\nto populate the tree view::\n\n    def populate_tree_view(tree_view, parent, node):\n        if parent is None:\n            tree_node = tree_view.add_node(TreeViewLabel(text=node['node_id'],\n                                                         is_open=True))\n        else:\n            tree_node = tree_view.add_node(TreeViewLabel(text=node['node_id'],\n                                                         is_open=True), parent)\n\n        for child_node in node['children']:\n            populate_tree_view(tree_view, tree_node, child_node)\n\n\n    tree = {'node_id': '1',\n            'children': [{'node_id': '1.1',\n                          'children': [{'node_id': '1.1.1',\n                                        'children': [{'node_id': '1.1.1.1',\n                                                      'children': []}]},\n                                       {'node_id': '1.1.2',\n                                        'children': []},\n                                       {'node_id': '1.1.3',\n                                        'children': []}]},\n                          {'node_id': '1.2',\n                           'children': []}]}\n\n\n    class TreeWidget(FloatLayout):\n        def __init__(self, **kwargs):\n            super(TreeWidget, self).__init__(**kwargs)\n\n            tv = TreeView(root_options=dict(text='Tree One'),\n                          hide_root=False,\n                          indent_level=4)\n\n            populate_tree_view(tv, None, tree)\n\n            self.add_widget(tv)\n\nThe root widget in the tree view is opened by default and has text set as\n'Root'. If you want to change that, you can use the\n:attr:`TreeView.root_options`\nproperty. This will pass options to the root widget::\n\n    tv = TreeView(root_options=dict(text='My root label'))\n\n\nCreating Your Own Node Widget\n-----------------------------\n\nFor a button node type, combine a :class:`~kivy.uix.button.Button` and a\n:class:`TreeViewNode` as follows::\n\n    class TreeViewButton(Button, TreeViewNode):\n        pass\n\nYou must know that, for a given node, only the\n:attr:`~kivy.uix.widget.Widget.size_hint_x` will be honored. The allocated\nwidth for the node will depend of the current width of the TreeView and the\nlevel of the node. For example, if a node is at level 4, the width\nallocated will be:\n\n    treeview.width - treeview.indent_start - treeview.indent_level * node.level\n\nYou might have some trouble with that. It is the developer's responsibility to\ncorrectly handle adapting the graphical representation nodes, if needed.\n'''\n\nfrom kivy.clock import Clock\nfrom kivy.uix.label import Label\nfrom kivy.uix.widget import Widget\nfrom kivy.properties import BooleanProperty, ListProperty, ObjectProperty, \\\n    AliasProperty, NumericProperty, ReferenceListProperty\n\n\nclass TreeViewException(Exception):\n    '''Exception for errors in the :class:`TreeView`.\n    '''\n    pass\n\n\nclass TreeViewNode(object):\n    '''TreeViewNode class, used to build a node class for a TreeView object.\n    '''\n\n    def __init__(self, **kwargs):\n        if self.__class__ is TreeViewNode:\n            raise TreeViewException('You cannot use directly TreeViewNode.')\n        super(TreeViewNode, self).__init__(**kwargs)\n\n    is_leaf = BooleanProperty(True)\n    '''Boolean to indicate whether this node is a leaf or not. Used to adjust\n    the graphical representation.\n\n    :attr:`is_leaf` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to True. It is automatically set to False when child is added.\n    '''\n\n    is_open = BooleanProperty(False)\n    '''Boolean to indicate whether this node is opened or not, in case there\n    are child nodes. This is used to adjust the graphical representation.\n\n    .. warning::\n\n        This property is automatically set by the :class:`TreeView`. You can\n        read but not write it.\n\n    :attr:`is_open` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    is_loaded = BooleanProperty(False)\n    '''Boolean to indicate whether this node is already loaded or not. This\n    property is used only if the :class:`TreeView` uses asynchronous loading.\n\n    :attr:`is_loaded` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    is_selected = BooleanProperty(False)\n    '''Boolean to indicate whether this node is selected or not. This is used\n    adjust the graphical representation.\n\n    .. warning::\n\n        This property is automatically set by the :class:`TreeView`. You can\n        read but not write it.\n\n    :attr:`is_selected` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    no_selection = BooleanProperty(False)\n    '''Boolean used to indicate whether selection of the node is allowed or\n     not.\n\n    :attr:`no_selection` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    nodes = ListProperty([])\n    '''List of nodes. The nodes list is different than the children list. A\n    node in the nodes list represents a node on the tree. An item in the\n    children list represents the widget associated with the node.\n\n    .. warning::\n\n        This property is automatically set by the :class:`TreeView`. You can\n        read but not write it.\n\n    :attr:`nodes` is a :class:`~kivy.properties.ListProperty` and defaults to\n    [].\n    '''\n\n    parent_node = ObjectProperty(None, allownone=True)\n    '''Parent node. This attribute is needed because the :attr:`parent` can be\n    None when the node is not displayed.\n\n    .. versionadded:: 1.0.7\n\n    :attr:`parent_node` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    level = NumericProperty(-1)\n    '''Level of the node.\n\n    :attr:`level` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to -1.\n    '''\n\n    color_selected = ListProperty([.3, .3, .3, 1.])\n    '''Background color of the node when the node is selected.\n\n    :attr:`color_selected` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [.1, .1, .1, 1].\n    '''\n\n    odd = BooleanProperty(False)\n    '''\n    This property is set by the TreeView widget automatically and is read-only.\n\n    :attr:`odd` is a :class:`~kivy.properties.BooleanProperty` and defaults to\n    False.\n    '''\n\n    odd_color = ListProperty([1., 1., 1., .0])\n    '''Background color of odd nodes when the node is not selected.\n\n    :attr:`odd_color` is a :class:`~kivy.properties.ListProperty` and defaults\n    to [1., 1., 1., 0.].\n    '''\n\n    even_color = ListProperty([0.5, 0.5, 0.5, 0.1])\n    '''Background color of even nodes when the node is not selected.\n\n    :attr:`bg_color` is a :class:`~kivy.properties.ListProperty` ans defaults\n    to [.5, .5, .5, .1].\n    '''\n\n\nclass TreeViewLabel(Label, TreeViewNode):\n    '''Combines a :class:`~kivy.uix.label.Label` and a :class:`TreeViewNode` to\n    create a :class:`TreeViewLabel` that can be used as a text node in the\n    tree.\n\n    See module documentation for more information.\n    '''\n\n\nclass TreeView(Widget):\n    '''TreeView class. See module documentation for more information.\n\n    :Events:\n        `on_node_expand`: (node, )\n            Fired when a node is being expanded\n        `on_node_collapse`: (node, )\n            Fired when a node is being collapsed\n    '''\n\n    __events__ = ('on_node_expand', 'on_node_collapse')\n\n    def __init__(self, **kwargs):\n        self._trigger_layout = Clock.create_trigger(self._do_layout, -1)\n        super(TreeView, self).__init__(**kwargs)\n        tvlabel = TreeViewLabel(text='Root', is_open=True, level=0)\n        for key, value in self.root_options.items():\n            setattr(tvlabel, key, value)\n        self._root = self.add_node(tvlabel, None)\n        self.bind(\n            pos=self._trigger_layout,\n            size=self._trigger_layout,\n            indent_level=self._trigger_layout,\n            indent_start=self._trigger_layout)\n        self._trigger_layout()\n\n    def add_node(self, node, parent=None):\n        '''Add a new node to the tree.\n\n        :Parameters:\n            `node`: instance of a :class:`TreeViewNode`\n                Node to add into the tree\n            `parent`: instance of a :class:`TreeViewNode`, defaults to None\n                Parent node to attach the new node. If `None`, it is added to\n                the :attr:`root` node.\n\n        :returns:\n            the node `node`.\n        '''\n        # check if the widget is \"ok\" for a node\n        if not isinstance(node, TreeViewNode):\n            raise TreeViewException(\n                'The node must be a subclass of TreeViewNode')\n        # create node\n        if parent is None and self._root:\n            parent = self._root\n        if parent:\n            parent.is_leaf = False\n            parent.nodes.append(node)\n            node.parent_node = parent\n            node.level = parent.level + 1\n        node.bind(size=self._trigger_layout)\n        self._trigger_layout()\n        return node\n\n    def remove_node(self, node):\n        '''Removes a node from the tree.\n\n        .. versionadded:: 1.0.7\n\n        :Parameters:\n            `node`: instance of a :class:`TreeViewNode`\n                Node to remove from the tree. If `node` is :attr:`root`, it is\n                not removed.\n        '''\n        # check if the widget is \"ok\" for a node\n        if not isinstance(node, TreeViewNode):\n            raise TreeViewException(\n                'The node must be a subclass of TreeViewNode')\n        parent = node.parent_node\n        if parent is not None:\n            nodes = parent.nodes\n            if node in nodes:\n                nodes.remove(node)\n                self._selected_node = None\n            parent.is_leaf = not bool(len(nodes))\n            node.parent_node = None\n            node.unbind(size=self._trigger_layout)\n            self._trigger_layout()\n\n    def on_node_expand(self, node):\n        pass\n\n    def on_node_collapse(self, node):\n        pass\n\n    def select_node(self, node):\n        '''Select a node in the tree.\n        '''\n        if node.no_selection:\n            return\n        if self._selected_node:\n            self._selected_node.is_selected = False\n        node.is_selected = True\n        self._selected_node = node\n\n    def toggle_node(self, node):\n        '''Toggle the state of the node (open/collapsed).\n        '''\n        node.is_open = not node.is_open\n        if node.is_open:\n            if self.load_func and not node.is_loaded:\n                self._do_node_load(node)\n            self.dispatch('on_node_expand', node)\n        else:\n            self.dispatch('on_node_collapse', node)\n        self._trigger_layout()\n\n    def get_node_at_pos(self, pos):\n        '''Get the node at the position (x, y).\n        '''\n        x, y = pos\n        for node in self.iterate_open_nodes(self.root):\n            if self.x <= x <= self.right and \\\n               node.y <= y <= node.top:\n                return node\n\n    def iterate_open_nodes(self, node=None):\n        '''Generator to iterate over all the expended nodes starting from\n        `node` and down. If `node` is `None`, the generator start with\n        :attr:`root`.\n\n        To get all the open nodes::\n\n            treeview = TreeView()\n            # ... add nodes ...\n            for node in treeview.iterate_open_nodes():\n                print(node)\n\n        '''\n        if not node:\n            node = self.root\n        if self.hide_root and node is self.root:\n            pass\n        else:\n            yield node\n        if not node.is_open:\n            return\n        f = self.iterate_open_nodes\n        for cnode in node.nodes:\n            for ynode in f(cnode):\n                yield ynode\n\n    def iterate_all_nodes(self, node=None):\n        '''Generator to iterate over all nodes from `node` and down whether\n        expanded or not. If `node` is `None`, the generator start with\n        :attr:`root`.\n        '''\n        if not node:\n            node = self.root\n        yield node\n        f = self.iterate_all_nodes\n        for cnode in node.nodes:\n            for ynode in f(cnode):\n                yield ynode\n\n    #\n    # Private\n    #\n    def on_load_func(self, instance, value):\n        if value:\n            Clock.schedule_once(self._do_initial_load)\n\n    def _do_initial_load(self, *largs):\n        if not self.load_func:\n            return\n        self._do_node_load(None)\n\n    def _do_node_load(self, node):\n        gen = self.load_func(self, node)\n        if node:\n            node.is_loaded = True\n        if not gen:\n            return\n        for cnode in gen:\n            self.add_node(cnode, node)\n\n    def on_root_options(self, instance, value):\n        if not self.root:\n            return\n        for key, value in value.items():\n            setattr(self.root, key, value)\n\n    def _do_layout(self, *largs):\n        self.clear_widgets()\n        # display only the one who are is_open\n        self._do_open_node(self.root)\n        # now do layout\n        self._do_layout_node(self.root, 0, self.top)\n        # now iterate for calculating minimum size\n        min_width = min_height = 0\n        count = 0\n        for node in self.iterate_open_nodes(self.root):\n            node.odd = False if count % 2 else True\n            count += 1\n            min_width = max(min_width, node.width + self.indent_level +\n                            node.level * self.indent_level)\n            min_height += node.height\n        self.minimum_size = (min_width, min_height)\n\n    def _do_open_node(self, node):\n        if self.hide_root and node is self.root:\n            height = 0\n        else:\n            self.add_widget(node)\n            height = node.height\n            if not node.is_open:\n                return height\n        for cnode in node.nodes:\n            height += self._do_open_node(cnode)\n        return height\n\n    def _do_layout_node(self, node, level, y):\n        if self.hide_root and node is self.root:\n            level -= 1\n        else:\n            node.x = self.x + self.indent_start + level * self.indent_level\n            node.top = y\n            if node.size_hint_x:\n                node.width = (self.width - (node.x - self.x)) \\\n                    * node.size_hint_x\n            y -= node.height\n            if not node.is_open:\n                return y\n        for cnode in node.nodes:\n            y = self._do_layout_node(cnode, level + 1, y)\n        return y\n\n    def on_touch_down(self, touch):\n        node = self.get_node_at_pos(touch.pos)\n        if not node:\n            return\n        if node.disabled:\n            return\n        # toggle node or selection ?\n        if node.x - self.indent_start <= touch.x < node.x:\n            self.toggle_node(node)\n        elif node.x <= touch.x:\n            self.select_node(node)\n            node.dispatch('on_touch_down', touch)\n        return True\n\n    #\n    # Private properties\n    #\n    _root = ObjectProperty(None)\n\n    _selected_node = ObjectProperty(None, allownone=True)\n\n    #\n    # Properties\n    #\n\n    minimum_width = NumericProperty(0)\n    '''Minimum width needed to contain all children.\n\n    .. versionadded:: 1.0.9\n\n    :attr:`minimum_width` is a :class:`kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    minimum_height = NumericProperty(0)\n    '''Minimum height needed to contain all children.\n\n    .. versionadded:: 1.0.9\n\n    :attr:`minimum_height` is a :class:`kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    minimum_size = ReferenceListProperty(minimum_width, minimum_height)\n    '''Minimum size needed to contain all children.\n\n    .. versionadded:: 1.0.9\n\n    :attr:`minimum_size` is a :class:`~kivy.properties.ReferenceListProperty`\n    of (:attr:`minimum_width`, :attr:`minimum_height`) properties.\n    '''\n\n    indent_level = NumericProperty('16dp')\n    '''Width used for the indentation of each level except the first level.\n\n    Computation of indent for each level of the tree is::\n\n        indent = indent_start + level * indent_level\n\n    :attr:`indent_level` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 16.\n    '''\n\n    indent_start = NumericProperty('24dp')\n    '''Indentation width of the level 0 / root node. This is mostly the initial\n    size to accommodate a tree icon (collapsed / expanded). See\n    :attr:`indent_level` for more information about the computation of level\n    indentation.\n\n    :attr:`indent_start` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 24.\n    '''\n\n    hide_root = BooleanProperty(False)\n    '''Use this property to show/hide the initial root node. If True, the root\n    node will be appear as a closed node.\n\n    :attr:`hide_root` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    def get_selected_node(self):\n        return self._selected_node\n\n    selected_node = AliasProperty(get_selected_node, None,\n                                  bind=('_selected_node', ))\n    '''Node selected by :meth:`TreeView.select_node` or by touch.\n\n    :attr:`selected_node` is a :class:`~kivy.properties.AliasProperty` and\n    defaults to None. It is read-only.\n    '''\n\n    def get_root(self):\n        return self._root\n\n    root = AliasProperty(get_root, None, bind=('_root', ))\n    '''Root node.\n\n    By default, the root node widget is a :class:`TreeViewLabel` with text\n    'Root'. If you want to change the default options passed to the widget\n    creation, use the :attr:`root_options` property::\n\n        treeview = TreeView(root_options={\n            'text': 'Root directory',\n            'font_size': 15})\n\n    :attr:`root_options` will change the properties of the\n    :class:`TreeViewLabel` instance. However, you cannot change the class used\n    for root node yet.\n\n    :attr:`root` is an :class:`~kivy.properties.AliasProperty` and defaults to\n    None. It is read-only. However, the content of the widget can be changed.\n    '''\n\n    root_options = ObjectProperty({})\n    '''Default root options to pass for root widget. See :attr:`root` property\n    for more information about the usage of root_options.\n\n    :attr:`root_options` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to {}.\n    '''\n\n    load_func = ObjectProperty(None)\n    '''Callback to use for asynchronous loading. If set, asynchronous loading\n    will be automatically done. The callback must act as a Python generator\n    function, using yield to send data back to the treeview.\n\n    The callback should be in the format::\n\n        def callback(treeview, node):\n            for name in ('Item 1', 'Item 2'):\n                yield TreeViewLabel(text=name)\n\n    :attr:`load_func` is a :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n\nif __name__ == '__main__':\n    from kivy.app import App\n\n    class TestApp(App):\n\n        def build(self):\n            tv = TreeView(hide_root=True)\n            add = tv.add_node\n            root = add(TreeViewLabel(text='Level 1, entry 1', is_open=True))\n            for x in range(5):\n                add(TreeViewLabel(text='Element %d' % x), root)\n            root2 = add(TreeViewLabel(text='Level 1, entry 2', is_open=False))\n            for x in range(24):\n                add(TreeViewLabel(text='Element %d' % x), root2)\n            for x in range(5):\n                add(TreeViewLabel(text='Element %d' % x), root)\n            root2 = add(TreeViewLabel(text='Element childs 2', is_open=False),\n                        root)\n            for x in range(24):\n                add(TreeViewLabel(text='Element %d' % x), root2)\n            return tv\n    TestApp().run()\n"
  },
  {
    "path": "tickeys/kivy/uix/video.py",
    "content": "'''\nVideo\n=====\n\nThe :class:`Video` widget is used to display video files and streams.\nDepending on your Video core provider, platform, and plugins, you will\nbe able to play different formats. For example, the pygame video\nprovider only supports MPEG1 on Linux and OSX. GStreamer is more\nversatile, and can read many video containers and codecs such as MKV,\nOGV, AVI, MOV, FLV (if the correct gstreamer plugins are installed). Our\n:class:`~kivy.core.video.VideoBase` implementation is used under the\nhood.\n\nVideo loading is asynchronous - many properties are not available until\nthe video is loaded (when the texture is created)::\n\n    def on_position_change(instance, value):\n        print('The position in the video is', value)\n    def on_duration_change(instance, value):\n        print('The duration of the video is', video)\n    video = Video(source='PandaSneezes.avi')\n    video.bind(position=on_position_change,\n               duration=on_duration_change)\n\n'''\n\n__all__ = ('Video', )\n\nfrom kivy.clock import Clock\nfrom kivy.uix.image import Image\nfrom kivy.core.video import Video as CoreVideo\nfrom kivy.resources import resource_find\nfrom kivy.properties import (BooleanProperty, NumericProperty, ObjectProperty,\n                             OptionProperty)\n\n\nclass Video(Image):\n    '''Video class. See module documentation for more information.\n    '''\n\n    state = OptionProperty('stop', options=('play', 'pause', 'stop'))\n    '''String, indicates whether to play, pause, or stop the video::\n\n        # start playing the video at creation\n        video = Video(source='movie.mkv', state='play')\n\n        # create the video, and start later\n        video = Video(source='movie.mkv')\n        # and later\n        video.state = 'play'\n\n    :attr:`state` is an :class:`~kivy.properties.OptionProperty` and defaults\n    to 'stop'.\n    '''\n\n    play = BooleanProperty(False)\n    '''\n    .. deprecated:: 1.4.0\n        Use :attr:`state` instead.\n\n    Boolean, indicates whether the video is playing or not.\n    You can start/stop the video by setting this property::\n\n        # start playing the video at creation\n        video = Video(source='movie.mkv', play=True)\n\n        # create the video, and start later\n        video = Video(source='movie.mkv')\n        # and later\n        video.play = True\n\n    :attr:`play` is a :class:`~kivy.properties.BooleanProperty` and defaults to\n    False.\n\n    .. deprecated:: 1.4.0\n        Use :attr:`state` instead.\n    '''\n\n    eos = BooleanProperty(False)\n    '''Boolean, indicates whether the video has finished playing or not\n    (reached the end of the stream).\n\n    :attr:`eos` is a :class:`~kivy.properties.BooleanProperty` and defaults to\n    False.\n    '''\n\n    loaded = BooleanProperty(False)\n    '''Boolean, indicates whether the video is loaded and ready for playback\n    or not.\n\n    .. versionadded:: 1.6.0\n\n    :attr:`loaded` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    position = NumericProperty(-1)\n    '''Position of the video between 0 and :attr:`duration`. The position\n    defaults to -1 and is set to a real position when the video is loaded.\n\n    :attr:`position` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to -1.\n    '''\n\n    duration = NumericProperty(-1)\n    '''Duration of the video. The duration defaults to -1, and is set to a real\n    duration when the video is loaded.\n\n    :attr:`duration` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to -1.\n    '''\n\n    volume = NumericProperty(1.)\n    '''Volume of the video, in the range 0-1. 1 means full volume, 0\n    means mute.\n\n    :attr:`volume` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 1.\n    '''\n\n    options = ObjectProperty({})\n    '''Options to pass at Video core object creation.\n\n    .. versionadded:: 1.0.4\n\n    :attr:`options` is an :class:`kivy.properties.ObjectProperty` and defaults\n    to {}.\n    '''\n\n    def __init__(self, **kwargs):\n        self._video = None\n        super(Video, self).__init__(**kwargs)\n        self.bind(source=self._trigger_video_load)\n\n        if \"eos\" in kwargs:\n            self.options[\"eos\"] = kwargs[\"eos\"]\n        if self.source:\n            self._trigger_video_load()\n\n    def seek(self, percent):\n        '''Change the position to a percentage of duration. Percentage\n        must be a value between 0-1.\n\n        .. warning::\n\n            Calling seek() before the video is loaded has no impact.\n\n        .. versionadded:: 1.2.0\n        '''\n        if self._video is None:\n            raise Exception('Video not loaded.')\n        self._video.seek(percent)\n\n    def _trigger_video_load(self, *largs):\n        Clock.unschedule(self._do_video_load)\n        Clock.schedule_once(self._do_video_load, -1)\n\n    def _do_video_load(self, *largs):\n        if CoreVideo is None:\n            return\n        if self._video:\n            self._video.stop()\n        if not self.source:\n            self._video = None\n            self.texture = None\n        else:\n            filename = self.source\n            # Check if filename is not url\n            if not '://' in filename:\n                filename = resource_find(filename)\n            self._video = CoreVideo(filename=filename, **self.options)\n            self._video.volume = self.volume\n            self._video.bind(on_load=self._on_load,\n                             on_frame=self._on_video_frame,\n                             on_eos=self._on_eos)\n            if self.state == 'play' or self.play:\n                self._video.play()\n            self.duration = 1.\n            self.position = 0.\n\n    def on_play(self, instance, value):\n        value = 'play' if value else 'stop'\n        return self.on_state(instance, value)\n\n    def on_state(self, instance, value):\n        if not self._video:\n            return\n        if value == 'play':\n            if self.eos:\n                self._video.stop()\n                self._video.position = 0.\n                self._video.eos = False\n            self.eos = False\n            self._video.play()\n        elif value == 'pause':\n            self._video.pause()\n        else:\n            self._video.stop()\n            self._video.position = 0\n            self._video.eos = False\n\n    def _on_video_frame(self, *largs):\n        video = self._video\n        if not video:\n            return\n        self.duration = video.duration\n        self.position = video.position\n        self.texture = video.texture\n        self.canvas.ask_update()\n\n    def _on_eos(self, *largs):\n        if self._video.eos != 'loop':\n            self.state = 'stop'\n            self.eos = True\n\n    def _on_load(self, *largs):\n        self.loaded = True\n        self._on_video_frame(largs)\n\n    def on_volume(self, instance, value):\n        if self._video:\n            self._video.volume = value\n\n    def unload(self):\n        '''Unload the video. The playback will be stopped.\n\n        .. versionadded:: 1.8.0\n        '''\n        if self._video:\n            self._video.stop()\n            self._video.unload()\n            self._video = None\n\nif __name__ == '__main__':\n    from kivy.app import App\n    import sys\n\n    if len(sys.argv) != 2:\n        print(\"usage: %s file\" % sys.argv[0])\n        sys.exit(1)\n\n    class VideoApp(App):\n        def build(self):\n            self.v = Video(source=sys.argv[1], state='play')\n            self.v.bind(state=self.replay)\n            return self.v\n\n        def replay(self, *args):\n            if self.v.state == 'stop':\n                self.v.state = 'play'\n\n    VideoApp().run()\n"
  },
  {
    "path": "tickeys/kivy/uix/videoplayer.py",
    "content": "'''\nVideo player\n============\n\n.. versionadded:: 1.2.0\n\nThe video player widget can be used to play video and let the user control the\nplay/pausing, volume and position. The widget cannot be customized much because\nof the complex assembly of numerous base widgets.\n\n.. image:: images/videoplayer.jpg\n    :align: center\n\nAnnotations\n-----------\n\nIf you want to display text at a specific time and for a certain duration,\nconsider annotations. An annotation file has a \".jsa\" extension. The player\nwill automatically load the associated annotation file if it exists.\n\nAn annotation file is JSON-based, providing a list of label dictionary items.\nThe key and value must match one of the :class:`VideoPlayerAnnotation` items.\nFor example, here is a short version of a jsa file that you can find in\n`examples/widgets/softboy.jsa`::\n\n\n    [\n        {\"start\": 0, \"duration\": 2,\n        \"text\": \"This is an example of annotation\"},\n        {\"start\": 2, \"duration\": 2,\n        \"bgcolor\": [0.5, 0.2, 0.4, 0.5],\n        \"text\": \"You can change the background color\"}\n    ]\n\nFor our softboy.avi example, the result will be:\n\n.. image:: images/videoplayer-annotation.jpg\n    :align: center\n\nIf you want to experiment with annotation files, test with::\n\n    python -m kivy.uix.videoplayer examples/widgets/softboy.avi\n\nFullscreen\n----------\n\nThe video player can play the video in fullscreen, if\n:attr:`VideoPlayer.allow_fullscreen` is activated by a double-tap on\nthe video. By default, if the video is smaller than the Window, it will be not\nstretched.\n\nYou can allow stretching by passing custom options to a\n:class:`VideoPlayer` instance::\n\n    player = VideoPlayer(source='myvideo.avi', state='play',\n        options={'allow_stretch': True})\n\nEnd-of-stream behavior\n----------------------\n\nYou can specify what happens when the video has finished playing by passing an\n`eos` (end of stream) directive to the underlying\n:class:`~kivy.core.video.VideoBase` class. `eos` can be one of 'stop', 'pause'\nor 'loop' and defaults to 'stop'. For example, in order to loop the video::\n\n    player = VideoPlayer(source='myvideo.avi', state='play',\n        options={'eos': 'loop'})\n\n.. note::\n\n    The `eos` property of the VideoBase class is a string specifying the\n    end-of-stream behavior. This property differs from the `eos`\n    properties of the :class:`VideoPlayer` and\n    :class:`~kivy.uix.video.Video` classes, whose `eos`\n    property is simply a boolean indicating that the end of the file has\n    been reached.\n\n'''\n\n__all__ = ('VideoPlayer', 'VideoPlayerAnnotation')\n\nfrom json import load\nfrom os.path import exists\nfrom kivy.properties import ObjectProperty, StringProperty, BooleanProperty, \\\n    NumericProperty, DictProperty, OptionProperty\nfrom kivy.animation import Animation\nfrom kivy.uix.gridlayout import GridLayout\nfrom kivy.uix.floatlayout import FloatLayout\nfrom kivy.uix.progressbar import ProgressBar\nfrom kivy.uix.label import Label\nfrom kivy.uix.video import Video\nfrom kivy.uix.video import Image\nfrom kivy.factory import Factory\nfrom kivy.logger import Logger\nfrom kivy.clock import Clock\n\n\nclass VideoPlayerVolume(Image):\n    video = ObjectProperty(None)\n\n    def on_touch_down(self, touch):\n        if not self.collide_point(*touch.pos):\n            return False\n        touch.grab(self)\n        # save the current volume and delta to it\n        touch.ud[self.uid] = [self.video.volume, 0]\n        return True\n\n    def on_touch_move(self, touch):\n        if touch.grab_current is not self:\n            return\n        # calculate delta\n        dy = abs(touch.y - touch.oy)\n        if dy > 10:\n            dy = min(dy - 10, 100)\n            touch.ud[self.uid][1] = dy\n            self.video.volume = dy / 100.\n        return True\n\n    def on_touch_up(self, touch):\n        if touch.grab_current is not self:\n            return\n        touch.ungrab(self)\n        dy = abs(touch.y - touch.oy)\n        if dy < 10:\n            if self.video.volume > 0:\n                self.video.volume = 0\n            else:\n                self.video.volume = 1.\n\n\nclass VideoPlayerPlayPause(Image):\n    video = ObjectProperty(None)\n\n    def on_touch_down(self, touch):\n        '''.. versionchanged:: 1.4.0'''\n        if self.collide_point(*touch.pos):\n            if self.video.state == 'play':\n                self.video.state = 'pause'\n            else:\n                self.video.state = 'play'\n            return True\n\n\nclass VideoPlayerStop(Image):\n    video = ObjectProperty(None)\n\n    def on_touch_down(self, touch):\n        if self.collide_point(*touch.pos):\n            self.video.state = 'stop'\n            self.video.position = 0\n            return True\n\n\nclass VideoPlayerProgressBar(ProgressBar):\n    video = ObjectProperty(None)\n    seek = NumericProperty(None, allownone=True)\n    alpha = NumericProperty(1.)\n\n    def __init__(self, **kwargs):\n        super(VideoPlayerProgressBar, self).__init__(**kwargs)\n        self.bubble = Factory.Bubble(size=(50, 44))\n        self.bubble_label = Factory.Label(text='0:00')\n        self.bubble.add_widget(self.bubble_label)\n        self.add_widget(self.bubble)\n        self.bind(pos=self._update_bubble,\n                  size=self._update_bubble,\n                  seek=self._update_bubble)\n\n    def on_video(self, instance, value):\n        self.video.bind(position=self._update_bubble,\n                        state=self._showhide_bubble)\n\n    def on_touch_down(self, touch):\n        if not self.collide_point(*touch.pos):\n            return\n        self._show_bubble()\n        touch.grab(self)\n        self._update_seek(touch.x)\n        return True\n\n    def on_touch_move(self, touch):\n        if touch.grab_current is not self:\n            return\n        self._update_seek(touch.x)\n        return True\n\n    def on_touch_up(self, touch):\n        if touch.grab_current is not self:\n            return\n        touch.ungrab(self)\n        if self.seek:\n            self.video.seek(self.seek)\n        self.seek = None\n        self._hide_bubble()\n        return True\n\n    def _update_seek(self, x):\n        if self.width == 0:\n            return\n        x = max(self.x, min(self.right, x)) - self.x\n        self.seek = x / float(self.width)\n\n    def _show_bubble(self):\n        self.alpha = 1\n        Animation.stop_all(self, 'alpha')\n\n    def _hide_bubble(self):\n        self.alpha = 1.\n        Animation(alpha=0, d=4, t='in_out_expo').start(self)\n\n    def on_alpha(self, instance, value):\n        self.bubble.background_color = (1, 1, 1, value)\n        self.bubble_label.color = (1, 1, 1, value)\n\n    def _update_bubble(self, *l):\n        seek = self.seek\n        if self.seek is None:\n            if self.video.duration == 0:\n                seek = 0\n            else:\n                seek = self.video.position / self.video.duration\n        # convert to minutes:seconds\n        d = self.video.duration * seek\n        minutes = int(d / 60)\n        seconds = int(d - (minutes * 60))\n        # fix bubble label & position\n        self.bubble_label.text = '%d:%02d' % (minutes, seconds)\n        self.bubble.center_x = self.x + seek * self.width\n        self.bubble.y = self.top\n\n    def _showhide_bubble(self, instance, value):\n        if value == 'play':\n            self._hide_bubble()\n        else:\n            self._show_bubble()\n\n\nclass VideoPlayerPreview(FloatLayout):\n    source = ObjectProperty(None)\n    video = ObjectProperty(None)\n    click_done = BooleanProperty(False)\n\n    def on_touch_down(self, touch):\n        if self.collide_point(*touch.pos) and not self.click_done:\n            self.click_done = True\n            self.video.state = 'play'\n        return True\n\n\nclass VideoPlayerAnnotation(Label):\n    '''Annotation class used for creating annotation labels.\n\n    Additional keys are available:\n\n    * bgcolor: [r, g, b, a] - background color of the text box\n    * bgsource: 'filename' - background image used for the background text box\n    * border: (n, e, s, w) - border used for the background image\n\n    '''\n    start = NumericProperty(0)\n    '''Start time of the annotation.\n\n    :attr:`start` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 0.\n    '''\n\n    duration = NumericProperty(1)\n    '''Duration of the annotation.\n\n    :attr:`duration` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 1.\n    '''\n\n    annotation = DictProperty({})\n\n    def on_annotation(self, instance, ann):\n        for key, value in ann.items():\n            setattr(self, key, value)\n\n\nclass VideoPlayer(GridLayout):\n    '''VideoPlayer class. See module documentation for more information.\n    '''\n\n    source = StringProperty('')\n    '''Source of the video to read.\n\n    :attr:`source` is a :class:`~kivy.properties.StringProperty` and\n    defaults to ''.\n\n    .. versionchanged:: 1.4.0\n    '''\n\n    thumbnail = StringProperty('')\n    '''Thumbnail of the video to show. If None, VideoPlayer will try to find\n    the thumbnail from the :attr:`source` + '.png'.\n\n    :attr:`thumbnail` a :class:`~kivy.properties.StringProperty` and defaults\n    to ''.\n\n    .. versionchanged:: 1.4.0\n    '''\n\n    duration = NumericProperty(-1)\n    '''Duration of the video. The duration defaults to -1 and is set to the\n    real duration when the video is loaded.\n\n    :attr:`duration` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to -1.\n    '''\n\n    position = NumericProperty(0)\n    '''Position of the video between 0 and :attr:`duration`. The position\n    defaults to -1 and is set to the real position when the video is loaded.\n\n    :attr:`position` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to -1.\n    '''\n\n    volume = NumericProperty(1.0)\n    '''Volume of the video in the range 0-1. 1 means full volume and 0 means\n    mute.\n\n    :attr:`volume` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 1.\n    '''\n\n    state = OptionProperty('stop', options=('play', 'pause', 'stop'))\n    '''String, indicates whether to play, pause, or stop the video::\n\n        # start playing the video at creation\n        video = VideoPlayer(source='movie.mkv', state='play')\n\n        # create the video, and start later\n        video = VideoPlayer(source='movie.mkv')\n        # and later\n        video.state = 'play'\n\n    :attr:`state` is an :class:`~kivy.properties.OptionProperty` and defaults\n    to 'play'.\n    '''\n\n    play = BooleanProperty(False)\n    '''\n    .. deprecated:: 1.4.0\n        Use :attr:`state` instead.\n\n    Boolean, indicates whether the video is playing or not. You can start/stop\n    the video by setting this property::\n\n        # start playing the video at creation\n        video = VideoPlayer(source='movie.mkv', play=True)\n\n        # create the video, and start later\n        video = VideoPlayer(source='movie.mkv')\n        # and later\n        video.play = True\n\n    :attr:`play` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    image_overlay_play = StringProperty(\n        'atlas://data/images/defaulttheme/player-play-overlay')\n    '''Image filename used to show a \"play\" overlay when the video has not yet\n    started.\n\n    :attr:`image_overlay_play` is a\n    :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/player-play-overlay'.\n\n    '''\n\n    image_loading = StringProperty('data/images/image-loading.gif')\n    '''Image filename used when the video is loading.\n\n    :attr:`image_loading` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'data/images/image-loading.gif'.\n    '''\n\n    image_play = StringProperty(\n        'atlas://data/images/defaulttheme/media-playback-start')\n    '''Image filename used for the \"Play\" button.\n\n    :attr:`image_play` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/media-playback-start'.\n    '''\n\n    image_stop = StringProperty(\n        'atlas://data/images/defaulttheme/media-playback-stop')\n    '''Image filename used for the \"Stop\" button.\n\n    :attr:`image_stop` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/media-playback-stop'.\n    '''\n\n    image_pause = StringProperty(\n        'atlas://data/images/defaulttheme/media-playback-pause')\n    '''Image filename used for the \"Pause\" button.\n\n    :attr:`image_pause` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/media-playback-pause'.\n    '''\n\n    image_volumehigh = StringProperty(\n        'atlas://data/images/defaulttheme/audio-volume-high')\n    '''Image filename used for the volume icon when the volume is high.\n\n    :attr:`image_volumehigh` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/audio-volume-high'.\n    '''\n\n    image_volumemedium = StringProperty(\n        'atlas://data/images/defaulttheme/audio-volume-medium')\n    '''Image filename used for the volume icon when the volume is medium.\n\n    :attr:`image_volumemedium` is a :class:`~kivy.properties.StringProperty`\n    and defaults to 'atlas://data/images/defaulttheme/audio-volume-medium'.\n    '''\n\n    image_volumelow = StringProperty(\n        'atlas://data/images/defaulttheme/audio-volume-low')\n    '''Image filename used for the volume icon when the volume is low.\n\n    :attr:`image_volumelow` is a :class:`~kivy.properties.StringProperty`\n    and defaults to 'atlas://data/images/defaulttheme/audio-volume-low'.\n    '''\n\n    image_volumemuted = StringProperty(\n        'atlas://data/images/defaulttheme/audio-volume-muted')\n    '''Image filename used for the volume icon when the volume is muted.\n\n    :attr:`image_volumemuted` is a :class:`~kivy.properties.StringProperty`\n    and defaults to 'atlas://data/images/defaulttheme/audio-volume-muted'.\n    '''\n\n    annotations = StringProperty('')\n    '''If set, it will be used for reading annotations box.\n\n    :attr:`annotations` is a :class:`~kivy.properties.StringProperty`\n    and defaults to ''.\n    '''\n\n    fullscreen = BooleanProperty(False)\n    '''Switch to fullscreen view. This should be used with care. When\n    activated, the widget will remove itself from its parent, remove all\n    children from the window and will add itself to it. When fullscreen is\n    unset, all the previous children are restored and the widget is restored to\n    its previous parent.\n\n    .. warning::\n\n        The re-add operation doesn't care about the index position of it's\n        children within the parent.\n\n    :attr:`fullscreen` is a :class:`~kivy.properties.BooleanProperty`\n    and defaults to False.\n    '''\n\n    allow_fullscreen = BooleanProperty(True)\n    '''By default, you can double-tap on the video to make it fullscreen. Set\n    this property to False to prevent this behavior.\n\n    :attr:`allow_fullscreen` is a :class:`~kivy.properties.BooleanProperty`\n    defaults to True.\n    '''\n\n    options = DictProperty({})\n    '''Optional parameters can be passed to a :class:`~kivy.uix.video.Video`\n    instance with this property.\n\n    :attr:`options` a :class:`~kivy.properties.DictProperty` and\n    defaults to {}.\n    '''\n\n    # internals\n    container = ObjectProperty(None)\n\n    def __init__(self, **kwargs):\n        self._video = None\n        self._image = None\n        self._annotations = ''\n        self._annotations_labels = []\n        super(VideoPlayer, self).__init__(**kwargs)\n        self._load_thumbnail()\n        self._load_annotations()\n\n        if self.source:\n            self._trigger_video_load()\n\n    def _trigger_video_load(self, *largs):\n        Clock.unschedule(self._do_video_load)\n        Clock.schedule_once(self._do_video_load, -1)\n\n    def on_source(self, instance, value):\n        # we got a value, try to see if we have an image for it\n        self._load_thumbnail()\n        self._load_annotations()\n        if self._video is not None:\n            self._video.unload()\n            self._video = None\n        if value:\n            self._trigger_video_load()\n\n    def on_image_overlay_play(self, instance, value):\n        self._image.image_overlay_play = value\n\n    def on_image_loading(self, instance, value):\n        self._image.image_loading = value\n\n    def _load_thumbnail(self):\n        if not self.container:\n            return\n        self.container.clear_widgets()\n        # get the source, remove extension, and use png\n        thumbnail = self.thumbnail\n        if not thumbnail:\n            filename = self.source.rsplit('.', 1)\n            thumbnail = filename[0] + '.png'\n        self._image = VideoPlayerPreview(source=thumbnail, video=self)\n        self.container.add_widget(self._image)\n\n    def _load_annotations(self):\n        if not self.container:\n            return\n        self._annotations_labels = []\n        annotations = self.annotations\n        if not annotations:\n            filename = self.source.rsplit('.', 1)\n            annotations = filename[0] + '.jsa'\n        if exists(annotations):\n            with open(annotations, 'r') as fd:\n                self._annotations = load(fd)\n        if self._annotations:\n            for ann in self._annotations:\n                self._annotations_labels.append(\n                    VideoPlayerAnnotation(annotation=ann))\n\n    def on_state(self, instance, value):\n        if self._video is not None:\n            self._video.state = value\n\n    def _set_state(self, instance, value):\n        self.state = value\n\n    def _do_video_load(self, *largs):\n        self._video = Video(source=self.source, state=self.state,\n                            volume=self.volume, pos_hint={'x': 0, 'y': 0},\n                            **self.options)\n        self._video.bind(texture=self._play_started,\n                         duration=self.setter('duration'),\n                         position=self.setter('position'),\n                         volume=self.setter('volume'),\n                         state=self._set_state)\n\n    def on_play(self, instance, value):\n        value = 'play' if value else 'stop'\n        return self.on_state(instance, value)\n\n    def on_volume(self, instance, value):\n        if not self._video:\n            return\n        self._video.volume = value\n\n    def on_position(self, instance, value):\n        labels = self._annotations_labels\n        if not labels:\n            return\n        for label in labels:\n            start = label.start\n            duration = label.duration\n            if start > value or (start + duration) < value:\n                if label.parent:\n                    label.parent.remove_widget(label)\n            elif label.parent is None:\n                self.container.add_widget(label)\n\n    def seek(self, percent):\n        '''Change the position to a percentage of the duration. Percentage must\n        be a value between 0-1.\n\n        .. warning::\n\n            Calling seek() before video is loaded has no effect.\n        '''\n        if not self._video:\n            return\n        self._video.seek(percent)\n\n    def _play_started(self, instance, value):\n        self.container.clear_widgets()\n        self.container.add_widget(self._video)\n\n    def on_touch_down(self, touch):\n        if not self.collide_point(*touch.pos):\n            return False\n        if touch.is_double_tap and self.allow_fullscreen:\n            self.fullscreen = not self.fullscreen\n            return True\n        return super(VideoPlayer, self).on_touch_down(touch)\n\n    def on_fullscreen(self, instance, value):\n        window = self.get_parent_window()\n        if not window:\n            Logger.warning('VideoPlayer: Cannot switch to fullscreen, '\n                           'window not found.')\n            if value:\n                self.fullscreen = False\n            return\n        if not self.parent:\n            Logger.warning('VideoPlayer: Cannot switch to fullscreen, '\n                           'no parent.')\n            if value:\n                self.fullscreen = False\n            return\n\n        if value:\n            self._fullscreen_state = state = {\n                'parent': self.parent,\n                'pos': self.pos,\n                'size': self.size,\n                'pos_hint': self.pos_hint,\n                'size_hint': self.size_hint,\n                'window_children': window.children[:]}\n\n            # remove all window children\n            for child in window.children[:]:\n                window.remove_widget(child)\n\n            # put the video in fullscreen\n            if state['parent'] is not window:\n                state['parent'].remove_widget(self)\n            window.add_widget(self)\n\n            # ensure the video widget is in 0, 0, and the size will be\n            # reajusted\n            self.pos = (0, 0)\n            self.size = (100, 100)\n            self.pos_hint = {}\n            self.size_hint = (1, 1)\n        else:\n            state = self._fullscreen_state\n            window.remove_widget(self)\n            for child in state['window_children']:\n                window.add_widget(child)\n            self.pos_hint = state['pos_hint']\n            self.size_hint = state['size_hint']\n            self.pos = state['pos']\n            self.size = state['size']\n            if state['parent'] is not window:\n                state['parent'].add_widget(self)\n\n\nif __name__ == '__main__':\n    import sys\n    from kivy.base import runTouchApp\n    player = VideoPlayer(source=sys.argv[1])\n    runTouchApp(player)\n    if player:\n        player.state = 'stop'\n"
  },
  {
    "path": "tickeys/kivy/uix/vkeyboard.py",
    "content": "'''\nVKeyboard\n=========\n\n.. image:: images/vkeyboard.jpg\n    :align: right\n\n.. versionadded:: 1.0.8\n\n\nVKeyboard is an onscreen keyboard for Kivy. Its operation is intended to be\ntransparent to the user. Using the widget directly is NOT recommended. Read the\nsection `Request keyboard`_ first.\n\nModes\n-----\n\nThis virtual keyboard has a docked and free mode:\n\n* docked mode (:attr:`VKeyboard.docked` = True)\n  Generally used when only one person is using the computer, like a tablet or\n  personal computer etc.\n* free mode: (:attr:`VKeyboard.docked` = False)\n  Mostly for multitouch surfaces. This mode allows multiple virtual\n  keyboards to be used on the screen.\n\nIf the docked mode changes, you need to manually call\n:meth:`VKeyboard.setup_mode` otherwise the change will have no impact.\nDuring that call, the VKeyboard, implemented on top of a\n:class:`~kivy.uix.scatter.Scatter`, will change the\nbehavior of the scatter and position the keyboard near the target (if target\nand docked mode is set).\n\n\nLayouts\n-------\n\nThe virtual keyboard is able to load a custom layout. If you create a new\nlayout and put the JSON in :file:`<kivy_data_dir>/keyboards/<layoutid>.json`,\nyou can load it by setting :attr:`VKeyboard.layout` to your layoutid.\n\nThe JSON must be structured like this::\n\n    {\n        \"title\": \"Title of your layout\",\n        \"description\": \"Description of your layout\",\n        \"cols\": 15,\n        \"rows\": 5,\n\n        ...\n    }\n\nThen, you need to describe the keys in each row, for either a \"normal\",\n\"shift\" or a \"special\" (added in version 1.9.0) mode. Keys for this row\ndata must be named `normal_<row>`, `shift_<row>` and `special_<row>`.\nReplace `row` with the row number.\nInside each row, you will describe the key. A key is a 4 element list in\nthe format::\n\n    [ <text displayed on the keyboard>, <text to put when the key is pressed>,\n      <text that represents the keycode>, <size of cols> ]\n\nHere are example keys::\n\n    # f key\n    [\"f\", \"f\", \"f\", 1]\n    # capslock\n    [\"\\u21B9\", \"\\t\", \"tab\", 1.5]\n\nFinally, complete the JSON::\n\n    {\n        ...\n        \"normal_1\": [\n            [\"`\", \"`\", \"`\", 1],    [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],\n            [\"3\", \"3\", \"3\", 1],    [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],\n            [\"6\", \"6\", \"6\", 1],    [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],\n            [\"9\", \"9\", \"9\", 1],    [\"0\", \"0\", \"0\", 1],    [\"+\", \"+\", \"+\", 1],\n            [\"=\", \"=\", \"=\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n        ],\n\n        \"shift_1\": [ ... ],\n        \"normal_2\": [ ... ],\n        \"special_2\": [ ... ],\n        ...\n    }\n\n\nRequest Keyboard\n----------------\n\nThe instantiation of the virtual keyboard is controlled by the configuration.\nCheck `keyboard_mode` and `keyboard_layout` in the :doc:`api-kivy.config`.\n\nIf you intend to create a widget that requires a keyboard, do not use the\nvirtual keyboard directly, but prefer to use the best method available on\nthe platform. Check the :meth:`~kivy.core.window.WindowBase.request_keyboard`\nmethod in the :doc:`api-kivy.core.window`.\n\nIf you want a specific layout when you request the keyboard, you should write\nsomething like this (from 1.8.0, numeric.json can be in the same directory as\nyour main.py)::\n\n    keyboard = Window.request_keyboard(\n        self._keyboard_close, self)\n    if keyboard.widget:\n        vkeyboard = self._keyboard.widget\n        vkeyboard.layout = 'numeric.json'\n\n'''\n\n__all__ = ('VKeyboard', )\n\nfrom kivy import kivy_data_dir\nfrom kivy.vector import Vector\nfrom kivy.config import Config\nfrom kivy.uix.scatter import Scatter\nfrom kivy.uix.label import Label\nfrom kivy.properties import ObjectProperty, NumericProperty, StringProperty, \\\n    BooleanProperty, DictProperty, OptionProperty, ListProperty\nfrom kivy.logger import Logger\nfrom kivy.graphics import Color, BorderImage, Canvas\nfrom kivy.core.image import Image\nfrom kivy.resources import resource_find\nfrom kivy.clock import Clock\n\nfrom os.path import join, splitext, basename\nfrom os import listdir\nfrom json import loads\n\n\ndefault_layout_path = join(kivy_data_dir, 'keyboards')\n\n\nclass VKeyboard(Scatter):\n    '''\n    VKeyboard is an onscreen keyboard with multitouch support.\n    Its layout is entirely customizable and you can switch between available\n    layouts using a button in the bottom right of the widget.\n\n    :Events:\n        `on_key_down`: keycode, internal, modifiers\n            Fired when the keyboard received a key down event (key press).\n        `on_key_up`: keycode, internal, modifiers\n            Fired when the keyboard received a key up event (key release).\n    '''\n\n    target = ObjectProperty(None, allownone=True)\n    '''Target widget associated with the VKeyboard. If set, it will be used to\n    send keyboard events. If the VKeyboard mode is \"free\", it will also be used\n    to set the initial position.\n\n    :attr:`target` is an :class:`~kivy.properties.ObjectProperty` instance and\n    defaults to None.\n    '''\n\n    callback = ObjectProperty(None, allownone=True)\n    '''Callback can be set to a function that will be called if the\n    VKeyboard is closed by the user.\n\n    :attr:`target` is an :class:`~kivy.properties.ObjectProperty` instance and\n    defaults to None.\n    '''\n\n    layout = StringProperty(None)\n    '''Layout to use for the VKeyboard. By default, it will be the\n    layout set in the configuration, according to the `keyboard_layout`\n    in `[kivy]` section.\n\n    .. versionchanged:: 1.8.0\n        If layout is a .json filename, it will loaded and added to the\n        available_layouts.\n\n    :attr:`layout` is a :class:`~kivy.properties.StringProperty` and defaults\n    to None.\n    '''\n\n    layout_path = StringProperty(default_layout_path)\n    '''Path from which layouts are read.\n\n    :attr:`layout` is a :class:`~kivy.properties.StringProperty` and\n    defaults to :file:`<kivy_data_dir>/keyboards/`\n    '''\n\n    available_layouts = DictProperty({})\n    '''Dictionary of all available layouts. Keys are the layout ID, and the\n    value is the JSON (translated into a Python object).\n\n    :attr:`available_layouts` is a :class:`~kivy.properties.DictProperty` and\n    defaults to {}.\n    '''\n\n    docked = BooleanProperty(False)\n    '''Indicate whether the VKeyboard is docked on the screen or not. If you\n    change it, you must manually call :meth:`setup_mode` otherwise it will have\n    no impact. If the VKeyboard is created by the Window, the docked mode will\n    be automatically set by the configuration, using the `keyboard_mode` token\n    in `[kivy]` section.\n\n    :attr:`docked` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    margin_hint = ListProperty([.05, .06, .05, .06])\n    '''Margin hint, used as spacing between keyboard background and keys\n    content. The margin is composed of four values, between 0 and 1::\n\n        margin_hint = [top, right, bottom, left]\n\n    The margin hints will be multiplied by width and height, according to their\n    position.\n\n    :attr:`margin_hint` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [.05, .06, .05, .06]\n    '''\n\n    key_margin = ListProperty([2, 2, 2, 2])\n    '''Key margin, used to create space between keys. The margin is composed of\n    four values, in pixels::\n\n        key_margin = [top, right, bottom, left]\n\n    :attr:`key_margin` is a :class:`~kivy.properties.ListProperty` and defaults\n    to [2, 2, 2, 2]\n    '''\n\n    background_color = ListProperty([1, 1, 1, 1])\n    '''Background color, in the format (r, g, b, a). If a background is\n    set, the color will be combined with the background texture.\n\n    :attr:`background_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [1, 1, 1, 1].\n    '''\n\n    background = StringProperty(\n        'atlas://data/images/defaulttheme/vkeyboard_background')\n    '''Filename of the background image.\n\n    :attr:`background` a :class:`~kivy.properties.StringProperty` and defaults\n    to :file:`atlas://data/images/defaulttheme/vkeyboard_background`.\n    '''\n\n    background_disabled = StringProperty(\n        'atlas://data/images/defaulttheme/vkeyboard_disabled_background')\n    '''Filename of the background image when vkeyboard is disabled.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`background_disabled` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    :file:`atlas://data/images/defaulttheme/vkeyboard__disabled_background`.\n\n    '''\n\n    key_background_color = ListProperty([1, 1, 1, 1])\n    '''Key background color, in the format (r, g, b, a). If a key background is\n    set, the color will be combined with the key background texture.\n\n    :attr:`key_background_color` is a :class:`~kivy.properties.ListProperty`\n    and defaults to [1, 1, 1, 1].\n    '''\n\n    key_background_normal = StringProperty(\n        'atlas://data/images/defaulttheme/vkeyboard_key_normal')\n    '''Filename of the key background image for use when no touches are active\n    on the widget.\n\n    :attr:`key_background_normal` a :class:`~kivy.properties.StringProperty`\n    and defaults to\n    :file:`atlas://data/images/defaulttheme/vkeyboard_key_normal`.\n    '''\n\n    key_disabled_background_normal = StringProperty(\n        'atlas://data/images/defaulttheme/vkeyboard_key_normal')\n    '''Filename of the key background image for use when no touches are active\n    on the widget and vkeyboard is disabled.\n\n    ..versionadded:: 1.8.0\n\n    :attr:`key_disabled_background_normal` a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    :file:`atlas://data/images/defaulttheme/vkeyboard_disabled_key_normal`.\n\n    '''\n\n    key_background_down = StringProperty(\n        'atlas://data/images/defaulttheme/vkeyboard_key_down')\n    '''Filename of the key background image for use when a touch is active\n    on the widget.\n\n    :attr:`key_background_down` a :class:`~kivy.properties.StringProperty`\n    and defaults to\n    :file:`atlas://data/images/defaulttheme/vkeyboard_key_down`.\n    '''\n\n    background_border = ListProperty([16, 16, 16, 16])\n    '''Background image border. Used for controlling the\n    :attr:`~kivy.graphics.vertex_instructions.BorderImage.border` property of\n    the background.\n\n    :attr:`background_border` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [16, 16, 16, 16]\n    '''\n\n    key_border = ListProperty([8, 8, 8, 8])\n    '''Key image border. Used for controlling the\n    :attr:`~kivy.graphics.vertex_instructions.BorderImage.border` property of\n    the key.\n\n    :attr:`key_border` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [16, 16, 16, 16]\n    '''\n\n    # XXX internal variables\n    layout_mode = OptionProperty('normal',\n        options=('normal', 'shift', 'special'))\n    layout_geometry = DictProperty({})\n    have_capslock = BooleanProperty(False)\n    have_shift = BooleanProperty(False)\n    have_special = BooleanProperty(False)\n    active_keys = DictProperty({})\n    font_size = NumericProperty('20dp')\n    font_name = StringProperty('data/fonts/DroidSans.ttf')\n    repeat_touch = ObjectProperty(allownone=True)\n\n    __events__ = ('on_key_down', 'on_key_up', 'on_textinput')\n\n    def __init__(self, **kwargs):\n        # XXX move to style.kv\n        kwargs.setdefault('size_hint', (None, None))\n        kwargs.setdefault('scale_min', .4)\n        kwargs.setdefault('scale_max', 1.6)\n        kwargs.setdefault('size', (700, 200))\n        kwargs.setdefault('docked', False)\n        self._trigger_update_layout_mode = Clock.create_trigger(\n            self._update_layout_mode)\n        self._trigger_load_layouts = Clock.create_trigger(\n            self._load_layouts)\n        self._trigger_load_layout = Clock.create_trigger(\n            self._load_layout)\n        self.bind(\n            docked=self.setup_mode,\n            have_shift=self._trigger_update_layout_mode,\n            have_capslock=self._trigger_update_layout_mode,\n            have_special=self._trigger_update_layout_mode,\n            layout_path=self._trigger_load_layouts,\n            layout=self._trigger_load_layout)\n        super(VKeyboard, self).__init__(**kwargs)\n\n        # load all the layouts found in the layout_path directory\n        self._load_layouts()\n\n        # ensure we have default layouts\n        available_layouts = self.available_layouts\n        if not available_layouts:\n            Logger.critical('VKeyboard: unable to load default layouts')\n\n        # load the default layout from configuration\n        if self.layout is None:\n            self.layout = Config.get('kivy', 'keyboard_layout')\n        else:\n            # ensure the current layout is found on the available layout\n            self._trigger_load_layout()\n\n        # update layout mode (shift or normal)\n        self._trigger_update_layout_mode()\n\n        # create a top layer to draw active keys on\n        with self.canvas:\n            self.background_key_layer = Canvas()\n            self.active_keys_layer = Canvas()\n\n    def on_disabled(self, intance, value):\n        self.refresh_keys()\n\n    def _update_layout_mode(self, *l):\n        # update mode according to capslock and shift key\n        mode = self.have_capslock != self.have_shift\n        mode = 'shift' if mode else 'normal'\n        if self.have_special:\n            mode = \"special\"\n        if mode != self.layout_mode:\n            self.layout_mode = mode\n            self.refresh(False)\n\n    def _load_layout(self, *largs):\n        # ensure new layouts are loaded first\n        if self._trigger_load_layouts.is_triggered:\n            self._load_layouts()\n            self._trigger_load_layouts.cancel()\n\n        value = self.layout\n        available_layouts = self.available_layouts\n\n        # it's a filename, try to load it directly\n        if self.layout[-5:] == '.json':\n            if value not in available_layouts:\n                fn = resource_find(self.layout)\n                self._load_layout_fn(fn, self.layout)\n\n        if not available_layouts:\n            return\n        if value not in available_layouts and value != 'qwerty':\n            Logger.error(\n                'Vkeyboard: <%s> keyboard layout mentioned in '\n                'conf file was not found, fallback on qwerty' %\n                value)\n            self.layout = 'qwerty'\n        self.refresh(True)\n\n    def _load_layouts(self, *largs):\n        # first load available layouts from json files\n        # XXX fix to be able to reload layout when path is changing\n        value = self.layout_path\n        for fn in listdir(value):\n            self._load_layout_fn(join(value, fn),\n                                 basename(splitext(fn)[0]))\n\n    def _load_layout_fn(self, fn, name):\n        available_layouts = self.available_layouts\n        if fn[-5:] != '.json':\n            return\n        with open(fn, 'r') as fd:\n            json_content = fd.read()\n            layout = loads(json_content)\n        available_layouts[name] = layout\n\n    def setup_mode(self, *largs):\n        '''Call this method when you want to readjust the keyboard according to\n        options: :attr:`docked` or not, with attached :attr:`target` or not:\n\n        * If :attr:`docked` is True, it will call :meth:`setup_mode_dock`\n        * If :attr:`docked` is False, it will call :meth:`setup_mode_free`\n\n        Feel free to overload these methods to create new\n        positioning behavior.\n        '''\n        if self.docked:\n            self.setup_mode_dock()\n        else:\n            self.setup_mode_free()\n\n    def setup_mode_dock(self, *largs):\n        '''Setup the keyboard in docked mode.\n\n        Dock mode will reset the rotation, disable translation, rotation and\n        scale. Scale and position will be automatically adjusted to attach the\n        keyboard to the bottom of the screen.\n\n        .. note::\n            Don't call this method directly, use :meth:`setup_mode` instead.\n        '''\n        self.do_translation = False\n        self.do_rotation = False\n        self.do_scale = False\n        self.rotation = 0\n        win = self.get_parent_window()\n        scale = win.width / float(self.width)\n        self.scale = scale\n        self.pos = 0, 0\n        win.bind(on_resize=self._update_dock_mode)\n\n    def _update_dock_mode(self, win, *largs):\n        scale = win.width / float(self.width)\n        self.scale = scale\n        self.pos = 0, 0\n\n    def setup_mode_free(self):\n        '''Setup the keyboard in free mode.\n\n        Free mode is designed to let the user control the position and\n        orientation of the keyboard. The only real usage is for a multiuser\n        environment, but you might found other ways to use it.\n        If a :attr:`target` is set, it will place the vkeyboard under the\n        target.\n\n        .. note::\n            Don't call this method directly, use :meth:`setup_mode` instead.\n        '''\n        self.do_translation = True\n        self.do_rotation = True\n        self.do_scale = True\n        target = self.target\n        if not target:\n            return\n\n        # NOTE all math will be done in window point of view\n        # determine rotation of the target\n        a = Vector(1, 0)\n        b = Vector(target.to_window(0, 0))\n        c = Vector(target.to_window(1, 0)) - b\n        self.rotation = -a.angle(c)\n\n        # determine the position of center/top of the keyboard\n        dpos = Vector(self.to_window(self.width / 2., self.height))\n\n        # determine the position of center/bottom of the target\n        cpos = Vector(target.to_window(target.center_x, target.y))\n\n        # the goal now is to map both point, calculate the diff between them\n        diff = dpos - cpos\n\n        # we still have an issue, self.pos represent the bounding box,\n        # not the 0,0 coordinate of the scatter. we need to apply also\n        # the diff between them (inside and outside coordinate matrix).\n        # It's hard to explain, but do a scheme on a paper, write all\n        # the vector i'm calculating, and you'll understand. :)\n        diff2 = Vector(self.x + self.width / 2., self.y + self.height) - \\\n            Vector(self.to_parent(self.width / 2., self.height))\n        diff -= diff2\n\n        # now we have a good \"diff\", set it as a pos.\n        self.pos = -diff\n\n    def change_layout(self):\n        # XXX implement popup with all available layouts\n        pass\n\n    def refresh(self, force=False):\n        '''(internal) Recreate the entire widget and graphics according to the\n        selected layout.\n        '''\n        self.clear_widgets()\n        if force:\n            self.refresh_keys_hint()\n        self.refresh_keys()\n        self.refresh_active_keys_layer()\n\n    def refresh_active_keys_layer(self):\n        self.active_keys_layer.clear()\n\n        active_keys = self.active_keys\n        layout_geometry = self.layout_geometry\n        background = resource_find(self.key_background_down)\n        texture = Image(background, mipmap=True).texture\n\n        with self.active_keys_layer:\n            Color(1, 1, 1)\n            for line_nb, index in active_keys.values():\n                pos, size = layout_geometry['LINE_%d' % line_nb][index]\n                BorderImage(texture=texture, pos=pos, size=size,\n                            border=self.key_border)\n\n    def refresh_keys_hint(self):\n        layout = self.available_layouts[self.layout]\n        layout_cols = layout['cols']\n        layout_rows = layout['rows']\n        layout_geometry = self.layout_geometry\n        mtop, mright, mbottom, mleft = self.margin_hint\n\n        # get relative EFFICIENT surface of the layout without external margins\n        el_hint = 1. - mleft - mright\n        eh_hint = 1. - mtop - mbottom\n        ex_hint = 0 + mleft\n        ey_hint = 0 + mbottom\n\n        # get relative unit surface\n        uw_hint = (1. / layout_cols) * el_hint\n        uh_hint = (1. / layout_rows) * eh_hint\n        layout_geometry['U_HINT'] = (uw_hint, uh_hint)\n\n        # calculate individual key RELATIVE surface and pos (without key\n        # margin)\n        current_y_hint = ey_hint + eh_hint\n        for line_nb in range(1, layout_rows + 1):\n            current_y_hint -= uh_hint\n            # get line_name\n            line_name = '%s_%d' % (self.layout_mode, line_nb)\n            line_hint = 'LINE_HINT_%d' % line_nb\n            layout_geometry[line_hint] = []\n            current_x_hint = ex_hint\n            # go through the list of keys (tuples of 4)\n            for key in layout[line_name]:\n                # calculate relative pos, size\n                layout_geometry[line_hint].append([\n                    (current_x_hint, current_y_hint),\n                    (key[3] * uw_hint, uh_hint)])\n                current_x_hint += key[3] * uw_hint\n\n        self.layout_geometry = layout_geometry\n\n    def refresh_keys(self):\n        layout = self.available_layouts[self.layout]\n        layout_rows = layout['rows']\n        layout_geometry = self.layout_geometry\n        w, h = self.size\n        kmtop, kmright, kmbottom, kmleft = self.key_margin\n        uw_hint, uh_hint = layout_geometry['U_HINT']\n\n        for line_nb in range(1, layout_rows + 1):\n            llg = layout_geometry['LINE_%d' % line_nb] = []\n            llg_append = llg.append\n            for key in layout_geometry['LINE_HINT_%d' % line_nb]:\n                x_hint, y_hint = key[0]\n                w_hint, h_hint = key[1]\n                kx = x_hint * w\n                ky = y_hint * h\n                kw = w_hint * w\n                kh = h_hint * h\n\n                # now adjust, considering the key margin\n                kx = int(kx + kmleft)\n                ky = int(ky + kmbottom)\n                kw = int(kw - kmleft - kmright)\n                kh = int(kh - kmbottom - kmtop)\n\n                pos = (kx, ky)\n                size = (kw, kh)\n                llg_append((pos, size))\n\n        self.layout_geometry = layout_geometry\n        self.draw_keys()\n\n    def draw_keys(self):\n        layout = self.available_layouts[self.layout]\n        layout_rows = layout['rows']\n        layout_geometry = self.layout_geometry\n        layout_mode = self.layout_mode\n\n        # draw background\n        w, h = self.size\n\n        background = resource_find(self.background_disabled\n                                   if self.disabled else\n                                   self.background)\n        texture = Image(background, mipmap=True).texture\n        self.background_key_layer.clear()\n        with self.background_key_layer:\n            Color(*self.background_color)\n            BorderImage(texture=texture, size=self.size,\n                        border=self.background_border)\n\n        # XXX seperate drawing the keys and the fonts to avoid\n        # XXX reloading the texture each time\n\n        # first draw keys without the font\n        key_normal = resource_find(self.key_background_disabled_normal\n                                   if self.disabled else\n                                   self.key_background_normal)\n        texture = Image(key_normal, mipmap=True).texture\n        with self.background_key_layer:\n            for line_nb in range(1, layout_rows + 1):\n                for pos, size in layout_geometry['LINE_%d' % line_nb]:\n                        BorderImage(texture=texture, pos=pos, size=size,\n                                    border=self.key_border)\n\n        # then draw the text\n        # calculate font_size\n        font_size = int(w) / 46\n        # draw\n        for line_nb in range(1, layout_rows + 1):\n            key_nb = 0\n            for pos, size in layout_geometry['LINE_%d' % line_nb]:\n                # retrieve the relative text\n                text = layout[layout_mode + '_' + str(line_nb)][key_nb][0]\n                l = Label(text=text, font_size=font_size, pos=pos, size=size,\n                          font_name=self.font_name)\n                self.add_widget(l)\n                key_nb += 1\n\n    def on_key_down(self, *largs):\n        pass\n\n    def on_key_up(self, *largs):\n        pass\n\n    def on_textinput(self, *largs):\n        pass\n\n    def get_key_at_pos(self, x, y):\n        w, h = self.size\n        x_hint = x / w\n        # focus on the surface without margins\n        layout_geometry = self.layout_geometry\n        layout = self.available_layouts[self.layout]\n        layout_rows = layout['rows']\n        mtop, mright, mbottom, mleft = self.margin_hint\n\n        # get the line of the layout\n        e_height = h - (mbottom + mtop) * h  # efficient height in pixels\n        line_height = e_height / layout_rows  # line height in px\n        y = y - mbottom * h\n        line_nb = layout_rows - int(y / line_height)\n\n        if line_nb > layout_rows:\n            line_nb = layout_rows\n        if line_nb < 1:\n            line_nb = 1\n\n        # get the key within the line\n        key_index = ''\n        current_key_index = 0\n        for key in layout_geometry['LINE_HINT_%d' % line_nb]:\n            if x_hint >= key[0][0] and x_hint < key[0][0] + key[1][0]:\n                key_index = current_key_index\n                break\n            else:\n                current_key_index += 1\n        if key_index == '':\n            return None\n\n        # get the full character\n        key = layout['%s_%d' % (self.layout_mode, line_nb)][key_index]\n\n        return [key, (line_nb, key_index)]\n\n    def collide_margin(self, x, y):\n        '''Do a collision test, and return True if the (x, y) is inside the\n        vkeyboard margin.\n        '''\n        mtop, mright, mbottom, mleft = self.margin_hint\n        x_hint = x / self.width\n        y_hint = y / self.height\n        if x_hint > mleft and x_hint < 1. - mright \\\n                and y_hint > mbottom and y_hint < 1. - mtop:\n            return False\n        return True\n\n    def process_key_on(self, touch):\n        x, y = self.to_local(*touch.pos)\n        key = self.get_key_at_pos(x, y)\n        if not key:\n            return\n\n        key_data = key[0]\n        displayed_char, internal, special_char, size = key_data\n        line_nb, key_index = key[1]\n\n        # save pressed key on the touch\n        ud = touch.ud[self.uid] = {}\n        ud['key'] = key\n\n        # for caps lock or shift only:\n        uid = touch.uid\n        if special_char is not None:\n            # Do not repeat special keys\n            if special_char in ('capslock', 'shift', 'layout', 'special'):\n                Clock.unschedule(self._start_repeat_key)\n                self.repeat_touch = None\n            if special_char == 'capslock':\n                self.have_capslock = not self.have_capslock\n                uid = -1\n            elif special_char == 'shift':\n                self.have_shift = True\n            elif special_char == 'special':\n                self.have_special = True\n            elif special_char == 'layout':\n                self.change_layout()\n\n        # send info to the bus\n        b_keycode = special_char\n        b_modifiers = self._get_modifiers()\n        if self.get_parent_window().__class__.__module__ == \\\n            'kivy.core.window.window_sdl2' and internal:\n            self.dispatch('on_textinput', internal)\n        else:\n            self.dispatch('on_key_down', b_keycode, internal, b_modifiers)\n\n        # save key as an active key for drawing\n        self.active_keys[uid] = key[1]\n        self.refresh_active_keys_layer()\n\n    def process_key_up(self, touch):\n        uid = touch.uid\n        if self.uid not in touch.ud:\n            return\n\n        # save pressed key on the touch\n        key_data, key = touch.ud[self.uid]['key']\n        displayed_char, internal, special_char, size = key_data\n\n        # send info to the bus\n        b_keycode = special_char\n        b_modifiers = self._get_modifiers()\n        self.dispatch('on_key_up', b_keycode, internal, b_modifiers)\n\n        if special_char == 'capslock':\n            uid = -1\n\n        if uid in self.active_keys:\n            self.active_keys.pop(uid, None)\n            if special_char == 'shift':\n                self.have_shift = False\n            elif special_char == 'special':\n                self.have_special = False\n            if special_char == 'capslock' and self.have_capslock:\n                self.active_keys[-1] = key\n            self.refresh_active_keys_layer()\n\n    def _get_modifiers(self):\n        ret = []\n        if self.have_shift:\n            ret.append('shift')\n        if self.have_capslock:\n            ret.append('capslock')\n        return ret\n\n    def _start_repeat_key(self, *kwargs):\n        Clock.schedule_interval(self._repeat_key, 0.05)\n\n    def _repeat_key(self, *kwargs):\n        self.process_key_on(self.repeat_touch)\n\n    def on_touch_down(self, touch):\n        x, y = touch.pos\n        if not self.collide_point(x, y):\n            return\n        if self.disabled:\n            return True\n\n        x, y = self.to_local(x, y)\n        if not self.collide_margin(x, y):\n            if self.repeat_touch is None:\n                Clock.schedule_once(self._start_repeat_key, 0.5)\n            self.repeat_touch = touch\n\n            self.process_key_on(touch)\n            touch.grab(self, exclusive=True)\n\n        else:\n            super(VKeyboard, self).on_touch_down(touch)\n        return True\n\n    def on_touch_up(self, touch):\n        if touch.grab_current is self:\n            self.process_key_up(touch)\n\n            Clock.unschedule(self._start_repeat_key)\n            if touch == self.repeat_touch:\n                Clock.unschedule(self._repeat_key)\n                self.repeat_touch = None\n\n        return super(VKeyboard, self).on_touch_up(touch)\n\n\nif __name__ == '__main__':\n    from kivy.base import runTouchApp\n    vk = VKeyboard(layout='azerty')\n    runTouchApp(vk)\n"
  },
  {
    "path": "tickeys/kivy/uix/widget.py",
    "content": "'''\nWidget class\n============\n\nThe :class:`Widget` class is the base class required to create a Widget.\nThis widget class is designed with a couple of principles in mind:\n\n    Event Driven\n        Widget interaction is built on top of events that occur. If a property\n        changes, the widget can respond to the change in the 'on_<propname>'\n        callback. If nothing changes, nothing will be done. That's the main\n        goal of the :class:`~kivy.properties.Property` class.\n\n    Separate the widget and its graphical representation\n        Widgets don't have a `draw()` method. This is done on purpose: The idea\n        is to allow you to create your own graphical representation outside the\n        widget class.\n        Obviously you can still use all the available properties to do that, so\n        that your representation properly reflects the widget's current state.\n        Every widget has its own :class:`~kivy.graphics.Canvas` that you\n        can use to draw. This separation allows Kivy to run your\n        application in a very efficient manner.\n\n    Bounding Box / Collision\n        Often you want to know if a certain point is within the bounds of your\n        widget. An example would be a button widget where you want to only\n        trigger an action when the button itself is actually touched.\n        For this, you can use the :meth:`Widget.collide_point` method, which\n        will return True if the point you pass to it is inside the axis-aligned\n        bounding box defined by the widget's position and size.\n        If a simple AABB is not sufficient, you can override the method to\n        perform the collision checks with more complex shapes, e.g. a polygon.\n        You can also check if a widget collides with another widget with\n        :meth:`Widget.collide_widget`.\n\n\nWe also have some default values and behaviors that you should be aware of:\n\n* A :class:`Widget` is not a :class:`~kivy.uix.layout.Layout`: it will not\n  change the position or the size of its children. If you want control over\n  positioning or sizing, use a :class:`~kivy.uix.layout.Layout`.\n\n* The default size of a widget is (100, 100). This is only changed if the\n  parent is a :class:`~kivy.uix.layout.Layout`.\n  For example, if you add a :class:`Label` inside a\n  :class:`Button`, the label will not inherit the button's size or position\n  because the button is not a *Layout*: it's just another *Widget*.\n\n* The default size_hint is (1, 1). If the parent is a :class:`Layout`, then the\n  widget size will be the parent layout's size.\n\n* :meth:`Widget.on_touch_down`, :meth:`Widget.on_touch_move`,\n  :meth:`Widget.on_touch_up` don't do any sort of collisions. If you want to\n  know if the touch is inside your widget, use :meth:`Widget.collide_point`.\n\nUsing Properties\n----------------\n\nWhen you read the documentation, all properties are described in the format::\n\n    <name> is a <property class> and defaults to <default value>.\n\ne.g.\n\n    :attr:`~kivy.uix.label.Label.text` is a\n    :class:`~kivy.properties.StringProperty` and defaults to ''.\n\nIf you want to be notified when the pos attribute changes, i.e. when the\nwidget moves, you can bind your own callback function like this::\n\n    def callback_pos(instance, value):\n        print('The widget', instance, 'moved to', value)\n\n    wid = Widget()\n    wid.bind(pos=callback_pos)\n\nRead more about :doc:`/api-kivy.properties`.\n\nBasic drawing\n-------------\n\nWidgets support a range of drawing instructions that you can use to customize\nthe look of your widgets and layouts. For example, to draw a background image\nfor your widget, you can do the following:\n\n.. code-block:: python\n\n    def redraw(self, args):\n        self.bg_rect.size = self.size\n        self.bg_rect.pos = self.pos\n\n    widget = Widget()\n    with widget.canvas:\n        widget.bg_rect = Rectangle(source=\"cover.jpg\", pos=self.pos, \\\nsize=self.size)\n    widget.bind(pos=redraw, size=redraw)\n\nTo draw a background in kv::\n\n    Widget:\n        canvas:\n            Rectangle:\n                source: \"cover.jpg\"\n                size: self.size\n                pos: self.pos\n\nThese examples only scratch the surface. Please see the :mod:`kivy.graphics`\ndocumentation for more information.\n\n.. _widget-event-bubbling:\n\nWidget touch event bubbling\n---------------------------\n\nWhen you catch touch events between multiple widgets, you often\nneed to be aware of the order in which these events are propogated. In Kivy,\nevents bubble up from the most recently added widget and then backwards through\nits children (from the most recently added back to the first child). This order\nis the same for the `on_touch_move` and `on_touch_up` events.\n\nIf you want to reverse this order, you can raise events in the children before\nthe parent by using the `super` command. For example:\n\n.. code-block:: python\n\n    class MyWidget(Widget):\n        def on_touch_down(self, touch):\n            super(MyWidget, self).on_touch_down(touch)\n            # Do stuff here\n\nIn general, this would seldom be the best approach as every event bubbles all\nthe way through event time and there is no way of determining if it has been\nhandled. In order to stop this event bubbling, one of these methods must\nreturn `True`. At this point, Kivy assumes the event has been handled and the\npropogation stops.\n\nThis means that the recommended approach is to let the event bubble naturally\nbut swallow the event if it has been handled. For example:\n\n.. code-block:: python\n\n    class MyWidget(Widget):\n        def on_touch_down(self, touch):\n            If <some_condition>:\n                # Do stuff here and kill the event\n                return True\n            else:\n                # Continue normal event bubbling\n                return super(MyWidget, self).on_touch_down(touch)\n\nThis approach gives you good control over exactly how events are dispatched\nand managed. Sometimes, however, you may wish to let the event be completely\npropogated before taking action. You can use the\n:class:`~kivy.clock.Clock` to help you here:\n\n.. code-block:: python\n\n    class MyLabel(Label):\n        def on_touch_down(self, touch, after=False):\n            if after:\n                print \"Fired after the event has been dispatched!\"\n            else:\n                Clock.schedule_once(lambda dt: self.on_touch_down(touch, True))\n                return super(MyLabel, self).on_touch_down(touch)\n\n'''\nfrom kivy.graphics.transformation import Matrix\n\n__all__ = ('Widget', 'WidgetException')\n\nfrom kivy.event import EventDispatcher\nfrom kivy.factory import Factory\nfrom kivy.properties import (NumericProperty, StringProperty, AliasProperty,\n                             ReferenceListProperty, ObjectProperty,\n                             ListProperty, DictProperty, BooleanProperty)\nfrom kivy.graphics import (Canvas, Translate, Fbo, ClearColor, ClearBuffers,\n                            Scale)\nfrom kivy.base import EventLoop\nfrom kivy.lang import Builder\nfrom kivy.context import get_current_context\nfrom kivy.weakproxy import WeakProxy\nfrom functools import partial\nfrom itertools import islice\n\n\n# References to all the widget destructors (partial method with widget uid as\n# key).\n_widget_destructors = {}\n\n\ndef _widget_destructor(uid, r):\n    # Internal method called when a widget is deleted from memory. the only\n    # thing we remember about it is its uid. Clear all the associated callbacks\n    # created in kv language.\n    del _widget_destructors[uid]\n    Builder.unbind_widget(uid)\n\n\nclass WidgetException(Exception):\n    '''Fired when the widget gets an exception.\n    '''\n    pass\n\n\nclass WidgetMetaclass(type):\n    '''Metaclass to automatically register new widgets for the\n    :class:`~kivy.factory.Factory`.\n\n    .. warning::\n        This metaclass is used by the Widget. Do not use it directly!\n    '''\n    def __init__(mcs, name, bases, attrs):\n        super(WidgetMetaclass, mcs).__init__(name, bases, attrs)\n        Factory.register(name, cls=mcs)\n\n\n#: Base class used for Widget, that inherits from :class:`EventDispatcher`\nWidgetBase = WidgetMetaclass('WidgetBase', (EventDispatcher, ), {})\n\n\nclass Widget(WidgetBase):\n    '''Widget class. See module documentation for more information.\n\n    :Events:\n        `on_touch_down`:\n            Fired when a new touch event occurs\n        `on_touch_move`:\n            Fired when an existing touch moves\n        `on_touch_up`:\n            Fired when an existing touch disappears\n\n    .. warning::\n        Adding a `__del__` method to a class derived from Widget with Python\n        prior to 3.4 will disable automatic garbage collection for instances\n        of that class. This is because the Widget class creates reference\n        cycles, thereby `preventing garbage collection\n        <https://docs.python.org/2/library/gc.html#gc.garbage>`_.\n\n    .. versionchanged:: 1.0.9\n        Everything related to event properties has been moved to the\n        :class:`~kivy.event.EventDispatcher`. Event properties can now be used\n        when contructing a simple class without subclassing :class:`Widget`.\n\n    .. versionchanged:: 1.5.0\n        The constructor now accepts on_* arguments to automatically bind\n        callbacks to properties or events, as in the Kv language.\n    '''\n\n    __metaclass__ = WidgetMetaclass\n    __events__ = ('on_touch_down', 'on_touch_move', 'on_touch_up')\n    _proxy_ref = None\n\n    def __init__(self, **kwargs):\n        # Before doing anything, ensure the windows exist.\n        EventLoop.ensure_window()\n\n        # Assign the default context of the widget creation.\n        if not hasattr(self, '_context'):\n            self._context = get_current_context()\n\n        super(Widget, self).__init__(**kwargs)\n\n        # Create the default canvas if it does not exist.\n        if self.canvas is None:\n            self.canvas = Canvas(opacity=self.opacity)\n\n        # Apply all the styles.\n        if '__no_builder' not in kwargs:\n            #current_root = Builder.idmap.get('root')\n            #Builder.idmap['root'] = self\n            Builder.apply(self)\n            #if current_root is not None:\n            #    Builder.idmap['root'] = current_root\n            #else:\n            #    Builder.idmap.pop('root')\n\n        # Bind all the events.\n        for argument in kwargs:\n            if argument[:3] == 'on_':\n                self.bind(**{argument: kwargs[argument]})\n\n    @property\n    def proxy_ref(self):\n        '''Return a proxy reference to the widget, i.e. without creating a\n        reference to the widget. See `weakref.proxy\n        <http://docs.python.org/2/library/weakref.html?highlight\\\n        =proxy#weakref.proxy>`_ for more information.\n\n        .. versionadded:: 1.7.2\n        '''\n        _proxy_ref = self._proxy_ref\n        if _proxy_ref is not None:\n            return _proxy_ref\n\n        f = partial(_widget_destructor, self.uid)\n        self._proxy_ref = _proxy_ref = WeakProxy(self, f)\n        # Only f should be enough here, but it appears that is a very\n        # specific case, the proxy destructor is not called if both f and\n        # _proxy_ref are not together in a tuple.\n        _widget_destructors[self.uid] = (f, _proxy_ref)\n        return _proxy_ref\n\n    def __hash__(self):\n        return id(self)\n\n    @property\n    def __self__(self):\n        return self\n\n    #\n    # Collision\n    #\n    def collide_point(self, x, y):\n        '''Check if a point (x, y) is inside the widget's axis aligned bounding\n        box.\n\n        :Parameters:\n            `x`: numeric\n                X position of the point (in window coordinates)\n            `y`: numeric\n                Y position of the point (in window coordinates)\n\n        :Returns:\n            bool, True if the point is inside the bounding box.\n\n    .. code-block:: python\n\n        >>> Widget(pos=(10, 10), size=(50, 50)).collide_point(40, 40)\n        True\n        '''\n        return self.x <= x <= self.right and self.y <= y <= self.top\n\n    def collide_widget(self, wid):\n        '''Check if the other widget collides with this widget.\n        Performs an axis-aligned bounding box intersection test by default.\n\n        :Parameters:\n            `wid`: :class:`Widget` class\n                Widget to collide with.\n\n        :Returns:\n            bool, True if the other widget collides with this widget.\n\n    .. code-block:: python\n\n        >>> wid = Widget(size=(50, 50))\n        >>> wid2 = Widget(size=(50, 50), pos=(25, 25))\n        >>> wid.collide_widget(wid2)\n        True\n        >>> wid2.pos = (55, 55)\n        >>> wid.collide_widget(wid2)\n        False\n        '''\n        if self.right < wid.x:\n            return False\n        if self.x > wid.right:\n            return False\n        if self.top < wid.y:\n            return False\n        if self.y > wid.top:\n            return False\n        return True\n\n    #\n    # Default event handlers\n    #\n    def on_touch_down(self, touch):\n        '''Receive a touch down event.\n\n        :Parameters:\n            `touch`: :class:`~kivy.input.motionevent.MotionEvent` class\n                Touch received. The touch is in parent coordinates. See\n                :mod:`~kivy.uix.relativelayout` for a discussion on\n                coordinate systems.\n\n        :Returns:\n            bool. If True, the dispatching of the touch event will stop.\n        '''\n        if self.disabled and self.collide_point(*touch.pos):\n            return True\n        for child in self.children[:]:\n            if child.dispatch('on_touch_down', touch):\n                return True\n\n    def on_touch_move(self, touch):\n        '''Receive a touch move event. The touch is in parent coordinates.\n\n        See :meth:`on_touch_down` for more information.\n        '''\n        if self.disabled:\n            return\n        for child in self.children[:]:\n            if child.dispatch('on_touch_move', touch):\n                return True\n\n    def on_touch_up(self, touch):\n        '''Receive a touch up event. The touch is in parent coordinates.\n\n        See :meth:`on_touch_down` for more information.\n        '''\n        if self.disabled:\n            return\n        for child in self.children[:]:\n            if child.dispatch('on_touch_up', touch):\n                return True\n\n    def on_disabled(self, instance, value):\n        for child in self.children:\n            child.disabled = value\n\n    #\n    # Tree management\n    #\n    def add_widget(self, widget, index=0, canvas=None):\n        '''Add a new widget as a child of this widget.\n\n        :Parameters:\n            `widget`: :class:`Widget`\n                Widget to add to our list of children.\n            `index`: int, defaults to 0\n                Index to insert the widget in the list.\n\n                .. versionadded:: 1.0.5\n            `canvas`: str, defaults to None\n                Canvas to add widget's canvas to. Can be 'before', 'after' or\n                None for the default canvas.\n\n                .. versionadded:: 1.9.0\n\n    .. code-block:: python\n\n        >>> from kivy.uix.button import Button\n        >>> from kivy.uix.slider import Slider\n        >>> root = Widget()\n        >>> root.add_widget(Button())\n        >>> slider = Slider()\n        >>> root.add_widget(slider)\n\n        '''\n        if not isinstance(widget, Widget):\n            raise WidgetException(\n                'add_widget() can be used only with instances'\n                ' of the Widget class.')\n\n        widget = widget.__self__\n        if widget is self:\n            raise WidgetException(\n                'Widget instances cannot be added to themselves.')\n        parent = widget.parent\n        # Check if the widget is already a child of another widget.\n        if parent:\n            raise WidgetException('Cannot add %r, it already has a parent %r'\n                                  % (widget, parent))\n        widget.parent = parent = self\n        # Child will be disabled if added to a disabled parent.\n        if parent.disabled:\n            widget.disabled = True\n\n        canvas = self.canvas.before if canvas == 'before' else \\\n            self.canvas.after if canvas == 'after' else self.canvas\n\n        if index == 0 or len(self.children) == 0:\n            self.children.insert(0, widget)\n            canvas.add(widget.canvas)\n        else:\n            canvas = self.canvas\n            children = self.children\n            if index >= len(children):\n                index = len(children)\n                next_index = 0\n            else:\n                next_child = children[index]\n                next_index = canvas.indexof(next_child.canvas)\n                if next_index == -1:\n                    next_index = canvas.length()\n                else:\n                    next_index += 1\n\n            children.insert(index, widget)\n            # We never want to insert widget _before_ canvas.before.\n            if next_index == 0 and canvas.has_before:\n                next_index = 1\n            canvas.insert(next_index, widget.canvas)\n\n    def remove_widget(self, widget):\n        '''Remove a widget from the children of this widget.\n\n        :Parameters:\n            `widget`: :class:`Widget`\n                Widget to remove from our children list.\n\n    .. code-block:: python\n\n        >>> from kivy.uix.button import Button\n        >>> root = Widget()\n        >>> button = Button()\n        >>> root.add_widget(button)\n        >>> root.remove_widget(button)\n        '''\n        if widget not in self.children:\n            return\n        self.children.remove(widget)\n        if widget.canvas in self.canvas.children:\n            self.canvas.remove(widget.canvas)\n        elif widget.canvas in self.canvas.after.children:\n            self.canvas.after.remove(widget.canvas)\n        elif widget.canvas in self.canvas.before.children:\n            self.canvas.before.remove(widget.canvas)\n        widget.parent = None\n\n    def clear_widgets(self, children=None):\n        '''Remove all widgets added to this widget.\n\n        .. versionchanged:: 1.8.0\n            `children` argument can be used to select the children we want to\n            remove. It should be a list of children (or filtered list) of the\n            current widget.\n        '''\n\n        if not children:\n            children = self.children\n        remove_widget = self.remove_widget\n        for child in children[:]:\n            remove_widget(child)\n\n    def export_to_png(self, filename, *args):\n        '''Saves an image of the widget and its children in png format at the\n        specified filename. Works by removing the widget canvas from its\n        parent, rendering to an :class:`~kivy.graphics.fbo.Fbo`, and calling\n        :meth:`~kivy.graphics.texture.Texture.save`.\n\n        .. note::\n\n            The image includes only this widget and its children. If you want\n            to include widgets elsewhere in the tree, you must call\n            :meth:`~Widget.export_to_png` from their common parent, or use\n            :meth:`~kivy.core.window.Window.screenshot` to capture the whole\n            window.\n\n        .. note::\n\n            The image will be saved in png format, you should include the\n            extension in your filename.\n\n        .. versionadded:: 1.9.0\n        '''\n\n        if self.parent is not None:\n            canvas_parent_index = self.parent.canvas.indexof(self.canvas)\n            self.parent.canvas.remove(self.canvas)\n\n        fbo = Fbo(size=self.size, with_stencilbuffer=True)\n\n        with fbo:\n            ClearColor(0, 0, 0, 1)\n            ClearBuffers()\n            Scale(1, -1, 1)\n            Translate(-self.x, -self.y - self.height, 0)\n\n        fbo.add(self.canvas)\n        fbo.draw()\n        fbo.texture.save(filename, flipped=False)\n        fbo.remove(self.canvas)\n\n        if self.parent is not None:\n            self.parent.canvas.insert(canvas_parent_index, self.canvas)\n\n        return True\n\n    def get_root_window(self):\n        '''Return the root window.\n\n        :Returns:\n            Instance of the root window. Can be a\n            :class:`~kivy.core.window.WindowBase` or\n            :class:`Widget`.\n        '''\n        if self.parent:\n            return self.parent.get_root_window()\n\n    def get_parent_window(self):\n        '''Return the parent window.\n\n        :Returns:\n            Instance of the parent window. Can be a\n            :class:`~kivy.core.window.WindowBase` or\n            :class:`Widget`.\n        '''\n        if self.parent:\n            return self.parent.get_parent_window()\n\n    def _walk(self, restrict=False, loopback=False, index=None):\n        # We pass index only when we are going on the parent\n        # so don't yield the parent as well.\n        if index is None:\n            index = len(self.children)\n            yield self\n\n        for child in reversed(self.children[:index]):\n            for walk_child in child._walk(restrict=True):\n                yield walk_child\n\n        # If we want to continue with our parent, just do it.\n        if not restrict:\n            parent = self.parent\n            try:\n                if parent is None or not isinstance(parent, Widget):\n                    raise ValueError\n                index = parent.children.index(self)\n            except ValueError:\n                # Self is root, if we want to loopback from the first element:\n                if not loopback:\n                    return\n                # If we started with root (i.e. index==None), then we have to\n                # start from root again, so we return self again. Otherwise, we\n                # never returned it, so return it now starting with it.\n                parent = self\n                index = None\n            for walk_child in parent._walk(loopback=loopback, index=index):\n                yield walk_child\n\n    def walk(self, restrict=False, loopback=False):\n        ''' Iterator that walks the widget tree starting with this widget and\n        goes forward returning widgets in the order in which layouts display\n        them.\n\n        :Parameters:\n            `restrict`: bool, defaults to False\n                If True, it will only iterate through the widget and its\n                children (or children of its children etc.). Defaults to False.\n            `loopback`: bool, defaults to False\n                If True, when the last widget in the tree is reached,\n                it'll loop back to the uppermost root and start walking until\n                we hit this widget again. Naturally, it can only loop back when\n                `restrict` is False. Defaults to False.\n\n        :return:\n            A generator that walks the tree, returning widgets in the\n            forward layout order.\n\n        For example, given a tree with the following structure::\n\n            GridLayout:\n                Button\n                BoxLayout:\n                    id: box\n                    Widget\n                    Button\n                Widget\n\n        walking this tree:\n\n        .. code-block:: python\n\n            >>> # Call walk on box with loopback True, and restrict False\n            >>> [type(widget) for widget in box.walk(loopback=True)]\n            [<class 'BoxLayout'>, <class 'Widget'>, <class 'Button'>,\n                <class 'Widget'>, <class 'GridLayout'>, <class 'Button'>]\n            >>> # Now with loopback False, and restrict False\n            >>> [type(widget) for widget in box.walk()]\n            [<class 'BoxLayout'>, <class 'Widget'>, <class 'Button'>,\n                <class 'Widget'>]\n            >>> # Now with restrict True\n            >>> [type(widget) for widget in box.walk(restrict=True)]\n            [<class 'BoxLayout'>, <class 'Widget'>, <class 'Button'>]\n\n        .. versionadded:: 1.9.0\n        '''\n        gen = self._walk(restrict, loopback)\n        yield next(gen)\n        for node in gen:\n            if node is self:\n                return\n            yield node\n\n    def _walk_reverse(self, loopback=False, go_up=False):\n        # process is walk up level, walk down its children tree, then walk up\n        # next level etc.\n        # default just walk down the children tree\n        root = self\n        index = 0\n        # we need to go up a level before walking tree\n        if go_up:\n            root = self.parent\n            try:\n                if root is None or not isinstance(root, Widget):\n                    raise ValueError\n                index = root.children.index(self) + 1\n            except ValueError:\n                if not loopback:\n                    return\n                index = 0\n                go_up = False\n                root = self\n\n        # now walk children tree starting with last-most child\n        for child in islice(root.children, index, None):\n            for walk_child in child._walk_reverse(loopback=loopback):\n                yield walk_child\n        # we need to return ourself last, in all cases\n        yield root\n\n        # if going up, continue walking up the parent tree\n        if go_up:\n            for walk_child in root._walk_reverse(loopback=loopback,\n                                                 go_up=go_up):\n                yield walk_child\n\n    def walk_reverse(self, loopback=False):\n        ''' Iterator that walks the widget tree backwards starting with the\n        widget before this, and going backwards returning widgets in the\n        reverse order in which layouts display them.\n\n        This walks in the opposite direction of :meth:`walk`, so a list of the\n        tree generated with :meth:`walk` will be in reverse order compared\n        to the list generated with this, provided `loopback` is True.\n\n        :Parameters:\n            `loopback`: bool, defaults to False\n                If True, when the uppermost root in the tree is\n                reached, it'll loop back to the last widget and start walking\n                back until after we hit widget again. Defaults to False.\n\n        :return:\n            A generator that walks the tree, returning widgets in the\n            reverse layout order.\n\n        For example, given a tree with the following structure::\n\n            GridLayout:\n                Button\n                BoxLayout:\n                    id: box\n                    Widget\n                    Button\n                Widget\n\n        walking this tree:\n\n        .. code-block:: python\n\n            >>> # Call walk on box with loopback True\n            >>> [type(widget) for widget in box.walk_reverse(loopback=True)]\n            [<class 'Button'>, <class 'GridLayout'>, <class 'Widget'>,\n                <class 'Button'>, <class 'Widget'>, <class 'BoxLayout'>]\n            >>> # Now with loopback False\n            >>> [type(widget) for widget in box.walk_reverse()]\n            [<class 'Button'>, <class 'GridLayout'>]\n            >>> forward = [w for w in box.walk(loopback=True)]\n            >>> backward = [w for w in box.walk_reverse(loopback=True)]\n            >>> forward == backward[::-1]\n            True\n\n        .. versionadded:: 1.9.0\n\n        '''\n        for node in self._walk_reverse(loopback=loopback, go_up=True):\n            yield node\n            if node is self:\n                return\n\n    def to_widget(self, x, y, relative=False):\n        '''Convert the given coordinate from window to local widget\n        coordinates. See :mod:`~kivy.uix.relativelayout` for details on the\n        coordinate systems.\n        '''\n        if self.parent:\n            x, y = self.parent.to_widget(x, y)\n        return self.to_local(x, y, relative=relative)\n\n    def to_window(self, x, y, initial=True, relative=False):\n        '''Transform local coordinates to window coordinates. See\n        :mod:`~kivy.uix.relativelayout` for details on the coordinate systems.\n        '''\n        if not initial:\n            x, y = self.to_parent(x, y, relative=relative)\n        if self.parent:\n            return self.parent.to_window(x, y, initial=False,\n                                         relative=relative)\n        return (x, y)\n\n    def to_parent(self, x, y, relative=False):\n        '''Transform local coordinates to parent coordinates. See\n        :mod:`~kivy.uix.relativelayout` for details on the coordinate systems.\n\n        :Parameters:\n            `relative`: bool, defaults to False\n                Change to True if you want to translate relative positions from\n                a widget to its parent coordinates.\n        '''\n        if relative:\n            return (x + self.x, y + self.y)\n        return (x, y)\n\n    def to_local(self, x, y, relative=False):\n        '''Transform parent coordinates to local coordinates. See\n        :mod:`~kivy.uix.relativelayout` for details on the coordinate systems.\n\n        :Parameters:\n            `relative`: bool, defaults to False\n                Change to True if you want to translate coordinates to\n                relative widget coordinates.\n        '''\n        if relative:\n            return (x - self.x, y - self.y)\n        return (x, y)\n\n    def _apply_transform(self, m):\n        return self.parent._apply_transform(m) if self.parent else m\n\n    def get_window_matrix(self, x=0, y=0):\n        '''Calculate the transformation matrix to convert between window and\n        widget coordinates.\n\n        :Parameters:\n            `x`: float, defaults to 0\n                Translates the matrix on the x axis.\n            `y`: float, defaults to 0\n                Translates the matrix on the y axis.\n        '''\n        m = Matrix()\n        m.translate(self.x + x, self.y + y, 0)\n        m = self._apply_transform(m)\n        return m\n\n    x = NumericProperty(0)\n    '''X position of the widget.\n\n    :attr:`x` is a :class:`~kivy.properties.NumericProperty` and defaults to 0.\n    '''\n\n    y = NumericProperty(0)\n    '''Y position of the widget.\n\n    :attr:`y` is a :class:`~kivy.properties.NumericProperty` and defaults to 0.\n    '''\n\n    width = NumericProperty(100)\n    '''Width of the widget.\n\n    :attr:`width` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 100.\n\n    .. warning::\n        Keep in mind that the `width` property is subject to layout logic and\n        that this has not yet happened at the time of the widget's `__init__`\n        method.\n    '''\n\n    height = NumericProperty(100)\n    '''Height of the widget.\n\n    :attr:`height` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 100.\n\n    .. warning::\n        Keep in mind that the `height` property is subject to layout logic and\n        that this has not yet happened at the time of the widget's `__init__`\n        method.\n    '''\n\n    pos = ReferenceListProperty(x, y)\n    '''Position of the widget.\n\n    :attr:`pos` is a :class:`~kivy.properties.ReferenceListProperty` of\n    (:attr:`x`, :attr:`y`) properties.\n    '''\n\n    size = ReferenceListProperty(width, height)\n    '''Size of the widget.\n\n    :attr:`size` is a :class:`~kivy.properties.ReferenceListProperty` of\n    (:attr:`width`, :attr:`height`) properties.\n    '''\n\n    def get_right(self):\n        return self.x + self.width\n\n    def set_right(self, value):\n        self.x = value - self.width\n\n    right = AliasProperty(get_right, set_right, bind=('x', 'width'))\n    '''Right position of the widget.\n\n    :attr:`right` is an :class:`~kivy.properties.AliasProperty` of\n    (:attr:`x` + :attr:`width`).\n    '''\n\n    def get_top(self):\n        return self.y + self.height\n\n    def set_top(self, value):\n        self.y = value - self.height\n\n    top = AliasProperty(get_top, set_top, bind=('y', 'height'))\n    '''Top position of the widget.\n\n    :attr:`top` is an :class:`~kivy.properties.AliasProperty` of\n    (:attr:`y` + :attr:`height`).\n    '''\n\n    def get_center_x(self):\n        return self.x + self.width / 2.\n\n    def set_center_x(self, value):\n        self.x = value - self.width / 2.\n\n    center_x = AliasProperty(get_center_x, set_center_x, bind=('x', 'width'))\n    '''X center position of the widget.\n\n    :attr:`center_x` is an :class:`~kivy.properties.AliasProperty` of\n    (:attr:`x` + :attr:`width` / 2.).\n    '''\n\n    def get_center_y(self):\n        return self.y + self.height / 2.\n\n    def set_center_y(self, value):\n        self.y = value - self.height / 2.\n\n    center_y = AliasProperty(get_center_y, set_center_y, bind=('y', 'height'))\n    '''Y center position of the widget.\n\n    :attr:`center_y` is an :class:`~kivy.properties.AliasProperty` of\n    (:attr:`y` + :attr:`height` / 2.).\n    '''\n\n    center = ReferenceListProperty(center_x, center_y)\n    '''Center position of the widget.\n\n    :attr:`center` is a :class:`~kivy.properties.ReferenceListProperty` of\n    (:attr:`center_x`, :attr:`center_y`) properties.\n    '''\n\n    cls = ListProperty([])\n    '''Class of the widget, used for styling.\n    '''\n\n    id = StringProperty(None, allownone=True)\n    '''Unique identifier of the widget in the tree.\n\n    :attr:`id` is a :class:`~kivy.properties.StringProperty` and defaults to\n    None.\n\n    .. warning::\n\n        If the :attr:`id` is already used in the tree, an exception will\n        be raised.\n    '''\n\n    children = ListProperty([])\n    '''List of children of this widget.\n\n    :attr:`children` is a :class:`~kivy.properties.ListProperty` and\n    defaults to an empty list.\n\n    Use :meth:`add_widget` and :meth:`remove_widget` for manipulating the\n    children list. Don't manipulate the children list directly unless you know\n    what you are doing.\n    '''\n\n    parent = ObjectProperty(None, allownone=True)\n    '''Parent of this widget.\n\n    :attr:`parent` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n\n    The parent of a widget is set when the widget is added to another widget\n    and unset when the widget is removed from its parent.\n    '''\n\n    size_hint_x = NumericProperty(1, allownone=True)\n    '''X size hint. Represents how much space the widget should use in the\n    direction of the X axis relative to its parent's width.\n    Only the :class:`~kivy.uix.layout.Layout` and\n    :class:`~kivy.core.window.Window` classes make use of the hint.\n\n    The size_hint is used by layouts for two purposes:\n\n    - When the layout considers widgets on their own rather than in\n      relation to its other children, the size_hint_x is a direct proportion\n      of the parent width, normally between 0.0 and 1.0. For instance, a\n      widget with ``size_hint_x=0.5`` in\n      a vertical BoxLayout will take up half the BoxLayout's width, or\n      a widget in a FloatLayout with ``size_hint_x=0.2`` will take up 20%\n      of the FloatLayout width. If the size_hint is greater than 1, the\n      widget will be wider than the parent.\n    - When multiple widgets can share a row of a layout, such as in a\n      horizontal BoxLayout, their widths will be their size_hint_x as a\n      fraction of the sum of widget size_hints. For instance, if the\n      size_hint_xs are (0.5, 1.0, 0.5), the first widget will have a\n      width of 25% of the parent width.\n\n    :attr:`size_hint_x` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 1.\n    '''\n\n    size_hint_y = NumericProperty(1, allownone=True)\n    '''Y size hint.\n\n    :attr:`size_hint_y` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 1.\n\n    See :attr:`size_hint_x` for more information, but with widths and heights\n    swapped.\n    '''\n\n    size_hint = ReferenceListProperty(size_hint_x, size_hint_y)\n    '''Size hint.\n\n    :attr:`size_hint` is a :class:`~kivy.properties.ReferenceListProperty` of\n    (:attr:`size_hint_x`, :attr:`size_hint_y`) properties.\n\n    See :attr:`size_hint_x` for more information.\n    '''\n\n    pos_hint = ObjectProperty({})\n    '''Position hint. This property allows you to set the position of\n    the widget inside its parent layout, in percent (similar to\n    size_hint).\n\n    For example, if you want to set the top of the widget to be at 90%\n    height of its parent layout, you can write::\n\n        widget = Widget(pos_hint={'top': 0.9})\n\n    The keys 'x', 'right' and 'center_x' will use the parent width.\n    The keys 'y', 'top' and 'center_y' will use the parent height.\n\n    See :doc:`api-kivy.uix.floatlayout` for further reference.\n\n    .. note::\n        :attr:`pos_hint` is not used by all layouts. Check the documentation\n        of the layout in question to see if it supports pos_hint.\n\n    :attr:`pos_hint` is an :class:`~kivy.properties.ObjectProperty`\n    containing a dict.\n    '''\n\n    ids = DictProperty({})\n    '''This is a dictionary of ids defined in your kv language. This will only\n    be populated if you use ids in your kv language code.\n\n    .. versionadded:: 1.7.0\n\n    :attr:`ids` is a :class:`~kivy.properties.DictProperty` and defaults to an\n    empty dict {}.\n\n    The :attr:`ids` are populated for each root level widget definition. For\n    example::\n\n        # in kv\n        <MyWidget@Widget>:\n            id: my_widget\n            Label:\n                id: label_widget\n                Widget:\n                    id: inner_widget\n                    Label:\n                        id: inner_label\n            TextInput:\n                id: text_input\n            OtherWidget:\n                id: other_widget\n\n\n        <OtherWidget@Widget>\n            id: other_widget\n            Label:\n                id: other_label\n                TextInput:\n                    id: other_textinput\n\n    Then, in python:\n\n    .. code-block:: python\n\n        >>> widget = MyWidget()\n        >>> print(widget.ids)\n        {'other_widget': <weakproxy at 041CFED0 to OtherWidget at 041BEC38>,\n        'inner_widget': <weakproxy at 04137EA0 to Widget at 04138228>,\n        'inner_label': <weakproxy at 04143540 to Label at 04138260>,\n        'label_widget': <weakproxy at 04137B70 to Label at 040F97A0>,\n        'text_input': <weakproxy at 041BB5D0 to TextInput at 041BEC00>}\n        >>> print(widget.ids['other_widget'].ids)\n        {'other_textinput': <weakproxy at 041DBB40 to TextInput at 041BEF48>,\n        'other_label': <weakproxy at 041DB570 to Label at 041BEEA0>}\n        >>> print(widget.ids['label_widget'].ids)\n        {}\n    '''\n\n    opacity = NumericProperty(1.0)\n    '''Opacity of the widget and all its children.\n\n    .. versionadded:: 1.4.1\n\n    The opacity attribute controls the opacity of the widget and its children.\n    Be careful, it's a cumulative attribute: the value is multiplied by the\n    current global opacity and the result is applied to the current context\n    color.\n\n    For example, if the parent has an opacity of 0.5 and a child has an\n    opacity of 0.2, the real opacity of the child will be 0.5 * 0.2 = 0.1.\n\n    Then, the opacity is applied by the shader as:\n\n    .. code-block:: python\n\n        frag_color = color * vec4(1.0, 1.0, 1.0, opacity);\n\n    :attr:`opacity` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 1.0.\n    '''\n\n    def on_opacity(self, instance, value):\n        canvas = self.canvas\n        if canvas is not None:\n            canvas.opacity = value\n\n    canvas = None\n    '''Canvas of the widget.\n\n    The canvas is a graphics object that contains all the drawing instructions\n    for the graphical representation of the widget.\n\n    There are no general properties for the Widget class, such as background\n    color, to keep the design simple and lean. Some derived classes, such as\n    Button, do add such convenience properties but generally the developer is\n    responsible for implementing the graphics representation for a custom\n    widget from the ground up. See the derived widget classes for patterns to\n    follow and extend.\n\n    See :class:`~kivy.graphics.Canvas` for more information about the usage.\n    '''\n\n    disabled = BooleanProperty(False)\n    '''Indicates whether this widget can interact with input or not.\n\n    .. note::\n\n      1. Child Widgets, when added to a disabled widget, will be disabled\n         automatically.\n      2. Disabling/enabling a parent disables/enables all\n         of its children.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`disabled` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n"
  },
  {
    "path": "tickeys/kivy/utils.py",
    "content": "# pylint: disable=W0611\n'''\nUtils\n=====\n\nThe Utils module provides a selection of general utility functions and classes\nthat may be useful for various applications. These include maths, color,\nalgebraic and platform functions.\n\n.. versionchanged:: 1.6.0\n    The OrderedDict class has been removed. Use collections.OrderedDict\n    instead.\n\n'''\n\n__all__ = ('intersection', 'difference', 'strtotuple',\n           'get_color_from_hex', 'get_hex_from_color', 'get_random_color',\n           'is_color_transparent', 'boundary',\n           'deprecated', 'SafeList',\n           'interpolate', 'QueryDict',\n           'platform', 'escape_markup', 'reify')\n\nfrom os import environ\nfrom sys import platform as _sys_platform\nfrom re import match, split\n\n\ndef boundary(value, minvalue, maxvalue):\n    '''Limit a value between a minvalue and maxvalue.'''\n    return min(max(value, minvalue), maxvalue)\n\n\ndef intersection(set1, set2):\n    '''Return the intersection of 2 lists.'''\n    return [s for s in set1 if s in set2]\n\n\ndef difference(set1, set2):\n    '''Return the difference between 2 lists.'''\n    return [s for s in set1 if s not in set2]\n\n\ndef interpolate(value_from, value_to, step=10):\n    '''Interpolate between two values. This can be useful for smoothing some\n    transitions. For example::\n\n        # instead of setting directly\n        self.pos = pos\n\n        # use interpolate, and you'll have a nicer transition\n        self.pos = interpolate(self.pos, new_pos)\n\n    .. warning::\n        These interpolations work only on lists/tuples/doubles with the same\n        dimensions. No test is done to check the dimensions are the same.\n    '''\n    if type(value_from) in (list, tuple):\n        out = []\n        for x, y in zip(value_from, value_to):\n            out.append(interpolate(x, y, step))\n        return out\n    else:\n        return value_from + (value_to - value_from) / float(step)\n\n\ndef strtotuple(s):\n    '''Convert a tuple string into a tuple\n    with some security checks. Designed to be used\n    with the eval() function::\n\n        a = (12, 54, 68)\n        b = str(a)         # return '(12, 54, 68)'\n        c = strtotuple(b)  # return (12, 54, 68)\n\n    '''\n    # security\n    if not match('^[,.0-9 ()\\[\\]]*$', s):\n        raise Exception('Invalid characters in string for tuple conversion')\n    # fast syntax check\n    if s.count('(') != s.count(')'):\n        raise Exception('Invalid count of ( and )')\n    if s.count('[') != s.count(']'):\n        raise Exception('Invalid count of [ and ]')\n    r = eval(s)\n    if type(r) not in (list, tuple):\n        raise Exception('Conversion failed')\n    return r\n\n\ndef get_color_from_hex(s):\n    '''Transform a hex string color to a kivy\n    :class:`~kivy.graphics.Color`.\n    '''\n    if s.startswith('#'):\n        return get_color_from_hex(s[1:])\n\n    value = [int(x, 16) / 255.\n             for x in split('([0-9a-f]{2})', s.lower()) if x != '']\n    if len(value) == 3:\n        value.append(1)\n    return value\n\n\ndef get_hex_from_color(color):\n    '''Transform a kivy :class:`~kivy.graphics.Color` to a hex value::\n\n        >>> get_hex_from_color((0, 1, 0))\n        '#00ff00'\n        >>> get_hex_from_color((.25, .77, .90, .5))\n        '#3fc4e57f'\n\n    .. versionadded:: 1.5.0\n    '''\n    return '#' + ''.join(['{0:02x}'.format(int(x * 255)) for x in color])\n\n\ndef get_random_color(alpha=1.0):\n    '''Returns a random color (4 tuple).\n\n    :Parameters:\n        `alpha` : float, defaults to 1.0\n            If alpha == 'random', a random alpha value is generated.\n    '''\n    from random import random\n    if alpha == 'random':\n        return [random(), random(), random(), random()]\n    else:\n        return [random(), random(), random(), alpha]\n\n\ndef is_color_transparent(c):\n    '''Return True if the alpha channel is 0.'''\n    if len(c) < 4:\n        return False\n    if float(c[3]) == 0.:\n        return True\n    return False\n\n\nDEPRECATED_CALLERS = []\n\n\ndef deprecated(func):\n    '''This is a decorator which can be used to mark functions\n    as deprecated. It will result in a warning being emitted the first time\n    the function is used.'''\n\n    import inspect\n    import functools\n\n    @functools.wraps(func)\n    def new_func(*args, **kwargs):\n        file, line, caller = inspect.stack()[1][1:4]\n        caller_id = \"%s:%s:%s\" % (file, line, caller)\n        # We want to print deprecated warnings only once:\n        if caller_id not in DEPRECATED_CALLERS:\n            DEPRECATED_CALLERS.append(caller_id)\n            warning = (\n                'Call to deprecated function %s in %s line %d.'\n                'Called from %s line %d'\n                ' by %s().' % (\n                    func.__name__,\n                    func.__code__.co_filename,\n                    func.__code__.co_firstlineno + 1,\n                    file, line, caller))\n            from kivy.logger import Logger\n            Logger.warn(warning)\n            if func.__doc__:\n                Logger.warn(func.__doc__)\n        return func(*args, **kwargs)\n    return new_func\n\n\nclass SafeList(list):\n    '''List with a clear() method.\n\n    .. warning::\n        Usage of the iterate() function will decrease your performance.\n    '''\n\n    def clear(self):\n        del self[:]\n\n    @deprecated\n    def iterate(self, reverse=False):\n        if reverse:\n            return iter(reversed(self))\n        return iter(self)\n\n\nclass QueryDict(dict):\n    '''QueryDict is a dict() that can be queried with dot.\n\n    .. versionadded:: 1.0.4\n\n  ::\n\n        d = QueryDict()\n        # create a key named toto, with the value 1\n        d.toto = 1\n        # it's the same as\n        d['toto'] = 1\n    '''\n\n    def __getattr__(self, attr):\n        try:\n            return self.__getitem__(attr)\n        except KeyError:\n            return super(QueryDict, self).__getattr__(attr)\n\n    def __setattr__(self, attr, value):\n        self.__setitem__(attr, value)\n\n\ndef format_bytes_to_human(size, precision=2):\n    '''Format a byte value to a human readable representation (B, KB, MB...).\n\n    .. versionadded:: 1.0.8\n\n    :Parameters:\n        `size`: int\n            Number that represents the bytes value\n        `precision`: int, defaults to 2\n            Precision after the comma\n\n    Examples::\n\n        >>> format_bytes_to_human(6463)\n        '6.31 KB'\n        >>> format_bytes_to_human(646368746541)\n        '601.98 GB'\n\n    '''\n    size = int(size)\n    fmt = '%%1.%df %%s' % precision\n    for unit in ['B', 'KB', 'MB', 'GB', 'TB']:\n        if size < 1024.0:\n            return fmt % (size, unit)\n        size /= 1024.0\n\n\nclass Platform(object):\n    # refactored to class to allow module function to be replaced\n    # with module variable\n\n    def __init__(self):\n        self._platform_ios = None\n        self._platform_android = None\n\n    @deprecated\n    def __call__(self):\n        return self._get_platform()\n\n    def __eq__(self, other):\n        return other == self._get_platform()\n\n    def __ne__(self, other):\n        return other != self._get_platform()\n\n    def __str__(self):\n        return self._get_platform()\n\n    def __repr__(self):\n        return 'platform name: \\'{platform}\\' from: \\n{instance}'.format(\n            platform=self._get_platform(),\n            instance=super(Platform, self).__repr__()\n        )\n\n    def __hash__(self):\n        return self._get_platform().__hash__()\n\n    def _get_platform(self):\n        if self._platform_android is None:\n            # ANDROID_ARGUMENT and ANDROID_PRIVATE are 2 environment variables\n            # from python-for-android project\n            self._platform_android = 'ANDROID_ARGUMENT' in environ\n\n        if self._platform_ios is None:\n            self._platform_ios = (environ.get('KIVY_BUILD', '') == 'ios')\n\n        # On android, _sys_platform return 'linux2', so prefer to check the\n        # import of Android module than trying to rely on _sys_platform.\n        if self._platform_android is True:\n            return 'android'\n        elif self._platform_ios is True:\n            return 'ios'\n        elif _sys_platform in ('win32', 'cygwin'):\n            return 'win'\n        elif _sys_platform == 'darwin':\n            return 'macosx'\n        elif _sys_platform[:5] == 'linux':\n            return 'linux'\n        return 'unknown'\n\n\nplatform = Platform()\n'''\nplatform is a string describing the current Operating System. It is one\nof: *win*, *linux*, *android*, *macosx*, *ios* or *unknown*.\nYou can use it as follows::\n\n    from kivy import platform\n    if platform == 'linux':\n        do_linux_things()\n    if platform() == 'linux': # triggers deprecation warning\n        do_more_linux_things()\n\n.. versionadded:: 1.3.0\n\n.. versionchanged:: 1.8.0\n\n    platform is now a variable instead of a  function.\n\n'''\n\n\ndef escape_markup(text):\n    '''\n    Escape markup characters found in the text. Intended to be used when markup\n    text is activated on the Label::\n\n        untrusted_text = escape_markup('Look at the example [1]')\n        text = '[color=ff0000]' + untrusted_text + '[/color]'\n        w = Label(text=text, markup=True)\n\n    .. versionadded:: 1.3.0\n    '''\n    return text.replace('&', '&amp;').replace('[', '&bl;').replace(']', '&br;')\n\n\nclass reify(object):\n    '''\n    Put the result of a method which uses this (non-data) descriptor decorator\n    in the instance dict after the first call, effectively replacing the\n    decorator with an instance variable.\n\n    It acts like @property, except that the function is only ever called once;\n    after that, the value is cached as a regular attribute. This gives you lazy\n    attribute creation on objects that are meant to be immutable.\n\n    Taken from the `Pyramid project <https://pypi.python.org/pypi/pyramid/>`_.\n\n    To use this as a decorator::\n\n         @reify\n         def lazy(self):\n              ...\n              return hard_to_compute_int\n         first_time = self.lazy   # lazy is reify obj, reify.__get__() runs\n         second_time = self.lazy  # lazy is hard_to_compute_int\n    '''\n\n    def __init__(self, func):\n        self.func = func\n        self.__doc__ = func.__doc__\n\n    def __get__(self, inst, cls):\n        if inst is None:\n            return self\n        retval = self.func(inst)\n        setattr(inst, self.func.__name__, retval)\n        return retval\n"
  },
  {
    "path": "tickeys/kivy/vector.py",
    "content": "'''Vector\n======\n\nThe :class:`Vector` represents a 2D vector (x, y).\nOur implementation is built on top of a Python list.\n\n An example of constructing a Vector::\n\n    >>> # Construct a point at 82,34\n    >>> v = Vector(82, 34)\n    >>> v[0]\n    82\n    >>> v.x\n    82\n    >>> v[1]\n    34\n    >>> v.y\n    34\n\n    >>> # Construct by giving a list of 2 values\n    >>> pos = (93, 45)\n    >>> v = Vector(pos)\n    >>> v[0]\n    93\n    >>> v.x\n    93\n    >>> v[1]\n    45\n    >>> v.y\n    45\n\n\nOptimized usage\n---------------\n\nMost of the time, you can use a list for arguments instead of using a\nVector. For example, if you want to calculate the distance between 2\npoints::\n\n    a = (10, 10)\n    b = (87, 34)\n\n    # optimized method\n    print('distance between a and b:', Vector(a).distance(b))\n\n    # non-optimized method\n    va = Vector(a)\n    vb = Vector(b)\n    print('distance between a and b:', va.distance(vb))\n\n\nVector operators\n----------------\n\nThe :class:`Vector` supports some numeric operators such as +, -, /::\n\n    >>> Vector(1, 1) + Vector(9, 5)\n    [10, 6]\n\n    >>> Vector(9, 5) - Vector(5, 5)\n    [4, 0]\n\n    >>> Vector(10, 10) / Vector(2., 4.)\n    [5.0, 2.5]\n\n    >>> Vector(10, 10) / 5.\n    [2.0, 2.0]\n\n\nYou can also use in-place operators::\n\n    >>> v = Vector(1, 1)\n    >>> v += 2\n    >>> v\n    [3, 3]\n    >>> v *= 5\n    [15, 15]\n    >>> v /= 2.\n    [7.5, 7.5]\n\n'''\n\n__all__ = ('Vector', )\n\nimport math\n\n\nclass Vector(list):\n    '''Vector class. See module documentation for more information.\n    '''\n\n    def __init__(self, *largs):\n        if len(largs) == 1:\n            super(Vector, self).__init__(largs[0])\n        elif len(largs) == 2:\n            super(Vector, self).__init__(largs)\n        else:\n            raise Exception('Invalid vector')\n\n    def _get_x(self):\n        return self[0]\n\n    def _set_x(self, x):\n        self[0] = x\n\n    x = property(_get_x, _set_x)\n    ''':attr:`x` represents the first element in the list.\n\n    >>> v = Vector(12, 23)\n    >>> v[0]\n    12\n    >>> v.x\n    12\n    '''\n\n    def _get_y(self):\n        return self[1]\n\n    def _set_y(self, y):\n        self[1] = y\n\n    y = property(_get_y, _set_y)\n    ''':attr:`y` represents the second element in the list.\n\n    >>> v = Vector(12, 23)\n    >>> v[1]\n    23\n    >>> v.y\n    23\n\n    '''\n\n    def __getslice__(self, i, j):\n        try:\n            # use the list __getslice__ method and convert\n            # result to vector\n            return Vector(super(Vector, self).__getslice__(i, j))\n        except Exception:\n            raise TypeError('vector::FAILURE in __getslice__')\n\n    def __add__(self, val):\n        return Vector(list(map(lambda x, y: x + y, self, val)))\n\n    def __iadd__(self, val):\n        if type(val) in (int, float):\n            self.x += val\n            self.y += val\n        else:\n            self.x += val.x\n            self.y += val.y\n        return self\n\n    def __neg__(self):\n        return Vector([-x for x in self])\n\n    def __sub__(self, val):\n        return Vector(list(map(lambda x, y: x - y, self, val)))\n\n    def __isub__(self, val):\n        if type(val) in (int, float):\n            self.x -= val\n            self.y -= val\n        else:\n            self.x -= val.x\n            self.y -= val.y\n        return self\n\n    def __mul__(self, val):\n        try:\n            return Vector(list(map(lambda x, y: x * y, self, val)))\n        except Exception:\n            return Vector([x * val for x in self])\n\n    def __imul__(self, val):\n        if type(val) in (int, float):\n            self.x *= val\n            self.y *= val\n        else:\n            self.x *= val.x\n            self.y *= val.y\n        return self\n\n    def __rmul__(self, val):\n        return (self * val)\n\n    def __truediv__(self, val):\n        try:\n            return Vector(list(map(lambda x, y: x / y, self, val)))\n        except Exception:\n            return Vector([x / val for x in self])\n\n    def __div__(self, val):\n        try:\n            return Vector(list(map(lambda x, y: x / y, self, val)))\n        except Exception:\n            return Vector([x / val for x in self])\n\n    def __rtruediv__(self, val):\n        try:\n            return Vector(*val) / self\n        except Exception:\n            return Vector(val, val) / self\n\n    def __rdiv__(self, val):\n        try:\n            return Vector(*val) / self\n        except Exception:\n            return Vector(val, val) / self\n\n    def __idiv__(self, val):\n        if type(val) in (int, float):\n            self.x /= val\n            self.y /= val\n        else:\n            self.x /= val.x\n            self.y /= val.y\n        return self\n\n    def length(self):\n        '''Returns the length of a vector.\n\n        >>> Vector(10, 10).length()\n        14.142135623730951\n        >>> pos = (10, 10)\n        >>> Vector(pos).length()\n        14.142135623730951\n\n        '''\n        return math.sqrt(self[0] ** 2 + self[1] ** 2)\n\n    def length2(self):\n        '''Returns the length of a vector squared.\n\n        >>> Vector(10, 10).length2()\n        200\n        >>> pos = (10, 10)\n        >>> Vector(pos).length2()\n        200\n\n        '''\n        return self[0] ** 2 + self[1] ** 2\n\n    def distance(self, to):\n        '''Returns the distance between two points.\n\n        >>> Vector(10, 10).distance((5, 10))\n        5.\n        >>> a = (90, 33)\n        >>> b = (76, 34)\n        >>> Vector(a).distance(b)\n        14.035668847618199\n\n        '''\n        return math.sqrt((self[0] - to[0]) ** 2 + (self[1] - to[1]) ** 2)\n\n    def distance2(self, to):\n        '''Returns the distance between two points squared.\n\n        >>> Vector(10, 10).distance2((5, 10))\n        25\n\n        '''\n        return (self[0] - to[0]) ** 2 + (self[1] - to[1]) ** 2\n\n    def normalize(self):\n        '''Returns a new vector that has the same direction as vec,\n        but has a length of one.\n\n        >>> v = Vector(88, 33).normalize()\n        >>> v\n        [0.93632917756904444, 0.3511234415883917]\n        >>> v.length()\n        1.0\n\n        '''\n        if self[0] == 0. and self[1] == 0.:\n            return Vector(0., 0.)\n        return self / self.length()\n\n    def dot(self, a):\n        '''Computes the dot product of a and b.\n\n        >>> Vector(2, 4).dot((2, 2))\n        12\n\n        '''\n        return self[0] * a[0] + self[1] * a[1]\n\n    def angle(self, a):\n        '''Computes the angle between a and b, and returns the angle in\n        degrees.\n\n        >>> Vector(100, 0).angle((0, 100))\n        -90.0\n        >>> Vector(87, 23).angle((-77, 10))\n        -157.7920283010705\n\n        '''\n        angle = -(180 / math.pi) * math.atan2(\n            self[0] * a[1] - self[1] * a[0],\n            self[0] * a[0] + self[1] * a[1])\n        return angle\n\n    def rotate(self, angle):\n        '''Rotate the vector with an angle in degrees.\n\n        >>> v = Vector(100, 0)\n        >>> v.rotate(45)\n        >>> v\n        [70.710678118654755, 70.710678118654741]\n\n        '''\n        angle = math.radians(angle)\n        return Vector(\n            (self[0] * math.cos(angle)) - (self[1] * math.sin(angle)),\n            (self[1] * math.cos(angle)) + (self[0] * math.sin(angle)))\n\n    @staticmethod\n    def line_intersection(v1, v2, v3, v4):\n        '''\n        Finds the intersection point between the lines (1)v1->v2 and (2)v3->v4\n        and returns it as a vector object.\n\n        >>> a = (98, 28)\n        >>> b = (72, 33)\n        >>> c = (10, -5)\n        >>> d = (20, 88)\n        >>> Vector.line_intersection(a, b, c, d)\n        [15.25931928687196, 43.911669367909241]\n\n        .. warning::\n\n            This is a line intersection method, not a segment intersection.\n\n        For math see: http://en.wikipedia.org/wiki/Line-line_intersection\n        '''\n        #linear algebar sucks...seriously!!\n        x1, x2, x3, x4 = float(v1[0]), float(v2[0]), float(v3[0]), float(v4[0])\n        y1, y2, y3, y4 = float(v1[1]), float(v2[1]), float(v3[1]), float(v4[1])\n\n        u = (x1 * y2 - y1 * x2)\n        v = (x3 * y4 - y3 * x4)\n        denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)\n        if denom == 0:\n            return None\n\n        px = (u * (x3 - x4) - (x1 - x2) * v) / denom\n        py = (u * (y3 - y4) - (y1 - y2) * v) / denom\n\n        return Vector(px, py)\n\n    @staticmethod\n    def segment_intersection(v1, v2, v3, v4):\n        '''\n        Finds the intersection point between segments (1)v1->v2 and (2)v3->v4\n        and returns it as a vector object.\n\n        >>> a = (98, 28)\n        >>> b = (72, 33)\n        >>> c = (10, -5)\n        >>> d = (20, 88)\n        >>> Vector.segment_intersection(a, b, c, d)\n        None\n\n        >>> a = (0, 0)\n        >>> b = (10, 10)\n        >>> c = (0, 10)\n        >>> d = (10, 0)\n        >>> Vector.segment_intersection(a, b, c, d)\n        [5, 5]\n        '''\n        #Yaaay! I love linear algebra applied within the realms of geometry.\n        x1, x2, x3, x4 = float(v1[0]), float(v2[0]), float(v3[0]), float(v4[0])\n        y1, y2, y3, y4 = float(v1[1]), float(v2[1]), float(v3[1]), float(v4[1])\n        #This is mostly the same as the line_intersection\n        u = (x1 * y2 - y1 * x2)\n        v = (x3 * y4 - y3 * x4)\n        denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)\n        if denom == 0:\n            return None\n\n        px = (u * (x3 - x4) - (x1 - x2) * v) / denom\n        py = (u * (y3 - y4) - (y1 - y2) * v) / denom\n        #Here are the new bits\n        c1 = (x1 <= px <= x2) or (x2 <= px <= x1)\n        c2 = (y1 <= py <= y2) or (y2 <= py <= y1)\n        c3 = (x3 <= px <= x4) or (x4 <= px <= x3)\n        c4 = (y3 <= py <= y4) or (y4 <= py <= y3)\n\n        if (c1 and c2) and (c3 and c4):\n            return Vector(px, py)\n        else:\n            return None\n\n    @staticmethod\n    def in_bbox(point, a, b):\n        '''Return True if `point` is in the bounding box defined by `a`\n        and `b`.\n\n        >>> bmin = (0, 0)\n        >>> bmax = (100, 100)\n        >>> Vector.in_bbox((50, 50), bmin, bmax)\n        True\n        >>> Vector.in_bbox((647, -10), bmin, bmax)\n        False\n\n        '''\n        return ((point[0] <= a[0] and point[0] >= b[0] or\n                 point[0] <= b[0] and point[0] >= a[0]) and\n                (point[1] <= a[1] and point[1] >= b[1] or\n                 point[1] <= b[1] and point[1] >= a[1]))\n"
  },
  {
    "path": "tickeys/kivy/weakmethod.py",
    "content": "'''\nWeak Method\n===========\n\nThe :class:`WeakMethod` is used by the :class:`~kivy.clock.Clock` class to\nallow references to a bound method that permits the associated object to\nbe garbage collected. Please refer to\n`examples/core/clock_method.py` for more information.\n\nThis WeakMethod class is taken from the recipe\nhttp://code.activestate.com/recipes/81253/, based on the nicodemus version.\nMany thanks nicodemus!\n'''\n\nimport weakref\nimport sys\n\nif sys.version > '3':\n\n    class WeakMethod:\n        '''Implementation of a\n        `weakref <http://en.wikipedia.org/wiki/Weak_reference>`_\n        for functions and bound methods.\n        '''\n        def __init__(self, method):\n            self.method = None\n            self.method_name = None\n            try:\n                if method.__self__ is not None:\n                    self.method_name = method.__func__.__name__\n                    self.proxy = weakref.proxy(method.__self__)\n                else:\n                    self.method = method\n                    self.proxy = None\n            except AttributeError:\n                self.method = method\n                self.proxy = None\n\n        def __call__(self):\n            '''Return a new bound-method like the original, or the\n            original function if it was just a function or unbound\n            method.\n            Returns None if the original object doesn't exist.\n            '''\n            try:\n                if self.proxy:\n                    return getattr(self.proxy, self.method_name)\n            except ReferenceError:\n                pass\n            return self.method\n\n        def is_dead(self):\n            '''Returns True if the referenced callable was a bound method and\n            the instance no longer exists. Otherwise, return False.\n            '''\n            return self.proxy is not None and not bool(dir(self.proxy))\n\n        def __repr__(self):\n            return '<WeakMethod proxy={} method={} method_name={}>'.format(\n                   self.proxy, self.method, self.method_name)\n\nelse:\n\n    import new\n\n    class WeakMethod(object):\n        '''Implementation of a\n        `weakref <http://en.wikipedia.org/wiki/Weak_reference>`_\n        for functions and bound methods.\n        '''\n\n        def __init__(self, method):\n            try:\n                if method.__self__ is not None:\n                    # bound method\n                    self._obj = weakref.ref(method.im_self)\n                else:\n                    # unbound method\n                    self._obj = None\n                self._func = method.im_func\n                self._class = method.im_class\n            except AttributeError:\n                # not a method\n                self._obj = None\n                self._func = method\n                self._class = None\n\n        def __call__(self):\n            '''Return a new bound-method like the original, or the\n            original function if it was just a function or unbound\n            method.\n            Returns None if the original object doesn't exist.\n            '''\n            if self.is_dead():\n                return None\n            if self._obj is not None:\n                return new.instancemethod(self._func, self._obj(), self._class)\n            else:\n                # we don't have an instance: return just the function\n                return self._func\n\n        def is_dead(self):\n            '''Returns True if the referenced callable was a bound method and\n            the instance no longer exists. Otherwise, return False.\n            '''\n            return self._obj is not None and self._obj() is None\n\n        def __eq__(self, other):\n            try:\n                return type(self) is type(other) and self() == other()\n            except:\n                return False\n\n        def __ne__(self, other):\n            return not self == other\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/__init__.py",
    "content": "'''\nKivy framework\n==============\n\nKivy is an open source library for developing multi-touch applications. It is\ncompletely cross-platform (Linux/OSX/Win) and released under the terms of the\nMIT License.\n\nIt comes with native support for many multi-touch input devices, a growing\nlibrary of multi-touch aware widgets and hardware accelerated OpenGL drawing.\nKivy is designed to let you focus on building custom and highly interactive\napplications as quickly and easily as possible.\n\nWith Kivy, you can take full advantage of the dynamic nature of Python. There\nare thousands of high-quality, free libraries that can be integrated in your\napplication. At the same time, performance-critical parts are implemented\nin the C language.\n\nSee http://kivy.org for more information.\n'''\n\n__all__ = (\n    'require',\n    'kivy_configure', 'kivy_register_post_configuration',\n    'kivy_options', 'kivy_base_dir',\n    'kivy_modules_dir', 'kivy_data_dir', 'kivy_shader_dir',\n    'kivy_icons_dir', 'kivy_home_dir', 'kivy_userexts_dir',\n    'kivy_config_fn', 'kivy_usermodules_dir',\n)\n\n__version__ = '1.9.0'\n\nimport sys\nimport shutil\nfrom getopt import getopt, GetoptError\nfrom os import environ, mkdir\nfrom os.path import dirname, join, basename, exists, expanduser\nfrom kivy.logger import Logger, LOG_LEVELS\nfrom kivy.utils import platform\n\n# internals for post-configuration\n__kivy_post_configuration = []\n\n\nif platform == 'macosx' and sys.maxsize < 9223372036854775807:\n    r = '''Unsupported Python version detected!:\n    Kivy requires a 64 bit version of Python to run on OS X. We strongly\n    advise you to use the version of Python that is provided by Apple\n    (don't use ports, fink or homebrew unless you know what you're\n    doing).\n    See http://kivy.org/docs/installation/installation-macosx.html for\n    details.\n    '''\n    Logger.critical(r)\n\n\ndef require(version):\n    '''Require can be used to check the minimum version required to run a Kivy\n    application. For example, you can start your application code like this::\n\n        import kivy\n        kivy.require('1.0.1')\n\n    If a user attempts to run your application with a version of Kivy that is\n    older than the specified version, an Exception is raised.\n\n    The Kivy version string is built like this::\n\n        X.Y.Z[-tag[-tagrevision]]\n\n        X is the major version\n        Y is the minor version\n        Z is the bugfixes revision\n\n    The tag is optional, but may be one of 'dev', 'alpha', or 'beta'.\n    The tagrevision is the revision of the tag.\n\n    .. warning::\n\n        You must not ask for a version with a tag, except -dev. Asking for a\n        'dev' version will just warn the user if the current Kivy\n        version is not a -dev, but it will never raise an exception.\n        You must not ask for a version with a tagrevision.\n\n    '''\n\n    def parse_version(version):\n        # check for tag\n        tag = None\n        tagrev = None\n        if '-' in version:\n            l = version.split('-')\n            if len(l) == 2:\n                version, tag = l\n            elif len(l) == 3:\n                version, tag, tagrev = l\n            else:\n                raise Exception('Revision format must be X.Y.Z[-tag]')\n\n        # check x y z\n        l = version.split('.')\n        if len(l) != 3:\n            raise Exception('Revision format must be X.Y.Z[-tag]')\n        return [int(x) for x in l], tag, tagrev\n\n    # user version\n    revision, tag, tagrev = parse_version(version)\n    # current version\n    sysrevision, systag, systagrev = parse_version(__version__)\n\n    # ensure that the required version don't contain tag, except dev\n    if tag not in (None, 'dev'):\n        raise Exception('Revision format must not have any tag except \"dev\"')\n    if tag == 'dev' and systag != 'dev':\n        Logger.warning('Application requested a -dev version of Kivy. '\n                       '(You have %s, but the application requires %s)' % (\n                           __version__, version))\n    # not tag rev (-alpha-1, -beta-x) allowed.\n    if tagrev is not None:\n        raise Exception('Revision format must not contain any tagrevision')\n\n    # finally, checking revision\n    if sysrevision < revision:\n        raise Exception('The version of Kivy installed on this system '\n                        'is too old. '\n                        '(You have %s, but the application requires %s)' % (\n                            __version__, version))\n\n\ndef kivy_configure():\n    '''Call post-configuration of Kivy.\n    This function must be called if you create the window yourself.\n    '''\n    for callback in __kivy_post_configuration:\n        callback()\n\n\ndef kivy_register_post_configuration(callback):\n    '''Register a function to be called when kivy_configure() is called.\n\n    .. warning::\n        Internal use only.\n    '''\n    __kivy_post_configuration.append(callback)\n\n\ndef kivy_usage():\n    '''Kivy Usage: %s [OPTION...]::\n\n        -h, --help\n            Prints this help message.\n        -d, --debug\n            Shows debug log.\n        -a, --auto-fullscreen\n            Force 'auto' fullscreen mode (no resolution change).\n            Uses your display's resolution. This is most likely what you want.\n        -c, --config section:key[:value]\n            Set a custom [section] key=value in the configuration object.\n        -f, --fullscreen\n            Force running in fullscreen mode.\n        -k, --fake-fullscreen\n            Force 'fake' fullscreen mode (no window border/decoration).\n            Uses the resolution specified by width and height in your config.\n        -w, --windowed\n            Force running in a window.\n        -p, --provider id:provider[,options]\n            Add an input provider (eg: ccvtable1:tuio,192.168.0.1:3333).\n        -m mod, --module=mod\n            Activate a module (use \"list\" to get a list of available modules).\n        -r, --rotation\n            Rotate the window's contents (0, 90, 180, 270).\n        -s, --save\n            Save current Kivy configuration.\n        --size=640x480\n            Size of window geometry.\n        --dpi=96\n            Manually overload the Window DPI (for testing only.)\n    '''\n    print(kivy_usage.__doc__ % (basename(sys.argv[0])))\n\n\n#: Global settings options for kivy\nkivy_options = {\n    'window': ('egl_rpi', 'sdl2', 'pygame', 'sdl', 'x11'),\n    'text': ('pil', 'sdl2', 'pygame', 'sdlttf'),\n    'video': (\n        'gstplayer', 'ffmpeg', 'ffpyplayer', 'gi', 'pygst', 'pyglet',\n        'null'),\n    'audio': ('gstplayer', 'pygame', 'gi', 'pygst', 'ffpyplayer', 'sdl2'),\n    'image': ('tex', 'imageio', 'dds', 'gif', 'sdl2', 'pygame', 'pil', 'ffpy'),\n    'camera': ('opencv', 'gi', 'pygst', 'videocapture', 'avfoundation'),\n    'spelling': ('enchant', 'osxappkit', ),\n    'clipboard': (\n        'android', 'winctypes', 'xsel', 'dbusklipper', 'nspaste', 'sdl2',\n        'pygame', 'dummy', 'gtk3', )}\n\n# Read environment\nfor option in kivy_options:\n    key = 'KIVY_%s' % option.upper()\n    if key in environ:\n        try:\n            if type(kivy_options[option]) in (list, tuple):\n                kivy_options[option] = environ[key].split(',')\n            else:\n                kivy_options[option] = environ[key].lower() in \\\n                    ('true', '1', 'yes', 'yup')\n        except Exception:\n            Logger.warning('Core: Wrong value for %s environment key' % key)\n            Logger.exception('')\n\n# Extract all needed path in kivy\n#: Kivy directory\nkivy_base_dir = dirname(sys.modules[__name__].__file__)\n#: Kivy modules directory\n\nkivy_modules_dir = environ.get('KIVY_MODULES_DIR',\n                               join(kivy_base_dir, 'modules'))\n#: Kivy extension directory\nkivy_exts_dir = environ.get('KIVY_EXTS_DIR',\n                            join(kivy_base_dir, 'extensions'))\n#: Kivy data directory\nkivy_data_dir = environ.get('KIVY_DATA_DIR',\n                            join(kivy_base_dir, 'data'))\n#: Kivy glsl shader directory\nkivy_shader_dir = join(kivy_data_dir, 'glsl')\n#: Kivy icons config path (don't remove the last '')\nkivy_icons_dir = join(kivy_data_dir, 'icons', '')\n#: Kivy user-home storage directory\nkivy_home_dir = ''\n#: Kivy configuration filename\nkivy_config_fn = ''\n#: Kivy user modules directory\nkivy_usermodules_dir = ''\n#: Kivy user extensions directory\nkivy_userexts_dir = ''\n\n\n# Don't go further if we generate documentation\nif any(name in sys.argv[0] for name in ('sphinx-build', 'autobuild.py')):\n    environ['KIVY_DOC'] = '1'\nif 'sphinx-build' in sys.argv[0]:\n    environ['KIVY_DOC_INCLUDE'] = '1'\nif any('nosetests' in arg for arg in sys.argv):\n    environ['KIVY_UNITTEST'] = '1'\nif any('pyinstaller' in arg for arg in sys.argv):\n    environ['KIVY_PACKAGING'] = '1'\n\nif not environ.get('KIVY_DOC_INCLUDE'):\n    # Configuration management\n    if 'KIVY_HOME' in environ:\n        kivy_home_dir = expanduser(environ['KIVY_HOME'])\n    else:\n        user_home_dir = expanduser('~')\n        if platform == 'android':\n            user_home_dir = environ['ANDROID_APP_PATH']\n        elif platform == 'ios':\n            user_home_dir = join(expanduser('~'), 'Documents')\n        kivy_home_dir = join(user_home_dir, '.kivy')\n    kivy_config_fn = join(kivy_home_dir, 'config.ini')\n    kivy_usermodules_dir = join(kivy_home_dir, 'mods')\n    kivy_userexts_dir = join(kivy_home_dir, 'extensions')\n    icon_dir = join(kivy_home_dir, 'icon')\n\n    if 'KIVY_NO_CONFIG' not in environ:\n        if not exists(kivy_home_dir):\n            mkdir(kivy_home_dir)\n        if not exists(kivy_usermodules_dir):\n            mkdir(kivy_usermodules_dir)\n        if not exists(kivy_userexts_dir):\n            mkdir(kivy_userexts_dir)\n        if not exists(icon_dir):\n            try:\n                shutil.copytree(join(kivy_data_dir, 'logo'), icon_dir)\n            except:\n                Logger.exception('Error when copying logo directory')\n\n    # configuration\n    from kivy.config import Config\n\n    # Set level of logger\n    level = LOG_LEVELS.get(Config.get('kivy', 'log_level'))\n    Logger.setLevel(level=level)\n\n    # Can be overrided in command line\n    if ('KIVY_UNITTEST' not in environ and\n        'KIVY_PACKAGING' not in environ and\n        'KIVY_NO_ARGS' not in environ):\n        # save sys argv, otherwize, gstreamer use it and display help..\n        sys_argv = sys.argv\n        sys.argv = sys.argv[:1]\n\n        try:\n            opts, args = getopt(sys_argv[1:], 'hp:fkawFem:sr:dc:', [\n                'help', 'fullscreen', 'windowed', 'fps', 'event',\n                'module=', 'save', 'fake-fullscreen', 'auto-fullscreen',\n                'display=', 'size=', 'rotate=', 'config=', 'debug',\n                'dpi='])\n\n        except GetoptError as err:\n            Logger.error('Core: %s' % str(err))\n            kivy_usage()\n            sys.exit(2)\n\n        # set argv to the non-read args\n        sys.argv = sys_argv[0:1] + args\n    else:\n        opts = []\n        args = []\n\n    need_save = False\n    for opt, arg in opts:\n        if opt in ('-h', '--help'):\n            kivy_usage()\n            sys.exit(0)\n        elif opt in ('-p', '--provider'):\n            try:\n                pid, args = arg.split(':', 1)\n                Config.set('input', pid, args)\n            except ValueError:\n                # when we are doing an executable on macosx with\n                # pyinstaller, they are passing information with -p. so\n                # it will conflict with our current -p option. since the\n                # format is not the same, just avoid it.\n                pass\n        elif opt in ('-a', '--auto-fullscreen'):\n            Config.set('graphics', 'fullscreen', 'auto')\n        elif opt in ('-c', '--config'):\n            l = arg.split(':', 2)\n            if len(l) == 2:\n                Config.set(l[0], l[1], '')\n            elif len(l) == 3:\n                Config.set(l[0], l[1], l[2])\n            else:\n                raise Exception('Invalid --config value')\n            if l[0] == 'kivy' and l[1] == 'log_level':\n                level = LOG_LEVELS.get(Config.get('kivy', 'log_level'))\n                Logger.setLevel(level=level)\n        elif opt in ('-k', '--fake-fullscreen'):\n            Config.set('graphics', 'fullscreen', 'fake')\n        elif opt in ('-f', '--fullscreen'):\n            Config.set('graphics', 'fullscreen', '1')\n        elif opt in ('-w', '--windowed'):\n            Config.set('graphics', 'fullscreen', '0')\n        elif opt in ('--size', ):\n            w, h = str(arg).split('x')\n            Config.set('graphics', 'width', w)\n            Config.set('graphics', 'height', h)\n        elif opt in ('--display', ):\n            Config.set('graphics', 'display', str(arg))\n        elif opt in ('-m', '--module'):\n            if str(arg) == 'list':\n                from kivy.modules import Modules\n                Modules.usage_list()\n                sys.exit(0)\n            args = arg.split(':', 1)\n            if len(args) == 1:\n                args += ['']\n            Config.set('modules', args[0], args[1])\n        elif opt in ('-s', '--save'):\n            need_save = True\n        elif opt in ('-r', '--rotation'):\n            Config.set('graphics', 'rotation', arg)\n        elif opt in ('-d', '--debug'):\n            level = LOG_LEVELS.get('debug')\n            Logger.setLevel(level=level)\n        elif opt == '--dpi':\n            environ['KIVY_DPI'] = arg\n\n    if need_save and 'KIVY_NO_CONFIG' not in environ:\n        try:\n            with open(kivy_config_fn, 'w') as fd:\n                Config.write(fd)\n        except Exception as e:\n            Logger.exception('Core: error while saving default'\n                             'configuration file:', str(e))\n        Logger.info('Core: Kivy configuration saved.')\n        sys.exit(0)\n\n    # configure all activated modules\n    from kivy.modules import Modules\n    Modules.configure()\n\n    # android hooks: force fullscreen and add android touch input provider\n    if platform in ('android', 'ios'):\n        from kivy.config import Config\n        Config.set('graphics', 'fullscreen', 'auto')\n        Config.remove_section('input')\n        Config.add_section('input')\n\n    if platform == 'android':\n        Config.set('input', 'androidtouch', 'android')\n\nLogger.info('Kivy: v%s' % (__version__))\nLogger.info('Python: v{}'.format(sys.version))\n\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/_event.pxd",
    "content": "from cpython.ref cimport PyObject\n\ncdef class ObjectWithUid(object):\n    cdef readonly int uid\n\n\ncdef class Observable(ObjectWithUid):\n    cdef object __fast_bind_mapping\n    cdef object bound_uid\n\n\ncdef class EventDispatcher(ObjectWithUid):\n    cdef dict __event_stack\n    cdef dict __properties\n    cdef dict __storage\n    cdef object __weakref__\n    cpdef dict properties(self)\n\n\ncdef enum BoundLock:\n    # the state of the BoundCallback, i.e. whether it can be deleted\n    unlocked  # whether the BoundCallback is unlocked and can be deleted\n    locked  # whether the BoundCallback is locked and cannot be deleted\n    deleted  # whether the locked BoundCallback was marked for deletion\n\ncdef class BoundCallback:\n    cdef object func\n    cdef tuple largs\n    cdef dict kwargs\n    cdef int is_ref  # if func is a ref to the function\n    cdef BoundLock lock  # see BoundLock\n    cdef BoundCallback next  # next callback in chain\n    cdef BoundCallback prev  # previous callback in chain\n    cdef object uid  # the uid given for this callback, None if not given\n\n\ncdef class EventObservers:\n    # If dispatching should occur in normal or reverse order of binding.\n    cdef int dispatch_reverse\n    # If in dispatch, the value parameter is dispatched or ignored.\n    cdef int dispatch_value\n    # The first callback bound\n    cdef BoundCallback first_callback\n    # The last callback bound\n    cdef BoundCallback last_callback\n    # The uid to assign to the next bound callback.\n    cdef object uid\n\n    cdef inline void bind(self, object observer, int is_ref=*) except *\n    cdef inline object fast_bind(self, object observer, tuple largs, dict kwargs, int is_ref)\n    cdef inline void unbind(self, object observer, int is_ref, int stop_on_first) except *\n    cdef inline void fast_unbind(self, object observer, tuple largs, dict kwargs) except *\n    cdef inline object unbind_uid(self, object uid)\n    cdef inline void remove_callback(self, BoundCallback callback, int force=*) except *\n    cdef inline object _dispatch(\n        self, object f, tuple slargs, dict skwargs, object obj, object value, tuple largs, dict kwargs)\n    cdef inline int dispatch(self, object obj, object value, tuple largs, dict kwargs, int stop_on_true) except 2\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/adapters/__init__.py",
    "content": "'''\nAdapters\n========\n\n.. versionadded:: 1.5.0\n\nAn adapter is a mediating controller-type class that processes and presents\ndata for use in views. It does this by generating models, generally lists of\n:class:`~kivy.uix.listview.SelectableView` items, that are consumed and\npresented by views. Views are top-level widgets, such as a\n:class:`~kivy.uix.listview.ListView`, that allow users to scroll through\nand (optionally) interact with your data.\n\nThe Concept\n-----------\n\nKivy adapters are modelled on the\n`Adapter design pattern <http://en.wikipedia.org/wiki/Adapter_pattern>`_.\nConceptually, they play the role of a 'controller' between you data and views\nin a `Model-View-Controller\n<https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller>`_\ntype architecture.\n\nThe role of an adapter can be depicted as follows:\n\n.. image:: images/adapters.png\n\n\nThe Components\n--------------\n\nThe components involved in this process are:\n\n- **Adapters**: The adapter plays a mediating role between the user interface\n  and your data. It manages the creation of the view elements for the model\n  using the args_converter to prepare the contructor arguments for your\n  cls/template view items.\n\n  The base :class:`Adapter` is subclassed by the\n  :class:`SimpleListAdapter` and :class:`ListAdapter`. The :class:`DictAdapter`\n  is a more advanced and flexible subclass of :class:`ListAdapter`.\n\n    :doc:`api-kivy.adapters.adapter`,\n    :doc:`api-kivy.adapters.simplelistadapter`,\n    :doc:`api-kivy.adapters.listadapter`,\n    :doc:`api-kivy.adapters.dictadapter`.\n\n- **Models**: The data for which an adapter serves as a bridge to views can be\n  any sort of data. However, for convenience, model mixin classes can ease the\n  preparation or shaping of data for use in the system. For selection\n  operations, the :class:`SelectableDataItem` can optionally prepare data items\n  to provide and receive selection information (data items are not required to\n  be \"selection-aware\", but in some cases it may be desired).\n\n    :doc:`api-kivy.adapters.models`.\n\n- **Args Converters**: Argument converters are made by the application\n  programmer to do the work of converting data items to argument dictionaries\n  suitable for instantiating views. In effect, they take each row of your data\n  and create dictionaries that are passed into the constructors of your\n  cls/template which are then used populate your View.\n\n    :doc:`api-kivy.adapters.args_converters`.\n\n- **Views**: Models of your data are presented to the user via views. Each of\n  your data items create a corresponding view subitem (the cls or template)\n  presented in a list by the View. The base :class:`AbstractView` currently has\n  one concrete implementation: the :class:`ListView`.\n\n    :doc:`api-kivy.uix.abstractview`,\n    :doc:`api-kivy.uix.listview`.\n\n----\n'''\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/adapters/adapter.py",
    "content": "'''\nAdapter\n=======\n\n.. versionadded:: 1.5\n\n.. warning::\n\n    This code is still experimental, and its API is subject to change in a\n    future version.\n\nAn :class:`~kivy.adapters.adapter.Adapter` is a bridge between data and\nan :class:`~kivy.uix.abstractview.AbstractView` or one of its subclasses, such\nas a :class:`~kivy.uix.listview.ListView`.\n\nThe following arguments can be passed to the contructor to initialise the\ncorresponding properties:\n\n* :attr:`~Adapter.data`: for any sort of data to be used in a view. For an\n  :class:`~kivy.adapters.adapter.Adapter`, data can be an object as well as a\n  list, dict, etc. For a :class:`~kivy.adapters.listadapter.ListAdapter`, data\n  should be a list. For a :class:`~kivy.adapters.dictadapter.DictAdapter`,\n  data should be a dict.\n\n* :attr:`~Adapter.cls`: the class used to instantiate each list item view\n  instance (Use this or the template argument).\n\n* :attr:`~Adapter.template`: a kv template to use to instantiate each list item\n  view instance (Use this or the cls argument).\n\n* :attr:`~Adapter.args_converter`: a function used to transform the data items\n  in preparation for either a cls instantiation or a kv template\n  invocation. If no args_converter is provided, the data items are assumed\n  to be simple strings.\n\nPlease refer to the :mod:`~kivy.adapters` documentation for an overview of how\nadapters are used.\n\n'''\n\n__all__ = ('Adapter', )\n\nfrom kivy.event import EventDispatcher\nfrom kivy.properties import ObjectProperty\nfrom kivy.lang import Builder\nfrom kivy.adapters.args_converters import list_item_args_converter\nfrom kivy.factory import Factory\nfrom kivy.compat import string_types\n\n\nclass Adapter(EventDispatcher):\n    '''An :class:`~kivy.adapters.adapter.Adapter` is a bridge between data and\n    an :class:`~kivy.uix.abstractview.AbstractView` or one of its subclasses,\n    such as a :class:`~kivy.uix.listview.ListView`.\n    '''\n\n    data = ObjectProperty(None)\n    '''\n    The data for which a view is to be constructed using either the cls or\n    template provided, together with the args_converter provided or the default\n    args_converter.\n\n    In this base class, data is an ObjectProperty, so it could be used for a\n    wide variety of single-view needs.\n\n    Subclasses may override it in order to use another data type, such as a\n    :class:`~kivy.properties.ListProperty` or\n    :class:`~kivy.properties.DictProperty` as appropriate. For example, in a\n    :class:`~.kivy.adapters.listadapter.ListAdapter`, data is a\n    :class:`~kivy.properties.ListProperty`.\n\n    :attr:`data` is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    cls = ObjectProperty(None)\n    '''\n    A class for instantiating a given view item (Use this or template). If this\n    is not set and neither is the template, a :class:`~kivy.uix.label.Label`\n    is used for the view item.\n\n    :attr:`cls` is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    template = ObjectProperty(None)\n    '''\n    A kv template for instantiating a given view item (Use this or cls).\n\n    :attr:`template` is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    args_converter = ObjectProperty(None)\n    '''\n    A function that prepares an args dict for the cls or kv template to build\n    a view from a data item.\n\n    If an args_converter is not provided, a default one is set that assumes\n    simple content in the form of a list of strings.\n\n    :attr:`args_converter` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    def __init__(self, **kwargs):\n\n        if 'data' not in kwargs:\n            raise Exception('adapter: input must include data argument')\n\n        if 'cls' in kwargs:\n            if 'template' in kwargs:\n                msg = 'adapter: cannot use cls and template at the same time'\n                raise Exception(msg)\n            elif not kwargs['cls']:\n                raise Exception('adapter: a cls or template must be defined')\n        else:\n            if 'template' in kwargs:\n                if not kwargs['template']:\n                    msg = 'adapter: a cls or template must be defined'\n                    raise Exception(msg)\n            else:\n                raise Exception('adapter: a cls or template must be defined')\n\n        if 'args_converter' in kwargs:\n            self.args_converter = kwargs['args_converter']\n        else:\n            self.args_converter = list_item_args_converter\n\n        super(Adapter, self).__init__(**kwargs)\n\n    def bind_triggers_to_view(self, func):\n        self.bind(data=func)\n\n    def get_data_item(self):\n        return self.data\n\n    def get_cls(self):\n        '''\n        .. versionadded:: 1.9.0\n\n        Returns the widget type specified by self.cls. If it is a\n        string, the :class:`~kivy.factory.Factory` is queried to retrieve the\n        widget class with the given name, otherwise it is returned directly.\n        '''\n        cls = self.cls\n        if isinstance(cls, string_types):\n            try:\n                cls = getattr(Factory, cls)\n            except AttributeError:\n                raise AttributeError(\n                    'Listadapter cls widget does not exist.')\n        return cls\n\n    def get_view(self, index):  # pragma: no cover\n        item_args = self.args_converter(self.data)\n\n        cls = self.get_cls()\n        if cls:\n            return cls(**item_args)\n        else:\n            return Builder.template(self.template, **item_args)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/adapters/args_converters.py",
    "content": "'''\nList Item View Argument Converters\n==================================\n\n.. versionadded:: 1.5\n\n\nThe default list item args converter for list adapters is a function (shown\nbelow) that takes a row index and a string. It returns a dict with the string as\nthe *text* item, along with two properties suited for simple text items with\na height of 25.\n\nSimple Usage\n------------\n\nArgument converters may be normal functions or, as in the case of the default\nargs converter, lambdas::\n\n    list_item_args_converter = lambda row_index, x: {'text': x,\n                                                     'size_hint_y': None,\n                                                     'height': 25}\n\nAdvanced Usage\n--------------\n\nTypically, having the argument converter perform a simple mapping suffices.\nThere are times, however, when more complex manipulation is required. When using\na :class:`~kivy.uix.listview.CompositeListItem`, it is possible to specify\na list of cls dictionaries. This allows you so compose a single view item\nout of multiple classes, each of which can recieve their own class constructor\narguments via the *kwargs* keyword::\n\n    args_converter = lambda row_index, rec: \\\\\n            {'text': rec['text'],\n             'size_hint_y': None,\n             'height': 25,\n             'cls_dicts': [{'cls': ListItemButton,\n                            'kwargs': {'text': rec['text']}},\n                           {'cls': ListItemLabel,\n                            'kwargs': {'text': \"Middle-{0}\".format(rec['text']),\n                                       'is_representing_cls': True}},\n                           {'cls': ListItemButton,\n                            'kwargs': {'text': rec['text']}}]}\n\nPlease see the `list_composite.py <https://github.com/\\\nkivy/kivy/tree/master/examples/widgets/lists/list_composite.py>`_ for a complete\nexample.\n\n'''\nlist_item_args_converter = lambda row_index, x: {'text': x,\n                                                 'size_hint_y': None,\n                                                 'height': 25}\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/adapters/dictadapter.py",
    "content": "'''\nDictAdapter\n===========\n\n.. versionadded:: 1.5\n\n.. warning::\n\n    This code is still experimental, and its API is subject to change in a\n    future version.\n\nA :class:`~kivy.adapters.dictadapter.DictAdapter` is an adapter around a\npython dictionary of records. It extends the list-like capabilities of the\n:class:`~kivy.adapters.listadapter.ListAdapter`.\n\nIf you wish to have a bare-bones list adapter, without selection, use the\n:class:`~kivy.adapters.simplelistadapter.SimpleListAdapter`.\n\n'''\n\n__all__ = ('DictAdapter', )\n\nfrom kivy.properties import ListProperty, DictProperty\nfrom kivy.adapters.listadapter import ListAdapter\n\n\nclass DictAdapter(ListAdapter):\n    '''A :class:`~kivy.adapters.dictadapter.DictAdapter` is an adapter around a\n    python dictionary of records. It extends the list-like capabilities of\n    the :class:`~kivy.adapters.listadapter.ListAdapter`.\n    '''\n\n    sorted_keys = ListProperty([])\n    '''The sorted_keys list property contains a list of hashable objects (can\n    be strings) that will be used directly if no args_converter function is\n    provided. If there is an args_converter, the record received from a\n    lookup of the data, using keys from sorted_keys, will be passed\n    to it for instantiation of list item view class instances.\n\n    :attr:`sorted_keys` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [].\n    '''\n\n    data = DictProperty(None)\n    '''A dict that indexes records by keys that are equivalent to the keys in\n    sorted_keys, or they are a superset of the keys in sorted_keys.\n\n    The values can be strings, class instances, dicts, etc.\n\n    :attr:`data` is a :class:`~kivy.properties.DictProperty` and defaults\n    to None.\n    '''\n\n    def __init__(self, **kwargs):\n        if 'sorted_keys' in kwargs:\n            if type(kwargs['sorted_keys']) not in (tuple, list):\n                msg = 'DictAdapter: sorted_keys must be tuple or list'\n                raise Exception(msg)\n        else:\n            self.sorted_keys = sorted(kwargs['data'].keys())\n\n        super(DictAdapter, self).__init__(**kwargs)\n\n        self.bind(sorted_keys=self.initialize_sorted_keys)\n\n    def bind_triggers_to_view(self, func):\n        self.bind(sorted_keys=func)\n        self.bind(data=func)\n\n    # self.data is paramount to self.sorted_keys. If sorted_keys is reset to\n    # mismatch data, force a reset of sorted_keys to data.keys(). So, in order\n    # to do a complete reset of data and sorted_keys, data must be reset\n    # first, followed by a reset of sorted_keys, if needed.\n    def initialize_sorted_keys(self, *args, **kwargs):\n        stale_sorted_keys = False\n        for key in self.sorted_keys:\n            if not key in self.data:\n                stale_sorted_keys = True\n                break\n        else:\n            if kwargs.get('new_data'):\n                if len(self.sorted_keys) != len(self.data):\n                    stale_sorted_keys = True\n        if stale_sorted_keys:\n            self.sorted_keys = sorted(self.data.keys())\n        self.delete_cache()\n        self.initialize_selection()\n\n    # Override ListAdapter.update_for_new_data().\n    def update_for_new_data(self, *args):\n        self.initialize_sorted_keys(new_data=True)\n\n    # Note: this is not len(self.data).\n    def get_count(self):\n        return len(self.sorted_keys)\n\n    def get_data_item(self, index):\n        if index < 0 or index >= len(self.sorted_keys):\n            return None\n        return self.data[self.sorted_keys[index]]\n\n    # [TODO] Also make methods for scroll_to_sel_start, scroll_to_sel_end,\n    #        scroll_to_sel_middle.\n\n    def trim_left_of_sel(self, *args):\n        '''Cut list items with indices in sorted_keys that are less than the\n        index of the first selected item, if there is a selection.\n\n        sorted_keys will be updated by update_for_new_data().\n        '''\n        if len(self.selection) > 0:\n            selected_keys = [sel.text for sel in self.selection]\n            first_sel_index = self.sorted_keys.index(selected_keys[0])\n            desired_keys = self.sorted_keys[first_sel_index:]\n            self.data = dict([(key, self.data[key]) for key in desired_keys])\n\n    def trim_right_of_sel(self, *args):\n        '''Cut list items with indices in sorted_keys that are greater than\n        the index of the last selected item, if there is a selection.\n\n        sorted_keys will be updated by update_for_new_data().\n        '''\n        if len(self.selection) > 0:\n            selected_keys = [sel.text for sel in self.selection]\n            last_sel_index = self.sorted_keys.index(selected_keys[-1])\n            desired_keys = self.sorted_keys[:last_sel_index + 1]\n            self.data = dict([(key, self.data[key]) for key in desired_keys])\n\n    def trim_to_sel(self, *args):\n        '''Cut list items with indices in sorted_keys that are les than or\n        greater than the index of the last selected item, if there is a\n        selection. This preserves intervening list items within the selected\n        range.\n\n        sorted_keys will be updated by update_for_new_data().\n        '''\n        if len(self.selection) > 0:\n            selected_keys = [sel.text for sel in self.selection]\n            first_sel_index = self.sorted_keys.index(selected_keys[0])\n            last_sel_index = self.sorted_keys.index(selected_keys[-1])\n            desired_keys = self.sorted_keys[first_sel_index:last_sel_index + 1]\n            self.data = dict([(key, self.data[key]) for key in desired_keys])\n\n    def cut_to_sel(self, *args):\n        '''Same as trim_to_sel, but intervening list items within the selected\n        range are also cut, leaving only list items that are selected.\n\n        sorted_keys will be updated by update_for_new_data().\n        '''\n        if len(self.selection) > 0:\n            selected_keys = [sel.text for sel in self.selection]\n            self.data = dict([(key, self.data[key]) for key in selected_keys])\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/adapters/listadapter.py",
    "content": "'''\nListAdapter\n=================\n\n.. versionadded:: 1.5\n\n.. warning::\n\n    This code is still experimental, and its API is subject to change in a\n    future version.\n\nA :class:`ListAdapter` is an adapter around a python list and adds support\nfor selection operations. If you wish to have a bare-bones list adapter,\nwithout selection, use a\n:class:`~kivy.adapters.simplelistadapter.SimpleListAdapter`.\n\nFrom an :class:`~kivy.adapters.Adapter`, a :class:`ListAdapter` inherits cls,\ntemplate, and args_converter properties and adds others that control selection\nbehaviour:\n\n* :attr:`~ListAdapter.selection`: a list of selected items.\n\n* :attr:`~ListAdapter.selection_mode`: one of 'single', 'multiple' or 'none'.\n\n* :attr:`~ListAdapter.allow_empty_selection`: a boolean. If False, a selection\n  is forced. If True, and only user or programmatic action will change\n  selection, it can be empty.\n\nA :class:`~kivy.adapters.dictadapter.DictAdapter` is a subclass of a\n:class:`~kivy.adapters.listadapter.ListAdapter`. They both dispatch the\n:attr:`~ListAdapter.on_selection_change` event when selection changes.\n\n.. versionchanged:: 1.6.0\n    Added data = ListProperty([]), which was proably inadvertently deleted at\n    some point. This means that whenever data changes an update will fire,\n    instead of having to reset the data object (Adapter has data defined as\n    an ObjectProperty, so we need to reset it here to ListProperty). See also\n    DictAdapter and its set of data = DictProperty().\n\n'''\n\n__all__ = ('ListAdapter', )\n\nimport inspect\nfrom kivy.event import EventDispatcher\nfrom kivy.adapters.adapter import Adapter\nfrom kivy.adapters.models import SelectableDataItem\nfrom kivy.properties import ListProperty\nfrom kivy.properties import DictProperty\nfrom kivy.properties import BooleanProperty\nfrom kivy.properties import OptionProperty\nfrom kivy.properties import NumericProperty\nfrom kivy.lang import Builder\n\n\nclass ListAdapter(Adapter, EventDispatcher):\n    '''\n    A base class for adapters interfacing with lists, dictionaries or other\n    collection type data, adding selection, view creation and management\n    functonality.\n    '''\n\n    data = ListProperty([])\n    '''The data list property is redefined here, overriding its definition as\n    an ObjectProperty in the Adapter class. We bind to data so that any\n    changes will trigger updates. See also how the\n    :class:`~kivy.adapters.DictAdapter` redefines data as a\n    :class:`~kivy.properties.DictProperty`.\n\n    :attr:`data` is a :class:`~kivy.properties.ListProperty` and defaults\n    to [].\n    '''\n\n    selection = ListProperty([])\n    '''The selection list property is the container for selected items.\n\n    :attr:`selection` is a :class:`~kivy.properties.ListProperty` and defaults\n    to [].\n    '''\n\n    selection_mode = OptionProperty('single',\n            options=('none', 'single', 'multiple'))\n    '''The selection_mode is a string and can be set to one of the following\n    values:\n\n       * 'none': use the list as a simple list (no select action). This option\n         is here so that selection can be turned off, momentarily or\n         permanently, for an existing list adapter.\n         A :class:`~kivy.adapters.listadapter.ListAdapter` is not meant to be\n         used as a primary no-selection list adapter. Use a\n         :class:`~kivy.adapters.simplelistadapter.SimpleListAdapter` for that.\n\n       * 'single': multi-touch/click ignored. Single item selection only.\n\n       * 'multiple': multi-touch / incremental addition to selection allowed;\n         may be limited to a count by setting the\n         :attr:`~ListAdapter.selection_limit`.\n\n    :attr:`selection_mode` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to 'single'.\n    '''\n\n    propagate_selection_to_data = BooleanProperty(False)\n    '''Normally, data items are not selected/deselected because the data items\n    might not have an is_selected boolean property -- only the item view for a\n    given data item is selected/deselected as part of the maintained selection\n    list. However, if the data items do have an is_selected property, or if\n    they mix in :class:`~kivy.adapters.models.SelectableDataItem`, the\n    selection machinery can propagate selection to data items. This can be\n    useful for storing selection state in a local database or backend database\n    for maintaining state in game play or other similar scenarios. It is a\n    convenience function.\n\n    To propagate selection or not?\n\n    Consider a shopping list application for shopping for fruits at the\n    market. The app allows for the selection of fruits to buy for each day of\n    the week, presenting seven lists: one for each day of the week. Each list is\n    loaded with all the available fruits, but the selection for each is a\n    subset. There is only one set of fruit data shared between the lists, so\n    it would not make sense to propagate selection to the data because\n    selection in any of the seven lists would clash and mix with that of the\n    others.\n\n    However, consider a game that uses the same fruits data for selecting\n    fruits available for fruit-tossing. A given round of play could have a\n    full fruits list, with fruits available for tossing shown selected. If the\n    game is saved and rerun, the full fruits list, with selection marked on\n    each item, would be reloaded correctly if selection is always propagated to\n    the data. You could accomplish the same functionality by writing code to\n    operate on list selection, but having selection stored in the data\n    ListProperty might prove convenient in some cases.\n\n    .. note::\n\n        This setting should be set to True if you wish to initialize the view\n        with item views already selected.\n\n    :attr:`propagate_selection_to_data` is a\n    :class:`~kivy.properties.BooleanProperty` and defaults to False.\n    '''\n\n    allow_empty_selection = BooleanProperty(True)\n    '''The allow_empty_selection may be used for cascading selection between\n    several list views, or between a list view and an observing view. Such\n    automatic maintenance of the selection is important for all but simple\n    list displays. Set allow_empty_selection to False and the selection is\n    auto-initialized and always maintained, so any observing views\n    may likewise be updated to stay in sync.\n\n    :attr:`allow_empty_selection` is a\n    :class:`~kivy.properties.BooleanProperty` and defaults to True.\n    '''\n\n    selection_limit = NumericProperty(-1)\n    '''When the :attr:`~ListAdapter.selection_mode` is 'multiple' and the\n    selection_limit is\n    non-negative, this number will limit the number of selected items. It can\n    be set to 1, which is equivalent to single selection. If selection_limit is\n    not set, the default value is -1, meaning that no limit will be enforced.\n\n    :attr:`selection_limit` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to -1 (no limit).\n    '''\n\n    cached_views = DictProperty({})\n    '''View instances for data items are instantiated and managed by the\n    adapter. Here we maintain a dictionary containing the view\n    instances keyed to the indices in the data.\n\n    This dictionary works as a cache. get_view() only asks for a view from\n    the adapter if one is not already stored for the requested index.\n\n    :attr:`cached_views` is a :class:`~kivy.properties.DictProperty` and\n    defaults to {}.\n    '''\n\n    __events__ = ('on_selection_change', )\n\n    def __init__(self, **kwargs):\n        super(ListAdapter, self).__init__(**kwargs)\n\n        self.bind(selection_mode=self.selection_mode_changed,\n                  allow_empty_selection=self.check_for_empty_selection,\n                  data=self.update_for_new_data)\n\n        self.update_for_new_data()\n\n    def delete_cache(self, *args):\n        self.cached_views = {}\n\n    def get_count(self):\n        return len(self.data)\n\n    def get_data_item(self, index):\n        if index < 0 or index >= len(self.data):\n            return None\n        return self.data[index]\n\n    def selection_mode_changed(self, *args):\n        if self.selection_mode == 'none':\n            for selected_view in self.selection:\n                self.deselect_item_view(selected_view)\n        else:\n            self.check_for_empty_selection()\n\n    def get_view(self, index):\n        if index in self.cached_views:\n            return self.cached_views[index]\n        item_view = self.create_view(index)\n        if item_view:\n            self.cached_views[index] = item_view\n        return item_view\n\n    def create_view(self, index):\n        '''This method is more complicated than the ones in the\n        :class:`~kivy.adapters.adapter.Adapter` and\n        :class:`~kivy.adapters.simplelistadapter.SimpleListAdapter` classes\n        because here we create bindings for the data items and their children\n        back to the *self.handle_selection()* event. We also perform\n        other selection-related tasks to keep item views in sync with the data.\n        '''\n        item = self.get_data_item(index)\n        if item is None:\n            return None\n\n        item_args = self.args_converter(index, item)\n\n        item_args['index'] = index\n\n        cls = self.get_cls()\n        if cls:\n            view_instance = cls(**item_args)\n        else:\n            view_instance = Builder.template(self.template, **item_args)\n\n        if self.propagate_selection_to_data:\n            # The data item must be a subclass of SelectableDataItem, or must\n            # have an is_selected boolean or function, so it has is_selected\n            # available. If is_selected is unavailable on the data item, an\n            # exception is raised.\n            #\n            if isinstance(item, SelectableDataItem):\n                if item.is_selected:\n                    self.handle_selection(view_instance)\n            elif type(item) == dict and 'is_selected' in item:\n                if item['is_selected']:\n                    self.handle_selection(view_instance)\n            elif hasattr(item, 'is_selected'):\n                if (inspect.isfunction(item.is_selected)\n                        or inspect.ismethod(item.is_selected)):\n                    if item.is_selected():\n                        self.handle_selection(view_instance)\n                else:\n                    if item.is_selected:\n                        self.handle_selection(view_instance)\n            else:\n                msg = \"ListAdapter: unselectable data item for {0}\"\n                raise Exception(msg.format(index))\n\n        view_instance.bind(on_release=self.handle_selection)\n\n        for child in view_instance.children:\n            child.bind(on_release=self.handle_selection)\n\n        return view_instance\n\n    def on_selection_change(self, *args):\n        '''on_selection_change() is the default handler for the\n        on_selection_change event. You can bind to this event to get notified\n        of selection changes.\n\n        :Parameters:\n            adapter: :class:`~ListAdapter` or subclass\n                The instance of the list adapter where the selection changed.\n                Use the adapters :attr:`selection` property to see what has been\n                selected.\n        '''\n        pass\n\n    def handle_selection(self, view, hold_dispatch=False, *args):\n        if view not in self.selection:\n            if self.selection_mode in ['none', 'single'] and \\\n                    len(self.selection) > 0:\n                for selected_view in self.selection:\n                    self.deselect_item_view(selected_view)\n            if self.selection_mode != 'none':\n                if self.selection_mode == 'multiple':\n                    if self.allow_empty_selection:\n                        # If < 0, selection_limit is not active.\n                        if self.selection_limit < 0:\n                            self.select_item_view(view)\n                        else:\n                            if len(self.selection) < self.selection_limit:\n                                self.select_item_view(view)\n                    else:\n                        self.select_item_view(view)\n                else:\n                    self.select_item_view(view)\n        else:\n            self.deselect_item_view(view)\n            if self.selection_mode != 'none':\n                # If the deselection makes selection empty, the following call\n                # will check allows_empty_selection, and if False, will\n                # select the first item. If view happens to be the first item,\n                # this will be a reselection, and the user will notice no\n                # change, except perhaps a flicker.\n                #\n                self.check_for_empty_selection()\n\n        if not hold_dispatch:\n            self.dispatch('on_selection_change')\n\n    def select_data_item(self, item):\n        self.set_data_item_selection(item, True)\n\n    def deselect_data_item(self, item):\n        self.set_data_item_selection(item, False)\n\n    def set_data_item_selection(self, item, value):\n        if isinstance(item, SelectableDataItem):\n            item.is_selected = value\n        elif type(item) == dict:\n            item['is_selected'] = value\n        elif hasattr(item, 'is_selected'):\n            if (inspect.isfunction(item.is_selected)\n                    or inspect.ismethod(item.is_selected)):\n                item.is_selected()\n            else:\n                item.is_selected = value\n\n    def select_item_view(self, view):\n        view.select()\n        view.is_selected = True\n        self.selection.append(view)\n\n        # [TODO] sibling selection for composite items\n        #        Needed? Or handled from parent?\n        #        (avoid circular, redundant selection)\n        #if hasattr(view, 'parent') and hasattr(view.parent, 'children'):\n         #siblings = [child for child in view.parent.children if child != view]\n         #for sibling in siblings:\n             #if hasattr(sibling, 'select'):\n                 #sibling.select()\n\n        if self.propagate_selection_to_data:\n            data_item = self.get_data_item(view.index)\n            self.select_data_item(data_item)\n\n    def select_list(self, view_list, extend=True):\n        '''The select call is made for the items in the provided view_list.\n\n        Arguments:\n\n            view_list: the list of item views to become the new selection, or\n            to add to the existing selection\n\n            extend: boolean for whether or not to extend the existing list\n        '''\n        if not extend:\n            self.selection = []\n\n        for view in view_list:\n            self.handle_selection(view, hold_dispatch=True)\n\n        self.dispatch('on_selection_change')\n\n    def deselect_item_view(self, view):\n        view.deselect()\n        view.is_selected = False\n        self.selection.remove(view)\n\n        # [TODO] sibling deselection for composite items\n        #        Needed? Or handled from parent?\n        #        (avoid circular, redundant selection)\n        #if hasattr(view, 'parent') and hasattr(view.parent, 'children'):\n         #siblings = [child for child in view.parent.children if child != view]\n         #for sibling in siblings:\n             #if hasattr(sibling, 'deselect'):\n                 #sibling.deselect()\n\n        if self.propagate_selection_to_data:\n            item = self.get_data_item(view.index)\n            self.deselect_data_item(item)\n\n    def deselect_list(self, l):\n        for view in l:\n            self.handle_selection(view, hold_dispatch=True)\n\n        self.dispatch('on_selection_change')\n\n    # [TODO] Could easily add select_all() and deselect_all().\n\n    def update_for_new_data(self, *args):\n        self.delete_cache()\n        self.initialize_selection()\n\n    def initialize_selection(self, *args):\n        if len(self.selection) > 0:\n            self.selection = []\n            self.dispatch('on_selection_change')\n\n        self.check_for_empty_selection()\n\n    def check_for_empty_selection(self, *args):\n        if not self.allow_empty_selection:\n            if len(self.selection) == 0:\n                # Select the first item if we have it.\n                v = self.get_view(0)\n                if v is not None:\n                    self.handle_selection(v)\n\n    # [TODO] Also make methods for scroll_to_sel_start, scroll_to_sel_end,\n    #        scroll_to_sel_middle.\n\n    def trim_left_of_sel(self, *args):\n        '''Cut list items with indices in sorted_keys that are less than the\n        index of the first selected item if there is a selection.\n        '''\n        if len(self.selection) > 0:\n            first_sel_index = min([sel.index for sel in self.selection])\n            self.data = self.data[first_sel_index:]\n\n    def trim_right_of_sel(self, *args):\n        '''Cut list items with indices in sorted_keys that are greater than\n        the index of the last selected item if there is a selection.\n        '''\n        if len(self.selection) > 0:\n            last_sel_index = max([sel.index for sel in self.selection])\n            print('last_sel_index', last_sel_index)\n            self.data = self.data[:last_sel_index + 1]\n\n    def trim_to_sel(self, *args):\n        '''Cut list items with indices in sorted_keys that are less than or\n        greater than the index of the last selected item if there is a\n        selection. This preserves intervening list items within the selected\n        range.\n        '''\n        if len(self.selection) > 0:\n            sel_indices = [sel.index for sel in self.selection]\n            first_sel_index = min(sel_indices)\n            last_sel_index = max(sel_indices)\n            self.data = self.data[first_sel_index:last_sel_index + 1]\n\n    def cut_to_sel(self, *args):\n        '''Same as trim_to_sel, but intervening list items within the selected\n        range are also cut, leaving only list items that are selected.\n        '''\n        if len(self.selection) > 0:\n            self.data = self.selection\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/adapters/models.py",
    "content": "'''\nSelectableDataItem\n==================\n\n.. versionadded:: 1.5\n\n.. warning::\n\n    This code is still experimental, and its API is subject to change in a\n    future version.\n\nData Models\n-----------\n\nKivy is open about the type of data used in applications built with\nthe system. However, base classes are sometimes needed to ensure data conforms\nto the requirements of some parts of the system.\n\nA :class:`SelectableDataItem` is a basic Python data model class that can be\nused as a mixin to build data objects that are compatible with Kivy's\n:class:`~kivy.adapters.adapter.Adapter`\nand selection system and which work with views such as a\n:class:`~kivy.uix.listview.ListView`. A boolean *is_selected*\nproperty a requirement.\n\nThe default operation of the selection system is to not propogate selection in\nviews such as ListView to the underlying data: selection is by default a\nview-only operation. However, in some cases, it is useful to propogate\nselection to the actual data items.\n\nYou may, of course, build your own Python data model system as the backend for\na Kivy application. For instance, to use the `Google App Engine Data Modeling\n<https://cloud.google.com/appengine/docs/python/datastore/datamodeling>`_\nsystem with Kivy, you could define your class as follows::\n\n    from google.appengine.ext import db\n\n    class MySelectableDataItem(db.Model):\n        # ... other properties\n        is_selected = db.BooleanProperty()\n\nIt is easy to build such a class with plain Python.\n\n'''\n\n__all__ = ('SelectableDataItem', )\n\n\nclass SelectableDataItem(object):\n    '''\n    A mixin class containing requirements for selection operations.\n    '''\n\n    def __init__(self, **kwargs):\n        super(SelectableDataItem, self).__init__()\n\n        self._is_selected = kwargs.get('is_selected', False)\n\n    @property\n    def is_selected(self):\n        \"\"\"A boolean property indicating whether the data item is selected or\n        not.\"\"\"\n        return self._is_selected\n\n    @is_selected.setter\n    def is_selected(self, value):\n        self._is_selected = value\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/adapters/simplelistadapter.py",
    "content": "'''\nSimpleListAdapter\n=================\n\n.. versionadded:: 1.5\n\n.. warning::\n\n    This code is still experimental, and its API is subject to change in a\n    future version.\n\nThe :class:`~kivy.adapters.simplelistadapter.SimpleListAdapter` is used for\nbasic lists. For example, it can be used for displaying a list of read-only\nstrings that do not require user interaction.\n\n'''\n\n__all__ = ('SimpleListAdapter', )\n\nfrom kivy.adapters.adapter import Adapter\nfrom kivy.properties import ListProperty\nfrom kivy.lang import Builder\n\n\nclass SimpleListAdapter(Adapter):\n    '''A :class:`~kivy.adapters.simplelistadapter.SimpleListAdapter` is an\n    adapter around a Python list.\n\n    From :class:`~kivy.adapters.adapter.Adapter`, the\n    :class:`~kivy.adapters.simplelistadapter.ListAdapter` gets cls, template,\n    and args_converter properties.\n    '''\n\n    data = ListProperty([])\n    '''The data list property contains a list of objects (which can be strings)\n    that will be used directly if no args_converter function is provided. If\n    there is an args_converter, the data objects will be passed to it for\n    instantiating the item view class instances.\n\n    :attr:`data` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [].\n    '''\n\n    def __init__(self, **kwargs):\n        if 'data' not in kwargs:\n            raise Exception('list adapter: input must include data argument')\n        if not isinstance(kwargs['data'], list) and \\\n                not isinstance(kwargs['data'], tuple):\n            raise Exception('list adapter: data must be a tuple or list')\n        super(SimpleListAdapter, self).__init__(**kwargs)\n\n    def get_count(self):\n        return len(self.data)\n\n    def get_data_item(self, index):\n        if index < 0 or index >= len(self.data):\n            return None\n        return self.data[index]\n\n    # Returns a view instance for an item.\n    def get_view(self, index):\n        item = self.get_data_item(index)\n\n        if item is None:\n            return None\n\n        item_args = self.args_converter(index, item)\n\n        cls = self.get_cls()\n        if cls:\n            instance = cls(**item_args)\n            return instance\n        else:\n            return Builder.template(self.template, **item_args)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/animation.py",
    "content": "'''\nAnimation\n=========\n\n:class:`Animation` and :class:`AnimationTransition` are used to animate\n:class:`~kivy.uix.widget.Widget` properties. You must specify at least a\nproperty name and target value. To use an Animation, follow these steps:\n\n    * Setup an Animation object\n    * Use the Animation object on a Widget\n\nSimple animation\n----------------\n\nTo animate a Widget's x or y position, simply specify the target x/y values\nwhere you want the widget positioned at the end of the animation::\n\n    anim = Animation(x=100, y=100)\n    anim.start(widget)\n\nThe animation will last for 1 second unless :attr:`duration` is specified.\nWhen anim.start() is called, the Widget will move smoothly from the current\nx/y position to (100, 100).\n\nMultiple properties and transitions\n-----------------------------------\n\nYou can animate multiple properties and use built-in or custom transition\nfunctions using :attr:`transition` (or the `t=` shortcut). For example,\nto animate the position and size using the 'in_quad' transition::\n\n    anim = Animation(x=50, size=(80, 80), t='in_quad')\n    anim.start(widget)\n\nNote that the `t=` parameter can be the string name of a method in the\n:class:`AnimationTransition` class or your own animation function.\n\nSequential animation\n--------------------\n\nTo join animations sequentially, use the '+' operator. The following example\nwill animate to x=50 over 1 second, then animate the size to (80, 80) over the\nnext two seconds::\n\n    anim = Animation(x=50) + Animation(size=(80, 80), duration=2.)\n    anim.start(widget)\n\nParallel animation\n------------------\n\nTo join animations in parallel, use the '&' operator. The following example\nwill animate the position to (80, 10) over 1 second, whilst in parallel\nanimating the size to (800, 800)::\n\n    anim = Animation(pos=(80, 10))\n    anim &= Animation(size=(800, 800), duration=2.)\n    anim.start(widget)\n\nKeep in mind that creating overlapping animations on the same property may have\nunexpected results. If you want to apply multiple animations to the same\nproperty, you should either schedule them sequentially (via the '+' operator or\nusing the *on_complete* callback) or cancel previous animations using the\n:attr:`~Animation.cancel_all` method.\n\nRepeating animation\n-------------------\n\n.. versionadded:: 1.8.0\n\n.. note::\n    This is currently only implemented for 'Sequence' animations.\n\nTo set an animation to repeat, simply set the :attr:`Sequence.repeat`\nproperty to `True`::\n\n    anim = Animation(...) + Animation(...)\n    anim.repeat = True\n    anim.start(widget)\n\nFor flow control of animations such as stopping and cancelling, use the methods\nalready in place in the animation module.\n'''\n\n__all__ = ('Animation', 'AnimationTransition')\n\nfrom math import sqrt, cos, sin, pi\nfrom kivy.event import EventDispatcher\nfrom kivy.clock import Clock\nfrom kivy.compat import string_types, iterkeys\nfrom kivy.weakproxy import WeakProxy\n\n\nclass Animation(EventDispatcher):\n    '''Create an animation definition that can be used to animate a Widget.\n\n    :Parameters:\n        `duration` or `d`: float, defaults to 1.\n            Duration of the animation, in seconds.\n        `transition` or `t`: str or func\n            Transition function for animate properties. It can be the name of a\n            method from :class:`AnimationTransition`.\n        `step` or `s`: float\n            Step in milliseconds of the animation. Defaults to 1 / 60.\n\n    :Events:\n        `on_start`: widget\n            Fired when the animation is started on a widget.\n        `on_complete`: widget\n            Fired when the animation is completed or stopped on a widget.\n        `on_progress`: widget, progression\n            Fired when the progression of the animation is changing.\n\n    .. versionchanged:: 1.4.0\n        Added s/step parameter.\n\n    '''\n\n    _instances = set()\n\n    __events__ = ('on_start', 'on_progress', 'on_complete')\n\n    def __init__(self, **kw):\n        super(Animation, self).__init__(**kw)\n\n        # Initialize\n        self._clock_installed = False\n        self._duration = kw.get('d', kw.get('duration', 1.))\n        self._transition = kw.get('t', kw.get('transition', 'linear'))\n        self._step = kw.get('s', kw.get('step', 1. / 60.))\n        if isinstance(self._transition, string_types):\n            self._transition = getattr(AnimationTransition, self._transition)\n        for key in ('d', 't', 's', 'step', 'duration', 'transition'):\n            kw.pop(key, None)\n        self._animated_properties = kw\n        self._widgets = {}\n\n    @property\n    def duration(self):\n        '''Return the duration of the animation.\n        '''\n        return self._duration\n\n    @property\n    def transition(self):\n        '''Return the transition of the animation.\n        '''\n        return self._transition\n\n    @property\n    def animated_properties(self):\n        '''Return the properties used to animate.\n        '''\n        return self._animated_properties\n\n    @staticmethod\n    def stop_all(widget, *largs):\n        '''Stop all animations that concern a specific widget / list of\n        properties.\n\n        Example::\n\n            anim = Animation(x=50)\n            anim.start(widget)\n\n            # and later\n            Animation.stop_all(widget, 'x')\n        '''\n        if len(largs):\n            for animation in list(Animation._instances):\n                for x in largs:\n                    animation.stop_property(widget, x)\n        else:\n            for animation in set(Animation._instances):\n                animation.stop(widget)\n\n    @staticmethod\n    def cancel_all(widget, *largs):\n        '''Cancel all animations that concern a specific widget / list of\n        properties. See :attr:`cancel`.\n\n        Example::\n\n            anim = Animation(x=50)\n            anim.start(widget)\n\n            # and later\n            Animation.cancel_all(widget, 'x')\n\n        .. versionadded:: 1.4.0\n        '''\n        if len(largs):\n            for animation in list(Animation._instances):\n                for x in largs:\n                    animation.cancel_property(widget, x)\n        else:\n            for animation in set(Animation._instances):\n                animation.cancel(widget)\n\n    def start(self, widget):\n        '''Start the animation on a widget.\n        '''\n        self.stop(widget)\n        self._initialize(widget)\n        self._register()\n        self.dispatch('on_start', widget)\n\n    def stop(self, widget):\n        '''Stop the animation previously applied to a widget, triggering the\n        `on_complete` event.'''\n        props = self._widgets.pop(widget.uid, None)\n        if props:\n            self.dispatch('on_complete', widget)\n        self.cancel(widget)\n\n    def cancel(self, widget):\n        '''Cancel the animation previously applied to a widget. Same\n        effect as :attr:`stop`, except the `on_complete` event will\n        *not* be triggered!\n\n        .. versionadded:: 1.4.0\n        '''\n        self._widgets.pop(widget.uid, None)\n        self._clock_uninstall()\n        if not self._widgets:\n            self._unregister()\n\n    def stop_property(self, widget, prop):\n        '''Even if an animation is running, remove a property. It will not be\n        animated futher. If it was the only/last property being animated,\n        the animation will be stopped (see :attr:`stop`).\n        '''\n        props = self._widgets.get(widget.uid, None)\n        if not props:\n            return\n        props['properties'].pop(prop, None)\n\n        # no more properties to animation ? kill the animation.\n        if not props['properties']:\n            self.stop(widget)\n\n    def cancel_property(self, widget, prop):\n        '''Even if an animation is running, remove a property. It will not be\n        animated further. If it was the only/last property being animated,\n        the animation will be canceled (see :attr:`cancel`)\n\n        .. versionadded:: 1.4.0\n        '''\n        props = self._widgets.get(widget.uid, None)\n        if not props:\n            return\n        props['properties'].pop(prop, None)\n\n        # no more properties to animation ? kill the animation.\n        if not props['properties']:\n            self.cancel(widget)\n\n    def have_properties_to_animate(self, widget):\n        '''Return True if a widget still has properties to animate.\n\n        .. versionadded:: 1.8.0\n        '''\n        props = self._widgets.get(widget.uid, None)\n        if props and props['properties']:\n            return True\n\n    #\n    # Private\n    #\n    def _register(self):\n        Animation._instances.add(self)\n\n    def _unregister(self):\n        if self in Animation._instances:\n            Animation._instances.remove(self)\n\n    def _initialize(self, widget):\n        d = self._widgets[widget.uid] = {\n            'widget': widget,\n            'properties': {},\n            'time': None}\n\n        # get current values\n        p = d['properties']\n        for key, value in self._animated_properties.items():\n            original_value = getattr(widget, key)\n            if isinstance(original_value, (tuple, list)):\n                original_value = original_value[:]\n            elif isinstance(original_value, dict):\n                original_value = original_value.copy()\n            p[key] = (original_value, value)\n\n        # install clock\n        self._clock_install()\n\n    def _clock_install(self):\n        if self._clock_installed:\n            return\n        Clock.schedule_interval(self._update, self._step)\n        self._clock_installed = True\n\n    def _clock_uninstall(self):\n        if self._widgets or not self._clock_installed:\n            return\n        self._clock_installed = False\n        Clock.unschedule(self._update)\n\n    def _update(self, dt):\n        widgets = self._widgets\n        transition = self._transition\n        calculate = self._calculate\n        for uid in list(widgets.keys())[:]:\n            anim = widgets[uid]\n            widget = anim['widget']\n\n            if isinstance(widget, WeakProxy) and not len(dir(widget)):\n                # empty proxy, widget is gone. ref: #2458\n                del widgets[uid]\n                continue\n\n            if anim['time'] is None:\n                anim['time'] = 0.\n            else:\n                anim['time'] += dt\n\n            # calculate progression\n            if self._duration:\n                progress = min(1., anim['time'] / self._duration)\n            else:\n                progress = 1\n            t = transition(progress)\n\n            # apply progression on widget\n            for key, values in anim['properties'].items():\n                a, b = values\n                value = calculate(a, b, t)\n                setattr(widget, key, value)\n\n            self.dispatch('on_progress', widget, progress)\n\n            # time to stop ?\n            if progress >= 1.:\n                self.stop(widget)\n\n    def _calculate(self, a, b, t):\n        _calculate = self._calculate\n        if isinstance(a, list) or isinstance(a, tuple):\n            if isinstance(a, list):\n                tp = list\n            else:\n                tp = tuple\n            return tp([_calculate(a[x], b[x], t) for x in range(len(a))])\n        elif isinstance(a, dict):\n            d = {}\n            for x in iterkeys(a):\n                if x not in b:\n                    # User requested to animate only part of the dict.\n                    # Copy the rest\n                    d[x] = a[x]\n                else:\n                    d[x] = _calculate(a[x], b[x], t)\n            return d\n        else:\n            return (a * (1. - t)) + (b * t)\n\n    #\n    # Default handlers\n    #\n    def on_start(self, widget):\n        pass\n\n    def on_progress(self, widget, progress):\n        pass\n\n    def on_complete(self, widget):\n        pass\n\n    def __add__(self, animation):\n        return Sequence(self, animation)\n\n    def __and__(self, animation):\n        return Parallel(self, animation)\n\n\nclass Sequence(Animation):\n\n    def __init__(self, anim1, anim2):\n        super(Sequence, self).__init__()\n\n        #: Repeat the sequence. See 'Repeating animation' in the header\n        #: documentation.\n        self.repeat = False\n\n        self.anim1 = anim1\n        self.anim2 = anim2\n\n        self.anim1.bind(on_start=self.on_anim1_start,\n                        on_progress=self.on_anim1_progress)\n        self.anim2.bind(on_complete=self.on_anim2_complete,\n                        on_progress=self.on_anim2_progress)\n\n    @property\n    def duration(self):\n        return self.anim1.duration + self.anim2.duration\n\n    def start(self, widget):\n        self.stop(widget)\n        self._widgets[widget.uid] = True\n        self._register()\n        self.anim1.start(widget)\n        self.anim1.bind(on_complete=self.on_anim1_complete)\n\n    def stop(self, widget):\n        self.anim1.stop(widget)\n        self.anim2.stop(widget)\n        props = self._widgets.pop(widget.uid, None)\n        if props:\n            self.dispatch('on_complete', widget)\n        super(Sequence, self).cancel(widget)\n\n    def stop_property(self, widget, prop):\n        self.anim1.stop_property(widget, prop)\n        self.anim2.stop_property(widget, prop)\n        if (not self.anim1.have_properties_to_animate(widget) and\n                not self.anim2.have_properties_to_animate(widget)):\n            self.stop(widget)\n\n    def cancel(self, widget):\n        self.anim1.cancel(widget)\n        self.anim2.cancel(widget)\n        super(Sequence, self).cancel(widget)\n\n    def on_anim1_start(self, instance, widget):\n        self.dispatch('on_start', widget)\n\n    def on_anim1_complete(self, instance, widget):\n        self.anim1.unbind(on_complete=self.on_anim1_complete)\n        self.anim2.start(widget)\n\n    def on_anim1_progress(self, instance, widget, progress):\n        self.dispatch('on_progress', widget, progress / 2.)\n\n    def on_anim2_complete(self, instance, widget):\n        '''Repeating logic used with boolean variable \"repeat\".\n\n        .. versionadded:: 1.7.1\n        '''\n        if self.repeat:\n            self.anim1.start(widget)\n            self.anim1.bind(on_complete=self.on_anim1_complete)\n        else:\n            self.dispatch('on_complete', widget)\n\n    def on_anim2_progress(self, instance, widget, progress):\n        self.dispatch('on_progress', widget, .5 + progress / 2.)\n\n\nclass Parallel(Animation):\n\n    def __init__(self, anim1, anim2):\n        super(Parallel, self).__init__()\n        self.anim1 = anim1\n        self.anim2 = anim2\n\n        self.anim1.bind(on_complete=self.on_anim_complete)\n        self.anim2.bind(on_complete=self.on_anim_complete)\n\n    @property\n    def duration(self):\n        return max(self.anim1.duration, self.anim2.duration)\n\n    def start(self, widget):\n        self.stop(widget)\n        self.anim1.start(widget)\n        self.anim2.start(widget)\n        self._widgets[widget.uid] = {'complete': 0}\n        self._register()\n        self.dispatch('on_start', widget)\n\n    def stop(self, widget):\n        self.anim1.stop(widget)\n        self.anim2.stop(widget)\n        props = self._widgets.pop(widget.uid, None)\n        if props:\n            self.dispatch('on_complete', widget)\n        super(Parallel, self).cancel(widget)\n\n    def stop_property(self, widget, prop):\n        self.anim1.stop_property(widget, prop)\n        self.anim2.stop_property(widget, prop)\n        if (not self.anim1.have_properties_to_animate(widget) and\n                not self.anim2.have_properties_to_animate(widget)):\n            self.stop(widget)\n\n    def cancel(self, widget):\n        self.anim1.cancel(widget)\n        self.anim2.cancel(widget)\n        super(Parallel, self).cancel(widget)\n\n    def on_anim_complete(self, instance, widget):\n        self._widgets[widget.uid]['complete'] += 1\n        if self._widgets[widget.uid]['complete'] == 2:\n            self.stop(widget)\n\n\nclass AnimationTransition(object):\n    '''Collection of animation functions to be used with the Animation object.\n    Easing Functions ported to Kivy from the Clutter Project\n    http://www.clutter-project.org/docs/clutter/stable/ClutterAlpha.html\n\n    The `progress` parameter in each animation function is in the range 0-1.\n    '''\n\n    @staticmethod\n    def linear(progress):\n        '''.. image:: images/anim_linear.png'''\n        return progress\n\n    @staticmethod\n    def in_quad(progress):\n        '''.. image:: images/anim_in_quad.png\n        '''\n        return progress * progress\n\n    @staticmethod\n    def out_quad(progress):\n        '''.. image:: images/anim_out_quad.png\n        '''\n        return -1.0 * progress * (progress - 2.0)\n\n    @staticmethod\n    def in_out_quad(progress):\n        '''.. image:: images/anim_in_out_quad.png\n        '''\n        p = progress * 2\n        if p < 1:\n            return 0.5 * p * p\n        p -= 1.0\n        return -0.5 * (p * (p - 2.0) - 1.0)\n\n    @staticmethod\n    def in_cubic(progress):\n        '''.. image:: images/anim_in_cubic.png\n        '''\n        return progress * progress * progress\n\n    @staticmethod\n    def out_cubic(progress):\n        '''.. image:: images/anim_out_cubic.png\n        '''\n        p = progress - 1.0\n        return p * p * p + 1.0\n\n    @staticmethod\n    def in_out_cubic(progress):\n        '''.. image:: images/anim_in_out_cubic.png\n        '''\n        p = progress * 2\n        if p < 1:\n            return 0.5 * p * p * p\n        p -= 2\n        return 0.5 * (p * p * p + 2.0)\n\n    @staticmethod\n    def in_quart(progress):\n        '''.. image:: images/anim_in_quart.png\n        '''\n        return progress * progress * progress * progress\n\n    @staticmethod\n    def out_quart(progress):\n        '''.. image:: images/anim_out_quart.png\n        '''\n        p = progress - 1.0\n        return -1.0 * (p * p * p * p - 1.0)\n\n    @staticmethod\n    def in_out_quart(progress):\n        '''.. image:: images/anim_in_out_quart.png\n        '''\n        p = progress * 2\n        if p < 1:\n            return 0.5 * p * p * p * p\n        p -= 2\n        return -0.5 * (p * p * p * p - 2.0)\n\n    @staticmethod\n    def in_quint(progress):\n        '''.. image:: images/anim_in_quint.png\n        '''\n        return progress * progress * progress * progress * progress\n\n    @staticmethod\n    def out_quint(progress):\n        '''.. image:: images/anim_out_quint.png\n        '''\n        p = progress - 1.0\n        return p * p * p * p * p + 1.0\n\n    @staticmethod\n    def in_out_quint(progress):\n        '''.. image:: images/anim_in_out_quint.png\n        '''\n        p = progress * 2\n        if p < 1:\n            return 0.5 * p * p * p * p * p\n        p -= 2.0\n        return 0.5 * (p * p * p * p * p + 2.0)\n\n    @staticmethod\n    def in_sine(progress):\n        '''.. image:: images/anim_in_sine.png\n        '''\n        return -1.0 * cos(progress * (pi / 2.0)) + 1.0\n\n    @staticmethod\n    def out_sine(progress):\n        '''.. image:: images/anim_out_sine.png\n        '''\n        return sin(progress * (pi / 2.0))\n\n    @staticmethod\n    def in_out_sine(progress):\n        '''.. image:: images/anim_in_out_sine.png\n        '''\n        return -0.5 * (cos(pi * progress) - 1.0)\n\n    @staticmethod\n    def in_expo(progress):\n        '''.. image:: images/anim_in_expo.png\n        '''\n        if progress == 0:\n            return 0.0\n        return pow(2, 10 * (progress - 1.0))\n\n    @staticmethod\n    def out_expo(progress):\n        '''.. image:: images/anim_out_expo.png\n        '''\n        if progress == 1.0:\n            return 1.0\n        return -pow(2, -10 * progress) + 1.0\n\n    @staticmethod\n    def in_out_expo(progress):\n        '''.. image:: images/anim_in_out_expo.png\n        '''\n        if progress == 0:\n            return 0.0\n        if progress == 1.:\n            return 1.0\n        p = progress * 2\n        if p < 1:\n            return 0.5 * pow(2, 10 * (p - 1.0))\n        p -= 1.0\n        return 0.5 * (-pow(2, -10 * p) + 2.0)\n\n    @staticmethod\n    def in_circ(progress):\n        '''.. image:: images/anim_in_circ.png\n        '''\n        return -1.0 * (sqrt(1.0 - progress * progress) - 1.0)\n\n    @staticmethod\n    def out_circ(progress):\n        '''.. image:: images/anim_out_circ.png\n        '''\n        p = progress - 1.0\n        return sqrt(1.0 - p * p)\n\n    @staticmethod\n    def in_out_circ(progress):\n        '''.. image:: images/anim_in_out_circ.png\n        '''\n        p = progress * 2\n        if p < 1:\n            return -0.5 * (sqrt(1.0 - p * p) - 1.0)\n        p -= 2.0\n        return 0.5 * (sqrt(1.0 - p * p) + 1.0)\n\n    @staticmethod\n    def in_elastic(progress):\n        '''.. image:: images/anim_in_elastic.png\n        '''\n        p = .3\n        s = p / 4.0\n        q = progress\n        if q == 1:\n            return 1.0\n        q -= 1.0\n        return -(pow(2, 10 * q) * sin((q - s) * (2 * pi) / p))\n\n    @staticmethod\n    def out_elastic(progress):\n        '''.. image:: images/anim_out_elastic.png\n        '''\n        p = .3\n        s = p / 4.0\n        q = progress\n        if q == 1:\n            return 1.0\n        return pow(2, -10 * q) * sin((q - s) * (2 * pi) / p) + 1.0\n\n    @staticmethod\n    def in_out_elastic(progress):\n        '''.. image:: images/anim_in_out_elastic.png\n        '''\n        p = .3 * 1.5\n        s = p / 4.0\n        q = progress * 2\n        if q == 2:\n            return 1.0\n        if q < 1:\n            q -= 1.0\n            return -.5 * (pow(2, 10 * q) * sin((q - s) * (2.0 * pi) / p))\n        else:\n            q -= 1.0\n            return pow(2, -10 * q) * sin((q - s) * (2.0 * pi) / p) * .5 + 1.0\n\n    @staticmethod\n    def in_back(progress):\n        '''.. image:: images/anim_in_back.png\n        '''\n        return progress * progress * ((1.70158 + 1.0) * progress - 1.70158)\n\n    @staticmethod\n    def out_back(progress):\n        '''.. image:: images/anim_out_back.png\n        '''\n        p = progress - 1.0\n        return p * p * ((1.70158 + 1) * p + 1.70158) + 1.0\n\n    @staticmethod\n    def in_out_back(progress):\n        '''.. image:: images/anim_in_out_back.png\n        '''\n        p = progress * 2.\n        s = 1.70158 * 1.525\n        if p < 1:\n            return 0.5 * (p * p * ((s + 1.0) * p - s))\n        p -= 2.0\n        return 0.5 * (p * p * ((s + 1.0) * p + s) + 2.0)\n\n    @staticmethod\n    def _out_bounce_internal(t, d):\n        p = t / d\n        if p < (1.0 / 2.75):\n            return 7.5625 * p * p\n        elif p < (2.0 / 2.75):\n            p -= (1.5 / 2.75)\n            return 7.5625 * p * p + .75\n        elif p < (2.5 / 2.75):\n            p -= (2.25 / 2.75)\n            return 7.5625 * p * p + .9375\n        else:\n            p -= (2.625 / 2.75)\n            return 7.5625 * p * p + .984375\n\n    @staticmethod\n    def _in_bounce_internal(t, d):\n        return 1.0 - AnimationTransition._out_bounce_internal(d - t, d)\n\n    @staticmethod\n    def in_bounce(progress):\n        '''.. image:: images/anim_in_bounce.png\n        '''\n        return AnimationTransition._in_bounce_internal(progress, 1.)\n\n    @staticmethod\n    def out_bounce(progress):\n        '''.. image:: images/anim_out_bounce.png\n        '''\n        return AnimationTransition._out_bounce_internal(progress, 1.)\n\n    @staticmethod\n    def in_out_bounce(progress):\n        '''.. image:: images/anim_in_out_bounce.png\n        '''\n        p = progress * 2.\n        if p < 1.:\n            return AnimationTransition._in_bounce_internal(p, 1.) * .5\n        return AnimationTransition._out_bounce_internal(p - 1., 1.) * .5 + .5\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/app.py",
    "content": "'''\nApplication\n===========\n\nThe :class:`App` class is the base for creating Kivy applications.\nThink of it as your main entry point into the Kivy run loop. In most\ncases, you subclass this class and make your own app. You create an\ninstance of your specific app class and then, when you are ready to\nstart the application's life cycle, you call your instance's\n:meth:`App.run` method.\n\n\nCreating an Application\n-----------------------\n\nMethod using build() override\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTo initialize your app with a widget tree, override the :meth:`~App.build`\nmethod in your app class and return the widget tree you constructed.\n\nHere's an example of a very simple application that just shows a button:\n\n.. include:: ../../examples/application/app_with_build.py\n   :literal:\n\nThe file is also available in the examples folder at\n:file:`kivy/examples/application/app_with_build.py`.\n\nHere, no widget tree was constructed (or if you will, a tree with only\nthe root node).\n\n\nMethod using kv file\n~~~~~~~~~~~~~~~~~~~~\n\nYou can also use the :doc:`api-kivy.lang` for creating applications. The\n.kv can contain rules and root widget definitions at the same time. Here\nis the same example as the Button one in a kv file.\n\nContents of 'test.kv':\n\n.. include:: ../../examples/application/test.kv\n   :literal:\n\nContents of 'main.py':\n\n.. include:: ../../examples/application/app_with_kv.py\n   :literal:\n\nSee :file:`kivy/examples/application/app_with_kv.py`.\n\nThe relation between main.py and test.kv is explained in :meth:`App.load_kv`.\n\n\nApplication configuration\n-------------------------\n\n.. versionadded:: 1.0.7\n\nUse the configuration file\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nYour application might want to have its own configuration file. The\n:class:`App` is able to handle an INI file automatically. You add your\nsection/key/value in the :meth:`App.build_config` method by using the `config`\nparameter (which is an instance of :class:`~kivy.config.ConfigParser`)::\n\n    class TestApp(App):\n        def build_config(self, config):\n            config.setdefaults('section1', {\n                'key1': 'value1',\n                'key2': '42'\n            })\n\nAs soon as you add one section in the config, a file is created on the\ndisk and named from the mangled name of your class. \"TestApp\" will give\na config file-name \"test.ini\" with the content::\n\n    [section1]\n    key1 = value1\n    key2 = 42\n\nThe \"test.ini\" will be automatically loaded at runtime and you can access the\nconfiguration in your :meth:`App.build` method::\n\n    class TestApp(App):\n        def build_config(self, config):\n            config.setdefaults('section1', {\n                'key1': 'value1',\n                'key2': '42'\n            })\n\n        def build(self):\n            config = self.config\n            return Label(text='key1 is %s and key2 is %d' % (\n                config.get('section1', 'key1'),\n                config.getint('section1', 'key2')))\n\nCreate a settings panel\n~~~~~~~~~~~~~~~~~~~~~~~\n\nYour application can have a settings panel to let your user configure some of\nyour config tokens. Here is an example done in the KinectViewer example\n(available in the examples directory):\n\n    .. image:: images/app-settings.jpg\n        :align: center\n\nYou can add your own panels of settings by extending\nthe :meth:`App.build_settings` method.\nCheck the :class:`~kivy.uix.settings.Settings` about how to create a panel,\nbecause you need a JSON file / data first.\n\nLet's take as an example the previous snippet of TestApp with custom\nconfig. We could create a JSON like this::\n\n    [\n        { \"type\": \"title\",\n          \"title\": \"Test application\" },\n\n        { \"type\": \"options\",\n          \"title\": \"My first key\",\n          \"desc\": \"Description of my first key\",\n          \"section\": \"section1\",\n          \"key\": \"key1\",\n          \"options\": [\"value1\", \"value2\", \"another value\"] },\n\n        { \"type\": \"numeric\",\n          \"title\": \"My second key\",\n          \"desc\": \"Description of my second key\",\n          \"section\": \"section1\",\n          \"key\": \"key2\" }\n    ]\n\nThen, we can create a panel using this JSON to automatically create all the\noptions and link them to our :attr:`App.config` ConfigParser instance::\n\n    class TestApp(App):\n        # ...\n        def build_settings(self, settings):\n            jsondata = \"\"\"... put the json data here ...\"\"\"\n            settings.add_json_panel('Test application',\n                self.config, data=jsondata)\n\nThat's all! Now you can press F1 (default keystroke) to toggle the\nsettings panel or press the \"settings\" key on your android device. You\ncan manually call :meth:`App.open_settings` and\n:meth:`App.close_settings` if you want to handle this manually. Every\nchange in the panel is automatically saved in the config file.\n\nYou can also use :meth:`App.build_settings` to modify properties of\nthe settings panel. For instance, the default panel has a sidebar for\nswitching between json panels whose width defaults to 200dp. If you'd\nprefer this to be narrower, you could add::\n\n    settings.interface.menu.width = dp(100)\n\nto your :meth:`build_settings` method.\n\nYou might want to know when a config value has been changed by the\nuser in order to adapt or reload your UI. You can then overload the\n:meth:`on_config_change` method::\n\n    class TestApp(App):\n        # ...\n        def on_config_change(self, config, section, key, value):\n            if config is self.config:\n                token = (section, key)\n                if token == ('section1', 'key1'):\n                    print('Our key1 have been changed to', value)\n                elif token == ('section1', 'key2'):\n                    print('Our key2 have been changed to', value)\n\nThe Kivy configuration panel is added by default to the settings\ninstance. If you don't want this panel, you can declare your Application as\nfollows::\n\n    class TestApp(App):\n        use_kivy_settings = False\n        # ...\n\nThis only removes the Kivy panel but does not stop the settings instance\nfrom appearing. If you want to prevent the settings instance from appearing\naltogether, you can do this::\n\n    class TestApp(App):\n        def open_settings(self, *largs):\n            pass\n\nProfiling with on_start and on_stop\n-----------------------------------\n\nIt is often useful to profile python code in order to discover locations to\noptimise. The standard library profilers\n(http://docs.python.org/2/library/profile.html) provides multiple options for\nprofiling code. For profiling the entire program, the natural\napproaches of using profile as a module or profile's run method does not work\nwith Kivy. It is however, possible to use :meth:`App.on_start` and\n:meth:`App.on_stop` methods::\n\n    import cProfile\n\n    class MyApp(App):\n        def on_start(self):\n            self.profile = cProfile.Profile()\n            self.profile.enable()\n\n        def on_stop(self):\n            self.profile.disable()\n            self.profile.dump_stats('myapp.profile')\n\nThis will create a file called `myapp.profile` when you exit your app.\n\nCustomising layout\n------------------\n\nYou can choose different settings widget layouts by setting\n:attr:`App.settings_cls`. By default, this is a\n:class:`~kivy.uix.settings.Settings` class which provides the pictured\nsidebar layout, but you could set it to any of the other layouts\nprovided in :mod:`kivy.uix.settings` or create your own. See the\nmodule documentation for :mod:`kivy.uix.settings` for more\ninformation.\n\nYou can customise how the settings panel is displayed by\noverriding :meth:`App.display_settings` which is called before\ndisplaying the settings panel on the screen. By default, it\nsimply draws the panel on top of the window, but you could modify it\nto (for instance) show the settings in a\n:class:`~kivy.uix.popup.Popup` or add it to your app's\n:class:`~kivy.uix.screenmanager.ScreenManager` if you are using\none. If you do so, you should also modify :meth:`App.close_settings`\nto exit the panel appropriately. For instance, to have the settings\npanel appear in a popup you can do::\n\n    def display_settings(self, settings):\n        try:\n            p = self.settings_popup\n        except AttributeError:\n            self.settings_popup = Popup(content=settings,\n                                        title='Settings',\n                                        size_hint=(0.8, 0.8))\n            p = self.settings_popup\n        if p.content is not settings:\n            p.content = settings\n        p.open()\n\n    def close_settings(self, *args):\n        try:\n            p = self.settings_popup\n            p.dismiss()\n        except AttributeError:\n            pass # Settings popup doesn't exist\n\nFinally, if you want to replace the current settings panel widget, you\ncan remove the internal references to it using\n:meth:`App.destroy_settings`. If you have modified\n:meth:`App.display_settings`, you should be careful to detect if the\nsettings panel has been replaced.\n\nPause mode\n----------\n\n.. versionadded:: 1.1.0\n\nOn tablets and phones, the user can switch at any moment to another\napplication. By default, your application will close and the\n:meth:`App.on_stop` event will be fired.\n\nIf you support Pause mode, when switching to another application, your\napplication will wait indefinitely until the user\nswitches back to your application. There is an issue with OpenGL on Android\ndevices: it is not guaranteed that the OpenGL ES Context will be restored when\nyour app resumes. The mechanism for restoring all the OpenGL data is not yet\nimplemented in Kivy.\n\nThe currently implemented Pause mechanism is:\n\n    #. Kivy checks every frame if Pause mode is activated by the Operating\n       System due to the user switching to another application, a phone\n       shutdown or any other reason.\n    #. :meth:`App.on_pause` is called:\n    #. If False is returned (default case), then :meth:`App.on_stop` is\n       called.\n    #. Otherwise the application will sleep until the OS resumes our App\n    #. When the app is resumed, :meth:`App.on_resume` is called.\n    #. If our app memory has been reclaimed by the OS, then nothing will be\n       called.\n\nHere is a simple example of how on_pause() should be used::\n\n   class TestApp(App):\n\n      def on_pause(self):\n         # Here you can save data if needed\n         return True\n\n      def on_resume(self):\n         # Here you can check if any data needs replacing (usually nothing)\n         pass\n\n.. warning::\n\n    Both `on_pause` and `on_stop` must save important data because after\n    `on_pause` is called, `on_resume` may not be called at all.\n\n'''\n\n__all__ = ('App', )\n\nimport os\nfrom inspect import getfile\nfrom os.path import dirname, join, exists, sep, expanduser, isfile\nfrom kivy.config import ConfigParser\nfrom kivy.base import runTouchApp, stopTouchApp\nfrom kivy.compat import string_types\nfrom kivy.factory import Factory\nfrom kivy.logger import Logger\nfrom kivy.event import EventDispatcher\nfrom kivy.lang import Builder\nfrom kivy.resources import resource_find\nfrom kivy.utils import platform as core_platform\nfrom kivy.uix.widget import Widget\nfrom kivy.properties import ObjectProperty, StringProperty\n\n\nplatform = core_platform\n\n\nclass App(EventDispatcher):\n    ''' Application class, see module documentation for more information.\n\n    :Events:\n        `on_start`:\n            Fired when the application is being started (before the\n            :func:`~kivy.base.runTouchApp` call.\n        `on_stop`:\n            Fired when the application stops.\n        `on_pause`:\n            Fired when the application is paused by the OS.\n        `on_resume`:\n            Fired when the application is resumed from pause by the OS. Beware:\n            you have no guarantee that this event will be fired after the\n            `on_pause` event has been called.\n\n    .. versionchanged:: 1.7.0\n        Parameter `kv_file` added.\n\n    .. versionchanged:: 1.8.0\n        Parameters `kv_file` and `kv_directory` are now properties of App.\n    '''\n\n    title = StringProperty(None)\n    '''\n    Title of your application. You can set this as follows::\n\n        class MyApp(App):\n            def build(self):\n                self.title = 'Hello world'\n\n    .. versionadded:: 1.0.5\n\n    .. versionchanged:: 1.8.0\n        `title` is now a :class:`~kivy.properties.StringProperty`. Don't set the\n        title in the class as previously stated in the documentation.\n\n    .. note::\n\n        For Kivy < 1.8.0, you can set this as follows::\n\n            class MyApp(App):\n                title = 'Custom title'\n\n        If you want to dynamically change the title, you can do::\n\n            from kivy.base import EventLoop\n            EventLoop.window.title = 'New title'\n\n    '''\n\n    icon = StringProperty(None)\n    '''Icon of your application.\n    The icon can be located in the same directory as your main file. You can set\n    this as follows::\n\n        class MyApp(App):\n            def build(self):\n                self.icon = 'myicon.png'\n\n    .. versionadded:: 1.0.5\n\n    .. versionchanged:: 1.8.0\n        `icon` is now a :class:`~kivy.properties.StringProperty`. Don't set the\n        icon in the class as previously stated in the documentation.\n\n    .. note::\n\n        For Kivy prior to 1.8.0, you need to set this as follows::\n\n            class MyApp(App):\n                icon = 'customicon.png'\n\n         Recommended 256x256 or 1024x1024? for GNU/Linux and Mac OSX\n         32x32 for Windows7 or less. <= 256x256 for windows 8\n         256x256 does work (on Windows 8 at least), but is scaled\n         down and doesn't look as good as a 32x32 icon.\n    '''\n\n    use_kivy_settings = True\n    '''.. versionadded:: 1.0.7\n\n    If True, the application settings will also include the Kivy settings. If\n    you don't want the user to change any kivy settings from your settings UI,\n    change this to False.\n    '''\n\n    settings_cls = ObjectProperty(None)\n    '''.. versionadded:: 1.8.0\n\n    The class used to construct the settings panel and\n    the instance passed to :meth:`build_config`. You should\n    use either :class:`~kivy.uix.settings.Settings` or one of the provided\n    subclasses with different layouts\n    (:class:`~kivy.uix.settings.SettingsWithSidebar`,\n    :class:`~kivy.uix.settings.SettingsWithSpinner`,\n    :class:`~kivy.uix.settings.SettingsWithTabbedPanel`,\n    :class:`~kivy.uix.settings.SettingsWithNoMenu`). You can also create your\n    own Settings subclass. See the documentation\n    of :mod:`~kivy.uix.settings.Settings` for more information.\n\n    :attr:`~App.settings_cls` is an :class:`~kivy.properties.ObjectProperty`\n    and defaults to :class:`~kivy.uix.settings.SettingsWithSpinner` which\n    displays settings panels with a spinner to switch between them. If you set a\n    string, the :class:`~kivy.factory.Factory` will be used to resolve the\n    class.\n\n    '''\n\n    kv_directory = StringProperty(None)\n    '''Path of the directory where application kv is stored, defaults to None\n\n    .. versionadded:: 1.8.0\n\n    If a kv_directory is set, it will be used to get the initial kv file. By\n    default, the file is assumed to be in the same directory as the current App\n    definition file.\n    '''\n\n    kv_file = StringProperty(None)\n    '''Filename of the Kv file to load, defaults to None.\n\n    .. versionadded:: 1.8.0\n\n    If a kv_file is set, it will be loaded when the application starts. The\n    loading of the \"default\" kv file will be prevented.\n    '''\n\n    # Return the current running App instance\n    _running_app = None\n\n    __events__ = ('on_start', 'on_stop', 'on_pause', 'on_resume')\n\n    def __init__(self, **kwargs):\n        App._running_app = self\n        self._app_directory = None\n        self._app_name = None\n        self._app_settings = None\n        self._app_window = None\n        super(App, self).__init__(**kwargs)\n        self.built = False\n\n        #: Options passed to the __init__ of the App\n        self.options = kwargs\n\n        #: Returns an instance of the :class:`~kivy.config.ConfigParser` for\n        #: the application configuration. You can use this to query some config\n        #: tokens in the :meth:`build` method.\n        self.config = None\n\n        #: The *root* widget returned by the :meth:`build` method or by the\n        #: :meth:`load_kv` method if the kv file contains a root widget.\n        self.root = None\n\n    def build(self):\n        '''Initializes the application; it will be called only once.\n        If this method returns a widget (tree), it will be used as the root\n        widget and added to the window.\n\n        :return:\n            None or a root :class:`~kivy.uix.widget.Widget` instance\n            if no self.root exists.'''\n\n        if not self.root:\n            return Widget()\n\n    def build_config(self, config):\n        '''.. versionadded:: 1.0.7\n\n        This method is called before the application is initialized to\n        construct your :class:`~kivy.config.ConfigParser` object. This\n        is where you can put any default section / key / value for your\n        config. If anything is set, the configuration will be\n        automatically saved in the file returned by\n        :meth:`get_application_config`.\n\n        :Parameters:\n            `config`: :class:`~kivy.config.ConfigParser`\n                Use this to add default section / key / value items\n\n        '''\n\n    def build_settings(self, settings):\n        '''.. versionadded:: 1.0.7\n\n        This method is called when the user (or you) want to show the\n        application settings. It is called once when the settings panel\n        is first opened, after which the panel is cached. It may be\n        called again if the cached settings panel is removed by\n        :meth:`destroy_settings`.\n\n        You can use this method to add settings panels and to\n        customise the settings widget e.g. by changing the sidebar\n        width. See the module documentation for full details.\n\n        :Parameters:\n            `settings`: :class:`~kivy.uix.settings.Settings`\n                Settings instance for adding panels\n\n        '''\n\n    def load_kv(self, filename=None):\n        '''This method is invoked the first time the app is being run if no\n        widget tree has been constructed before for this app.\n        This method then looks for a matching kv file in the same directory as\n        the file that contains the application class.\n\n        For example, say you have a file named main.py that contains::\n\n            class ShowcaseApp(App):\n                pass\n\n        This method will search for a file named `showcase.kv` in\n        the directory that contains main.py. The name of the kv file has to be\n        the lowercase name of the class, without the 'App' postfix at the end\n        if it exists.\n\n        You can define rules and a root widget in your kv file::\n\n            <ClassName>: # this is a rule\n                ...\n\n            ClassName: # this is a root widget\n                ...\n\n        There must be only one root widget. See the :doc:`api-kivy.lang`\n        documentation for more information on how to create kv files. If your\n        kv file contains a root widget, it will be used as self.root, the root\n        widget for the application.\n\n        .. note::\n\n            This function is called from :meth:`run`, therefore, any widget\n            whose styling is defined in this kv file and is created before\n            :meth:`run` is called (e.g. in `__init__`), won't have its styling\n            applied. Note that :meth:`build` is called after :attr:`load_kv`\n            has been called.\n        '''\n        # Detect filename automatically if it was not specified.\n        if filename:\n            filename = resource_find(filename)\n        else:\n            try:\n                default_kv_directory = dirname(getfile(self.__class__))\n                if default_kv_directory == '':\n                    default_kv_directory = '.'\n            except TypeError:\n                # if it's a builtin module.. use the current dir.\n                default_kv_directory = '.'\n\n            kv_directory = self.kv_directory or default_kv_directory\n            clsname = self.__class__.__name__.lower()\n            if (clsname.endswith('app') and\n                    not isfile(join(kv_directory, '%s.kv' % clsname))):\n                clsname = clsname[:-3]\n            filename = join(kv_directory, '%s.kv' % clsname)\n\n        # Load KV file\n        Logger.debug('App: Loading kv <{0}>'.format(filename))\n        rfilename = resource_find(filename)\n        if rfilename is None or not exists(rfilename):\n            Logger.debug('App: kv <%s> not found' % filename)\n            return False\n        root = Builder.load_file(rfilename)\n        if root:\n            self.root = root\n        return True\n\n    def get_application_name(self):\n        '''Return the name of the application.\n        '''\n        if self.title is not None:\n            return self.title\n        clsname = self.__class__.__name__\n        if clsname.endswith('App'):\n            clsname = clsname[:-3]\n        return clsname\n\n    def get_application_icon(self):\n        '''Return the icon of the application.\n        '''\n        if not resource_find(self.icon):\n            return ''\n        else:\n            return resource_find(self.icon)\n\n    def get_application_config(self, defaultpath='%(appdir)s/%(appname)s.ini'):\n        '''.. versionadded:: 1.0.7\n\n        .. versionchanged:: 1.4.0\n            Customized the default path for iOS and Android platforms. Added a\n            defaultpath parameter for desktop OS's (not applicable to iOS\n            and Android.)\n\n        Return the filename of your application configuration. Depending\n        on the platform, the application file will be stored in\n        different locations:\n\n            - on iOS: <appdir>/Documents/.<appname>.ini\n            - on Android: /sdcard/.<appname>.ini\n            - otherwise: <appdir>/<appname>.ini\n\n        When you are distributing your application on Desktops, please\n        note that if the application is meant to be installed\n        system-wide, the user might not have write-access to the\n        application directory. If you want to store user settings, you\n        should overload this method and change the default behavior to\n        save the configuration file in the user directory.::\n\n            class TestApp(App):\n                def get_application_config(self):\n                    return super(TestApp, self).get_application_config(\n                        '~/.%(appname)s.ini')\n\n        Some notes:\n\n        - The tilda '~' will be expanded to the user directory.\n        - %(appdir)s will be replaced with the application :attr:`directory`\n        - %(appname)s will be replaced with the application :attr:`name`\n        '''\n\n        if platform == 'android':\n            defaultpath = '/sdcard/.%(appname)s.ini'\n        elif platform == 'ios':\n            defaultpath = '~/Documents/%(appname)s.ini'\n        elif platform == 'win':\n            defaultpath = defaultpath.replace('/', sep)\n        return expanduser(defaultpath) % {\n            'appname': self.name, 'appdir': self.directory}\n\n    @property\n    def root_window(self):\n        '''.. versionadded:: 1.9.0\n\n        Returns the root window instance used by :meth:`run`.\n        '''\n        return self._app_window\n\n    def load_config(self):\n        '''(internal) This function is used for returning a ConfigParser with\n        the application configuration. It's doing 3 things:\n\n            #. Creating an instance of a ConfigParser\n            #. Loading the default configuration by calling\n               :meth:`build_config`, then\n            #. If it exists, it loads the application configuration file,\n               otherwise it creates one.\n\n        :return:\n            :class:`~kivy.config.ConfigParser` instance\n        '''\n        try:\n            config = ConfigParser.get_configparser('app')\n        except KeyError:\n            config = None\n        if config is None:\n            config = ConfigParser(name='app')\n        self.config = config\n        self.build_config(config)\n        # if no sections are created, that's mean the user don't have\n        # configuration.\n        if len(config.sections()) == 0:\n            return\n        # ok, the user have some sections, read the default file if exist\n        # or write it !\n        filename = self.get_application_config()\n        if filename is None:\n            return config\n        Logger.debug('App: Loading configuration <{0}>'.format(filename))\n        if exists(filename):\n            try:\n                config.read(filename)\n            except:\n                Logger.error('App: Corrupted config file, ignored.')\n                config.name = ''\n                try:\n                    config = ConfigParser.get_configparser('app')\n                except KeyError:\n                    config = None\n                if config is None:\n                    config = ConfigParser(name='app')\n                self.config = config\n                self.build_config(config)\n                pass\n        else:\n            Logger.debug('App: First configuration, create <{0}>'.format(\n                filename))\n            config.filename = filename\n            config.write()\n        return config\n\n    @property\n    def directory(self):\n        '''.. versionadded:: 1.0.7\n\n        Return the directory where the application lives.\n        '''\n        if self._app_directory is None:\n            try:\n                self._app_directory = dirname(getfile(self.__class__))\n                if self._app_directory == '':\n                    self._app_directory = '.'\n            except TypeError:\n                # if it's a builtin module.. use the current dir.\n                self._app_directory = '.'\n        return self._app_directory\n\n    @property\n    def user_data_dir(self):\n        '''\n        .. versionadded:: 1.7.0\n\n        Returns the path to the directory in the users file system which the\n        application can use to store additional data.\n\n        Different platforms have different conventions with regards to where\n        the user can store data such as preferences, saved games and settings.\n        This function implements these conventions. The <app_name> directory\n        is created when the property is called, unless it already exists.\n\n        On iOS, `~/Documents<app_name>` is returned (which is inside the\n        app's sandbox).\n\n        On Android, `/sdcard/<app_name>` is returned.\n\n        On Windows, `%APPDATA%/<app_name>` is returned.\n\n        On Mac OSX, `~/Library/Application Support/<app_name>` is returned.\n\n        On Linux, `$XDG_CONFIG_HOME/<app_name>` is returned.\n        '''\n        data_dir = \"\"\n        if platform == 'ios':\n            data_dir = join('~/Documents', self.name)\n        elif platform == 'android':\n            data_dir = join('/sdcard', self.name)\n        elif platform == 'win':\n            data_dir = os.path.join(os.environ['APPDATA'], self.name)\n        elif platform == 'macosx':\n            data_dir = '~/Library/Application Support/{}'.format(self.name)\n        else:  # _platform == 'linux' or anything else...:\n            data_dir = os.environ.get('XDG_CONFIG_HOME', '~/.config')\n            data_dir = join(data_dir, self.name)\n        data_dir = expanduser(data_dir)\n        if not exists(data_dir):\n            os.mkdir(data_dir)\n        return data_dir\n\n    @property\n    def name(self):\n        '''.. versionadded:: 1.0.7\n\n        Return the name of the application based on the class name.\n        '''\n        if self._app_name is None:\n            clsname = self.__class__.__name__\n            if clsname.endswith('App'):\n                clsname = clsname[:-3]\n            self._app_name = clsname.lower()\n        return self._app_name\n\n    def run(self):\n        '''Launches the app in standalone mode.\n        '''\n        if not self.built:\n            self.load_config()\n            self.load_kv(filename=self.kv_file)\n            root = self.build()\n            if root:\n                self.root = root\n        if self.root:\n            if not isinstance(self.root, Widget):\n                Logger.critical('App.root must be an _instance_ of Widget')\n                raise Exception('Invalid instance in App.root')\n            from kivy.core.window import Window\n            Window.add_widget(self.root)\n\n        # Check if the window is already created\n        from kivy.base import EventLoop\n        window = EventLoop.window\n        if window:\n            self._app_window = window\n            window.set_title(self.get_application_name())\n            icon = self.get_application_icon()\n            if icon:\n                window.set_icon(icon)\n            self._install_settings_keys(window)\n        else:\n            Logger.critical(\"Application: No window is created.\"\n                            \" Terminating application run.\")\n            return\n\n        self.dispatch('on_start')\n        runTouchApp()\n        self.stop()\n\n    def stop(self, *largs):\n        '''Stop the application.\n\n        If you use this method, the whole application will stop by issuing\n        a call to :func:`~kivy.base.stopTouchApp`.\n        '''\n        self.dispatch('on_stop')\n        stopTouchApp()\n\n        # Clear the window children\n        for child in self._app_window.children:\n            self._app_window.remove_widget(child)\n\n    def on_start(self):\n        '''Event handler for the `on_start` event which is fired after\n        initialization (after build() has been called) but before the\n        application has started running.\n        '''\n        pass\n\n    def on_stop(self):\n        '''Event handler for the `on_stop` event which is fired when the\n        application has finished running (i.e. the window is about to be\n        closed).\n        '''\n        pass\n\n    def on_pause(self):\n        '''Event handler called when Pause mode is requested. You should\n        return True if your app can go into Pause mode, otherwise\n        return False and your application will be stopped (the default).\n\n        You cannot control when the application is going to go into this mode.\n        It's determined by the Operating System and mostly used for mobile\n        devices (android/ios) and for resizing.\n\n        The default return value is False.\n\n        .. versionadded:: 1.1.0\n        '''\n        return False\n\n    def on_resume(self):\n        '''Event handler called when your application is resuming from\n        the Pause mode.\n\n        .. versionadded:: 1.1.0\n\n        .. warning::\n\n            When resuming, the OpenGL Context might have been damaged / freed.\n            This is where you can reconstruct some of your OpenGL state\n            e.g. FBO content.\n        '''\n        pass\n\n    @staticmethod\n    def get_running_app():\n        '''Return the currently running application instance.\n\n        .. versionadded:: 1.1.0\n        '''\n        return App._running_app\n\n    def on_config_change(self, config, section, key, value):\n        '''Event handler fired when a configuration token has been changed by\n        the settings page.\n        '''\n        pass\n\n    def open_settings(self, *largs):\n        '''Open the application settings panel. It will be created the very\n        first time, or recreated if the previously cached panel has been\n        removed by :meth:`destroy_settings`. The settings panel will be\n        displayed with the\n        :meth:`display_settings` method, which by default adds the\n        settings panel to the Window attached to your application. You\n        should override that method if you want to display the\n        settings panel differently.\n\n        :return:\n            True if the settings has been opened.\n\n        '''\n        if self._app_settings is None:\n            self._app_settings = self.create_settings()\n        displayed = self.display_settings(self._app_settings)\n        if displayed:\n            return True\n        return False\n\n    def display_settings(self, settings):\n        '''.. versionadded:: 1.8.0\n\n        Display the settings panel. By default, the panel is drawn directly\n        on top of the window. You can define other behaviour by overriding\n        this method, such as adding it to a ScreenManager or Popup.\n\n        You should return True if the display is successful, otherwise False.\n\n        :Parameters:\n            `settings`: :class:`~kivy.uix.settings.Settings`\n                You can modify this object in order to modify the settings\n                display.\n\n        '''\n        win = self._app_window\n        if not win:\n            raise Exception('No windows are set on the application, you cannot'\n                            ' open settings yet.')\n        if settings not in win.children:\n            win.add_widget(settings)\n            return True\n        return False\n\n    def close_settings(self, *largs):\n        '''Close the previously opened settings panel.\n\n        :return:\n            True if the settings has been closed.\n        '''\n        win = self._app_window\n        settings = self._app_settings\n        if win is None or settings is None:\n            return\n        if settings in win.children:\n            win.remove_widget(settings)\n            return True\n        return False\n\n    def create_settings(self):\n        '''Create the settings panel. This method will normally\n        be called only one time per\n        application life-time and the result is cached internally,\n        but it may be called again if the cached panel is removed\n        by :meth:`destroy_settings`.\n\n        By default, it will build a settings panel according to\n        :attr:`settings_cls`, call :meth:`build_settings`, add a Kivy panel if\n        :attr:`use_kivy_settings` is True, and bind to\n        on_close/on_config_change.\n\n        If you want to plug your own way of doing settings, without the Kivy\n        panel or close/config change events, this is the method you want to\n        overload.\n\n        .. versionadded:: 1.8.0\n        '''\n        if self.settings_cls is None:\n            from kivy.uix.settings import SettingsWithSpinner\n            self.settings_cls = SettingsWithSpinner\n        elif isinstance(self.settings_cls, string_types):\n            self.settings_cls = Factory.get(self.settings_cls)\n        s = self.settings_cls()\n        self.build_settings(s)\n        if self.use_kivy_settings:\n            s.add_kivy_panel()\n        s.bind(on_close=self.close_settings,\n               on_config_change=self._on_config_change)\n        return s\n\n    def destroy_settings(self):\n        '''.. versionadded:: 1.8.0\n\n        Dereferences the current settings panel if one\n        exists. This means that when :meth:`App.open_settings` is next\n        run, a new panel will be created and displayed. It doesn't\n        affect any of the contents of the panel, but lets you (for\n        instance) refresh the settings panel layout if you have\n        changed the settings widget in response to a screen size\n        change.\n\n        If you have modified :meth:`~App.open_settings` or\n        :meth:`~App.display_settings`, you should be careful to\n        correctly detect if the previous settings widget has been\n        destroyed.\n\n        '''\n        if self._app_settings is not None:\n            self._app_settings = None\n\n    #\n    # privates\n    #\n\n    def _on_config_change(self, *largs):\n        self.on_config_change(*largs[1:])\n\n    def _install_settings_keys(self, window):\n        window.bind(on_keyboard=self._on_keyboard_settings)\n\n    def _on_keyboard_settings(self, window, *largs):\n        key = largs[0]\n        setting_key = 282  # F1\n\n        # android hack, if settings key is pygame K_MENU\n        if platform == 'android':\n            import pygame\n            setting_key = pygame.K_MENU\n\n        if key == setting_key:\n            # toggle settings panel\n            if not self.open_settings():\n                self.close_settings()\n            return True\n        if key == 27:\n            return self.close_settings()\n\n    def on_title(self, instance, title):\n        if self._app_window:\n            self._app_window.set_title(title)\n\n    def on_icon(self, instance, icon):\n        if self._app_window:\n            self._app_window.set_icon(self.get_application_icon())\n\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/atlas.py",
    "content": "'''\nAtlas\n=====\n\n.. versionadded:: 1.1.0\n\nAtlas manages texture atlases: packing multiple textures into\none. With it, you reduce the number of images loaded and speedup the\napplication loading. This module contains both the Atlas class and command line\nprocessing for creating an atlas from a set of individual PNG files. The\ncommand line section requires the Pillow library, or the defunct Python Imaging\nLibrary (PIL), to be installed.\n\nAn Atlas is composed of files:\n    - a json file (.atlas) that contains the image file names and texture\n      locations of the atlas.\n    - one or multiple image files containing textures referenced by the .atlas\n      file.\n\nDefinition of .atlas files\n--------------------------\n\nA file with ``<basename>.atlas`` is a json file formatted like this::\n\n    {\n        \"<basename>-<index>.png\": {\n            \"id1\": [ <x>, <y>, <width>, <height> ],\n            \"id2\": [ <x>, <y>, <width>, <height> ],\n            # ...\n        },\n        # ...\n    }\n\nExample from the Kivy ``data/images/defaulttheme.atlas``::\n\n    {\n        \"defaulttheme-0.png\": {\n            \"progressbar_background\": [431, 224, 59, 24],\n            \"image-missing\": [253, 344, 48, 48],\n            \"filechooser_selected\": [1, 207, 118, 118],\n            \"bubble_btn\": [83, 174, 32, 32],\n            # ... and more ...\n        }\n    }\n\nIn this example, \"defaulttheme-0.png\" is a large image, with the pixels in the\nrectangle from (431, 224) to (431 + 59, 224 + 24) usable as\n``atlas://data/images/defaulttheme/progressbar_background`` in\nany image parameter.\n\nHow to create an Atlas\n----------------------\n\n.. warning::\n\n    The atlas creation requires the Pillow library (or the defunct Imaging/PIL\n    library). This requirement will be removed in the future when the Kivy core\n    Image is able to support loading, blitting, and saving operations.\n\nYou can directly use this module to create atlas files with this command::\n\n    $ python -m kivy.atlas <basename> <size> <list of images...>\n\n\nLet's say you have a list of images that you want to put into an Atlas. The\ndirectory is named ``images`` with lots of 64x64 png files inside::\n\n    $ ls\n    images\n    $ cd images\n    $ ls\n    bubble.png bubble-red.png button.png button-down.png\n\nYou can combine all the png's into one and generate the atlas file with::\n\n    $ python -m kivy.atlas myatlas 256x256 *.png\n    Atlas created at myatlas.atlas\n    1 image has been created\n    $ ls\n    bubble.png bubble-red.png button.png button-down.png myatlas.atlas\n    myatlas-0.png\n\nAs you can see, we get 2 new files: ``myatlas.atlas`` and ``myatlas-0.png``.\n``myatlas-0.png`` is a new 256x256 .png composed of all your images.\n\n.. note::\n\n    When using this script, the ids referenced in the atlas are the base names\n    of the images without the extension. So, if you are going to name a file\n    ``../images/button.png``, the id for this image will be ``button``.\n\n    If you need path information included, you should include ``use_path`` as\n    follows::\n\n        $ python -m kivy.atlas use_path myatlas 256 *.png\n\n    In which case the id for ``../images/button.png`` will be ``images_button``\n\n\nHow to use an Atlas\n-------------------\n\nUsually, you would use the atlas as follows::\n\n    a = Button(background_normal='images/button.png',\n               background_down='images/button_down.png')\n\nIn our previous example, we have created the atlas containing both images and\nput them in ``images/myatlas.atlas``. You can use url notation to reference\nthem::\n\n    atlas://path/to/myatlas/id\n    # will search for the ``path/to/myatlas.atlas`` and get the image ``id``\n\nIn our case, it would be::\n\n    atlas://images/myatlas/button\n\n.. note::\n\n    In the atlas url, there is no need to add the ``.atlas`` extension. It will\n    be automatically append to the filename.\n\nManual usage of the Atlas\n-------------------------\n\n::\n\n    >>> from kivy.atlas import Atlas\n    >>> atlas = Atlas('path/to/myatlas.atlas')\n    >>> print(atlas.textures.keys())\n    ['bubble', 'bubble-red', 'button', 'button-down']\n    >>> print(atlas['button'])\n    <kivy.graphics.texture.TextureRegion object at 0x2404d10>\n'''\n\n__all__ = ('Atlas', )\n\nimport json\nfrom os.path import basename, dirname, join, splitext\nfrom kivy.event import EventDispatcher\nfrom kivy.logger import Logger\nfrom kivy.properties import AliasProperty, DictProperty\nimport os\n\n\n# late import to prevent recursion\nCoreImage = None\n\n\nclass Atlas(EventDispatcher):\n    '''Manage texture atlas. See module documentation for more information.\n    '''\n\n    textures = DictProperty({})\n    '''List of available textures within the atlas.\n\n    :attr:`textures` is a :class:`~kivy.properties.DictProperty` and defaults\n    to {}.\n    '''\n\n    def _get_filename(self):\n        return self._filename\n\n    filename = AliasProperty(_get_filename, None)\n    '''Filename of the current Atlas.\n\n    :attr:`filename` is an :class:`~kivy.properties.AliasProperty` and defaults\n    to None.\n    '''\n\n    def __init__(self, filename):\n        self._filename = filename\n        super(Atlas, self).__init__()\n        self._load()\n\n    def __getitem__(self, key):\n        return self.textures[key]\n\n    def _load(self):\n        # late import to prevent recursive import.\n        global CoreImage\n        if CoreImage is None:\n            from kivy.core.image import Image as CoreImage\n\n        # must be a name finished by .atlas ?\n        filename = self._filename\n        assert(filename.endswith('.atlas'))\n        filename = filename.replace('/', os.sep)\n\n        Logger.debug('Atlas: Load <%s>' % filename)\n        with open(filename, 'r') as fd:\n            meta = json.load(fd)\n\n        Logger.debug('Atlas: Need to load %d images' % len(meta))\n        d = dirname(filename)\n        textures = {}\n        for subfilename, ids in meta.items():\n            subfilename = join(d, subfilename)\n            Logger.debug('Atlas: Load <%s>' % subfilename)\n\n            # load the image\n            ci = CoreImage(subfilename)\n\n            # for all the uid, load the image, get the region, and put\n            # it in our dict.\n            for meta_id, meta_coords in ids.items():\n                x, y, w, h = meta_coords\n                textures[meta_id] = ci.texture.get_region(*meta_coords)\n\n        self.textures = textures\n\n    @staticmethod\n    def create(outname, filenames, size, padding=2, use_path=False):\n        '''This method can be used to create an atlas manually from a set of\n        images.\n\n        :Parameters:\n            `outname`: str\n                Basename to use for ``.atlas`` creation and ``-<idx>.png``\n                associated images.\n            `filenames`: list\n                List of filenames to put in the atlas.\n            `size`: int or list (width, height)\n                Size of the atlas image.\n            `padding`: int, defaults to 2\n                Padding to put around each image.\n\n                Be careful. If you're using a padding < 2, you might have\n                issues with the borders of the images. Because of the OpenGL\n                linearization, it might use the pixels of the adjacent image.\n\n                If you're using a padding >= 2, we'll automatically generate a\n                \"border\" of 1px around your image. If you look at\n                the result, don't be scared if the image inside is not\n                exactly the same as yours :).\n\n            `use_path`: bool, defaults to False\n                If True, the relative path of the source png\n                file names will be included in the atlas ids rather\n                that just in the file names. Leading dots and slashes will be\n                excluded and all other slashes in the path will be replaced\n                with underscores. For example, if `use_path` is False\n                (the default) and the file name is\n                ``../data/tiles/green_grass.png``, the id will be\n                ``green_grass``. If `use_path` is True, it will be\n                ``data_tiles_green_grass``.\n\n            .. versionchanged:: 1.8.0\n                Parameter use_path added\n        '''\n        # Thanks to\n        # omnisaurusgames.com/2011/06/texture-atlas-generation-using-python/\n        # for its initial implementation.\n        try:\n            from PIL import Image\n        except ImportError:\n            Logger.critical('Atlas: Imaging/PIL are missing')\n            raise\n\n        if isinstance(size, (tuple, list)):\n            size_w, size_h = map(int, size)\n        else:\n            size_w = size_h = int(size)\n\n        # open all of the images\n        ims = list()\n        for f in filenames:\n            fp = open(f, 'rb')\n            im = Image.open(fp)\n            im.load()\n            fp.close()\n            ims.append((f, im))\n\n        # sort by image area\n        ims = sorted(ims, key=lambda im: im[1].size[0] * im[1].size[1],\n                     reverse=True)\n\n        # free boxes are empty space in our output image set\n        # the freebox tuple format is: outidx, x, y, w, h\n        freeboxes = [(0, 0, 0, size_w, size_h)]\n        numoutimages = 1\n\n        # full boxes are areas where we have placed images in the atlas\n        # the full box tuple format is: image, outidx, x, y, w, h, filename\n        fullboxes = []\n\n        # do the actual atlasing by sticking the largest images we can\n        # have into the smallest valid free boxes\n        for imageinfo in ims:\n            im = imageinfo[1]\n            imw, imh = im.size\n            imw += padding\n            imh += padding\n            if imw > size_w or imh > size_h:\n                Logger.error(\n                    'Atlas: image %s (%d by %d) is larger than the atlas size!'\n                    % (imageinfo[0], imw, imh))\n                return\n\n            inserted = False\n            while not inserted:\n                for idx, fb in enumerate(freeboxes):\n                    # find the smallest free box that will contain this image\n                    if fb[3] >= imw and fb[4] >= imh:\n                        # we found a valid spot! Remove the current\n                        # freebox, and split the leftover space into (up to)\n                        # two new freeboxes\n                        del freeboxes[idx]\n                        if fb[3] > imw:\n                            freeboxes.append((\n                                fb[0], fb[1] + imw, fb[2],\n                                fb[3] - imw, imh))\n\n                        if fb[4] > imh:\n                            freeboxes.append((\n                                fb[0], fb[1], fb[2] + imh,\n                                fb[3], fb[4] - imh))\n\n                        # keep this sorted!\n                        freeboxes = sorted(freeboxes,\n                                           key=lambda fb: fb[3] * fb[4])\n                        fullboxes.append((im,\n                                          fb[0], fb[1] + padding,\n                                          fb[2] + padding, imw - padding,\n                                          imh - padding, imageinfo[0]))\n                        inserted = True\n                        break\n\n                if not inserted:\n                    # oh crap - there isn't room in any of our free\n                    # boxes, so we have to add a new output image\n                    freeboxes.append((numoutimages, 0, 0, size_w, size_h))\n                    numoutimages += 1\n\n        # now that we've figured out where everything goes, make the output\n        # images and blit the source images to the approriate locations\n        Logger.info('Atlas: create an {0}x{1} rgba image'.format(size_w,\n                                                                 size_h))\n        outimages = [Image.new('RGBA', (size_w, size_h))\n                     for i in range(0, int(numoutimages))]\n        for fb in fullboxes:\n            x, y = fb[2], fb[3]\n            out = outimages[fb[1]]\n            out.paste(fb[0], (fb[2], fb[3]))\n            w, h = fb[0].size\n            if padding > 1:\n                out.paste(fb[0].crop((0, 0, w, 1)), (x, y - 1))\n                out.paste(fb[0].crop((0, h - 1, w, h)), (x, y + h))\n                out.paste(fb[0].crop((0, 0, 1, h)), (x - 1, y))\n                out.paste(fb[0].crop((w - 1, 0, w, h)), (x + w, y))\n\n        # save the output images\n        for idx, outimage in enumerate(outimages):\n            outimage.save('%s-%d.png' % (outname, idx))\n\n        # write out an json file that says where everything ended up\n        meta = {}\n        for fb in fullboxes:\n            fn = '%s-%d.png' % (basename(outname), fb[1])\n            if fn not in meta:\n                d = meta[fn] = {}\n            else:\n                d = meta[fn]\n\n            # fb[6] contain the filename\n            if use_path:\n                # use the path with separators replaced by _\n                # example '../data/tiles/green_grass.png' becomes\n                # 'data_tiles_green_grass'\n                uid = splitext(fb[6])[0]\n                # remove leading dots and slashes\n                uid = uid.lstrip('./\\\\')\n                # replace remaining slashes with _\n                uid = uid.replace('/', '_').replace('\\\\', '_')\n            else:\n                # for example, '../data/tiles/green_grass.png'\n                # just get only 'green_grass' as the uniq id.\n                uid = splitext(basename(fb[6]))[0]\n\n            x, y, w, h = fb[2:6]\n            d[uid] = x, size_h - y - h, w, h\n\n        outfn = '%s.atlas' % outname\n        with open(outfn, 'w') as fd:\n            json.dump(meta, fd)\n\n        return outfn, meta\n\n\nif __name__ == '__main__':\n    \"\"\" Main line program. Process command line arguments\n    to make a new atlas. \"\"\"\n\n    import sys\n    from glob import glob\n    argv = sys.argv[1:]\n    # earlier import of kivy has already called getopt to remove kivy system\n    # arguments from this line. That is all arguments up to the first '--'\n    if len(argv) < 3:\n        print('Usage: python -m kivy.atlas [-- [--use-path] '\n              '[--padding=2]] <outname> '\n              '<size|512x256> <img1.png> [<img2.png>, ...]')\n        sys.exit(1)\n\n    options = {'use_path': False}\n    while True:\n        option = argv[0]\n        if option == '--use-path':\n            options['use_path'] = True\n        elif option.startswith('--padding='):\n            options['padding'] = int(option.split('=', 1)[-1])\n        elif option[:2] == '--':\n            print('Unknown option {}'.format(option))\n            sys.exit(1)\n        else:\n            break\n        argv = argv[1:]\n\n    outname = argv[0]\n    try:\n        if 'x' in argv[1]:\n            size = map(int, argv[1].split('x', 1))\n        else:\n            size = int(argv[1])\n    except ValueError:\n        print('Error: size must be an integer or <integer>x<integer>')\n        sys.exit(1)\n\n    filenames = [fname for fnames in argv[2:] for fname in glob(fnames)]\n    ret = Atlas.create(outname, filenames, size, **options)\n    if not ret:\n        print('Error while creating atlas!')\n        sys.exit(1)\n\n    fn, meta = ret\n    print('Atlas created at', fn)\n    print('%d image%s been created' % (len(meta),\n          's have' if len(meta) > 1 else ' has'))\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/base.py",
    "content": "# pylint: disable=W0611\n'''\nKivy Base\n=========\n\nThis module contains core Kivy functionality and is not intended for end users.\nFeel free to look though it, but calling any of these methods directly may well\nresult in unpredicatable behavior.\n\nEvent loop management\n---------------------\n\n'''\n\n__all__ = (\n    'EventLoop',\n    'EventLoopBase',\n    'ExceptionHandler',\n    'ExceptionManagerBase',\n    'ExceptionManager',\n    'runTouchApp',\n    'stopTouchApp',\n)\n\nimport sys\nfrom kivy.config import Config\nfrom kivy.logger import Logger\nfrom kivy.utils import platform\nfrom kivy.clock import Clock\nfrom kivy.event import EventDispatcher\nfrom kivy.lang import Builder\nfrom kivy.context import register_context\n\n# private vars\nEventLoop = None\n\n\nclass ExceptionHandler(object):\n    '''Base handler that catches exceptions in :func:`runTouchApp`.\n    You can subclass and extend it as follows::\n\n        class E(ExceptionHandler):\n            def handle_exception(self, inst):\n                Logger.exception('Exception catched by ExceptionHandler')\n                return ExceptionManager.PASS\n\n        ExceptionManager.add_handler(E())\n\n    All exceptions will be set to PASS, and logged to the console!\n    '''\n\n    def __init__(self):\n        pass\n\n    def handle_exception(self, exception):\n        '''Handle one exception, defaults to returning\n        ExceptionManager.STOP.\n        '''\n        return ExceptionManager.RAISE\n\n\nclass ExceptionManagerBase:\n    '''ExceptionManager manages exceptions handlers.'''\n\n    RAISE = 0\n    PASS = 1\n\n    def __init__(self):\n        self.handlers = []\n        self.policy = ExceptionManagerBase.RAISE\n\n    def add_handler(self, cls):\n        '''Add a new exception handler to the stack.'''\n        if not cls in self.handlers:\n            self.handlers.append(cls)\n\n    def remove_handler(self, cls):\n        '''Remove a exception handler from the stack.'''\n        if cls in self.handlers:\n            self.handlers.remove(cls)\n\n    def handle_exception(self, inst):\n        '''Called when an exception occured in the runTouchApp() main loop.'''\n        ret = self.policy\n        for handler in self.handlers:\n            r = handler.handle_exception(inst)\n            if r == ExceptionManagerBase.PASS:\n                ret = r\n        return ret\n\n#: Instance of a :class:`ExceptionManagerBase` implementation.\nExceptionManager = register_context('ExceptionManager', ExceptionManagerBase)\n\n\nclass EventLoopBase(EventDispatcher):\n    '''Main event loop. This loop handles the updating of input and\n    dispatching events.\n    '''\n\n    __events__ = ('on_start', 'on_pause', 'on_stop')\n\n    def __init__(self):\n        super(EventLoopBase, self).__init__()\n        self.quit = False\n        self.input_events = []\n        self.postproc_modules = []\n        self.status = 'idle'\n        self.input_providers = []\n        self.input_providers_autoremove = []\n        self.event_listeners = []\n        self.window = None\n        self.me_list = []\n\n    @property\n    def touches(self):\n        '''Return the list of all touches currently in down or move states.\n        '''\n        return self.me_list\n\n    def ensure_window(self):\n        '''Ensure that we have a window.\n        '''\n        import kivy.core.window  # NOQA\n        if not self.window:\n            Logger.critical('App: Unable to get a Window, abort.')\n            sys.exit(1)\n\n    def set_window(self, window):\n        '''Set the window used for the event loop.\n        '''\n        self.window = window\n\n    def add_input_provider(self, provider, auto_remove=False):\n        '''Add a new input provider to listen for touch events.\n        '''\n        if provider not in self.input_providers:\n            self.input_providers.append(provider)\n            if auto_remove:\n                self.input_providers_autoremove.append(provider)\n\n    def remove_input_provider(self, provider):\n        '''Remove an input provider.\n        '''\n        if provider in self.input_providers:\n            self.input_providers.remove(provider)\n\n    def add_event_listener(self, listener):\n        '''Add a new event listener for getting touch events.\n        '''\n        if not listener in self.event_listeners:\n            self.event_listeners.append(listener)\n\n    def remove_event_listener(self, listener):\n        '''Remove an event listener from the list.\n        '''\n        if listener in self.event_listeners:\n            self.event_listeners.remove(listener)\n\n    def start(self):\n        '''Must be called only once before run().\n        This starts all configured input providers.'''\n        self.status = 'started'\n        self.quit = False\n        for provider in self.input_providers:\n            provider.start()\n        self.dispatch('on_start')\n\n    def close(self):\n        '''Exit from the main loop and stop all configured\n        input providers.'''\n        self.quit = True\n        self.stop()\n        self.status = 'closed'\n\n    def stop(self):\n        '''Stop all input providers and call callbacks registered using\n        EventLoop.add_stop_callback().'''\n\n        # XXX stop in reverse order that we started them!! (like push\n        # pop), very important because e.g. wm_touch and WM_PEN both\n        # store old window proc and the restore, if order is messed big\n        # problem happens, crashing badly without error\n        for provider in reversed(self.input_providers[:]):\n            provider.stop()\n            if provider in self.input_providers_autoremove:\n                self.input_providers_autoremove.remove(provider)\n                self.input_providers.remove(provider)\n\n        # ensure any restart will not break anything later.\n        self.input_events = []\n\n        self.status = 'stopped'\n        self.dispatch('on_stop')\n\n    def add_postproc_module(self, mod):\n        '''Add a postproc input module (DoubleTap, TripleTap, DeJitter\n        RetainTouch are defaults).'''\n        if mod not in self.postproc_modules:\n            self.postproc_modules.append(mod)\n\n    def remove_postproc_module(self, mod):\n        '''Remove a postproc module.'''\n        if mod in self.postproc_modules:\n            self.postproc_modules.remove(mod)\n\n    def post_dispatch_input(self, etype, me):\n        '''This function is called by dispatch_input() when we want to dispatch\n        an input event. The event is dispatched to all listeners and if\n        grabbed, it's dispatched to grabbed widgets.\n        '''\n        # update available list\n        if etype == 'begin':\n            self.me_list.append(me)\n        elif etype == 'end':\n            if me in self.me_list:\n                self.me_list.remove(me)\n\n        # dispatch to listeners\n        if not me.grab_exclusive_class:\n            for listener in self.event_listeners:\n                listener.dispatch('on_motion', etype, me)\n\n        # dispatch grabbed touch\n        me.grab_state = True\n        for _wid in me.grab_list[:]:\n\n            # it's a weakref, call it!\n            wid = _wid()\n            if wid is None:\n                # object is gone, stop.\n                me.grab_list.remove(_wid)\n                continue\n\n            root_window = wid.get_root_window()\n            if wid != root_window and root_window is not None:\n                me.push()\n                w, h = root_window.system_size\n                if platform == 'ios':\n                    w, h = root_window.size\n                kheight = root_window.keyboard_height\n                smode = root_window.softinput_mode\n                me.scale_for_screen(w, h, rotation=root_window.rotation,\n                                    smode=smode, kheight=kheight)\n                parent = wid.parent\n                # and do to_local until the widget\n                try:\n                    if parent:\n                        me.apply_transform_2d(parent.to_widget)\n                    else:\n                        me.apply_transform_2d(wid.to_widget)\n                        me.apply_transform_2d(wid.to_parent)\n                except AttributeError:\n                    # when using inner window, an app have grab the touch\n                    # but app is removed. the touch can't access\n                    # to one of the parent. (i.e, self.parent will be None)\n                    # and BAM the bug happen.\n                    me.pop()\n                    continue\n\n            me.grab_current = wid\n\n            wid._context.push()\n\n            if etype == 'begin':\n                # don't dispatch again touch in on_touch_down\n                # a down event are nearly uniq here.\n                # wid.dispatch('on_touch_down', touch)\n                pass\n            elif etype == 'update':\n                if wid._context.sandbox:\n                    with wid._context.sandbox:\n                        wid.dispatch('on_touch_move', me)\n                else:\n                    wid.dispatch('on_touch_move', me)\n\n            elif etype == 'end':\n                if wid._context.sandbox:\n                    with wid._context.sandbox:\n                        wid.dispatch('on_touch_up', me)\n                else:\n                    wid.dispatch('on_touch_up', me)\n\n            wid._context.pop()\n\n            me.grab_current = None\n\n            if wid != root_window and root_window is not None:\n                me.pop()\n        me.grab_state = False\n\n    def _dispatch_input(self, *ev):\n        # remove the save event for the touch if exist\n        if ev in self.input_events:\n            self.input_events.remove(ev)\n        self.input_events.append(ev)\n\n    def dispatch_input(self):\n        '''Called by idle() to read events from input providers, pass events to\n        postproc, and dispatch final events.\n        '''\n\n        # first, aquire input events\n        for provider in self.input_providers:\n            provider.update(dispatch_fn=self._dispatch_input)\n\n        # execute post-processing modules\n        for mod in self.postproc_modules:\n            self.input_events = mod.process(events=self.input_events)\n\n        # real dispatch input\n        input_events = self.input_events\n        pop = input_events.pop\n        post_dispatch_input = self.post_dispatch_input\n        while input_events:\n            post_dispatch_input(*pop(0))\n\n    def idle(self):\n        '''This function is called after every frame. By default:\n\n           * it \"ticks\" the clock to the next frame.\n           * it reads all input and dispatches events.\n           * it dispatches `on_update`, `on_draw` and `on_flip` events to the\n             window.\n        '''\n\n        # update dt\n        Clock.tick()\n\n        # read and dispatch input from providers\n        self.dispatch_input()\n\n        # flush all the canvas operation\n        Builder.sync()\n\n        # tick before draw\n        Clock.tick_draw()\n\n        # flush all the canvas operation\n        Builder.sync()\n\n        window = self.window\n        if window and window.canvas.needs_redraw:\n            window.dispatch('on_draw')\n            window.dispatch('on_flip')\n\n        # don't loop if we don't have listeners !\n        if len(self.event_listeners) == 0:\n            Logger.error('Base: No event listeners have been created')\n            Logger.error('Base: Application will leave')\n            self.exit()\n            return False\n\n        return self.quit\n\n    def run(self):\n        '''Main loop'''\n        while not self.quit:\n            self.idle()\n        self.exit()\n\n    def exit(self):\n        '''Close the main loop and close the window.'''\n        self.close()\n        if self.window:\n            self.window.close()\n\n    def on_stop(self):\n        '''Event handler for `on_stop` events which will be fired right\n        after all input providers have been stopped.'''\n        pass\n\n    def on_pause(self):\n        '''Event handler for `on_pause` which will be fired when\n        the event loop is paused.'''\n        pass\n\n    def on_start(self):\n        '''Event handler for `on_start` which will be fired right\n        after all input providers have been started.'''\n        pass\n\n#: EventLoop instance\nEventLoop = EventLoopBase()\n\n\ndef _run_mainloop():\n    '''If no window has been created, this will be the executed mainloop.'''\n    while True:\n        try:\n            EventLoop.run()\n            stopTouchApp()\n            break\n        except BaseException as inst:\n            # use exception manager first\n            r = ExceptionManager.handle_exception(inst)\n            if r == ExceptionManager.RAISE:\n                stopTouchApp()\n                raise\n            else:\n                pass\n\n\ndef runTouchApp(widget=None, slave=False):\n    '''Static main function that starts the application loop.\n    You can access some magic via the following arguments:\n\n    :Parameters:\n        `<empty>`\n            To make dispatching work, you need at least one\n            input listener. If not, application will leave.\n            (MTWindow act as an input listener)\n\n        `widget`\n            If you pass only a widget, a MTWindow will be created\n            and your widget will be added to the window as the root\n            widget.\n\n        `slave`\n            No event dispatching is done. This will be your job.\n\n        `widget + slave`\n            No event dispatching is done. This will be your job but\n            we try to get the window (must be created by you beforehand)\n            and add the widget to it. Very usefull for embedding Kivy\n            in another toolkit. (like Qt, check kivy-designed)\n\n    '''\n\n    from kivy.input import MotionEventFactory, kivy_postproc_modules\n\n    # Ok, we got one widget, and we are not in slave mode\n    # so, user don't create the window, let's create it for him !\n    if widget:\n        EventLoop.ensure_window()\n\n    # Instance all configured input\n    for key, value in Config.items('input'):\n        Logger.debug('Base: Create provider from %s' % (str(value)))\n\n        # split value\n        args = str(value).split(',', 1)\n        if len(args) == 1:\n            args.append('')\n        provider_id, args = args\n        provider = MotionEventFactory.get(provider_id)\n        if provider is None:\n            Logger.warning('Base: Unknown <%s> provider' % str(provider_id))\n            continue\n\n        # create provider\n        p = provider(key, args)\n        if p:\n            EventLoop.add_input_provider(p, True)\n\n    # add postproc modules\n    for mod in list(kivy_postproc_modules.values()):\n        EventLoop.add_postproc_module(mod)\n\n    # add main widget\n    if widget and EventLoop.window:\n        if widget not in EventLoop.window.children:\n            EventLoop.window.add_widget(widget)\n\n    # start event loop\n    Logger.info('Base: Start application main loop')\n    EventLoop.start()\n\n    # we are in a slave mode, don't do dispatching.\n    if slave:\n        return\n\n    # in non-slave mode, they are 2 issues\n    #\n    # 1. if user created a window, call the mainloop from window.\n    #    This is due to glut, it need to be called with\n    #    glutMainLoop(). Only FreeGLUT got a gluMainLoopEvent().\n    #    So, we are executing the dispatching function inside\n    #    a redisplay event.\n    #\n    # 2. if no window is created, we are dispatching event lopp\n    #    ourself (previous behavior.)\n    #\n    try:\n        if EventLoop.window is None:\n            _run_mainloop()\n        else:\n            EventLoop.window.mainloop()\n    finally:\n        stopTouchApp()\n\n\ndef stopTouchApp():\n    '''Stop the current application by leaving the main loop'''\n    if EventLoop is None:\n        return\n    if EventLoop.status != 'started':\n        return\n    Logger.info('Base: Leaving application in progress...')\n    EventLoop.close()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/cache.py",
    "content": "'''\nCache manager\n=============\n\nThe cache manager can be used to store python objects attached to a unique\nkey. The cache can be controlled in two ways: with a object limit or a\ntimeout.\n\nFor example, we can create a new cache with a limit of 10 objects and a\ntimeout of 5 seconds::\n\n    # register a new Cache\n    Cache.register('mycache', limit=10, timeout=5)\n\n    # create an object + id\n    key = 'objectid'\n    instance = Label(text=text)\n    Cache.append('mycache', key, instance)\n\n    # retrieve the cached object\n    instance = Cache.get('mycache', key)\n\nIf the instance is NULL, the cache may have trashed it because you've\nnot used the label for 5 seconds and you've reach the limit.\n'''\n\n__all__ = ('Cache', )\n\nfrom os import environ\nfrom kivy.logger import Logger\nfrom kivy.clock import Clock\n\n\nclass Cache(object):\n    '''See module documentation for more information.\n    '''\n\n    _categories = {}\n    _objects = {}\n\n    @staticmethod\n    def register(category, limit=None, timeout=None):\n        '''Register a new category in the cache with the specified limit.\n\n        :Parameters:\n            `category` : str\n                Identifier of the category.\n            `limit` : int (optional)\n                Maximum number of objects allowed in the cache.\n                If None, no limit is applied.\n            `timeout` : double (optional)\n                Time after which to delete the object if it has not been used.\n                If None, no timeout is applied.\n        '''\n        Cache._categories[category] = {\n            'limit': limit,\n            'timeout': timeout}\n        Cache._objects[category] = {}\n        Logger.debug(\n            'Cache: register <%s> with limit=%s, timeout=%s' %\n            (category, str(limit), str(timeout)))\n\n    @staticmethod\n    def append(category, key, obj, timeout=None):\n        '''Add a new object to the cache.\n\n        :Parameters:\n            `category` : str\n                Identifier of the category.\n            `key` : str\n                Unique identifier of the object to store.\n            `obj` : object\n                Object to store in cache.\n            `timeout` : double (optional)\n                Time after which to delete the object if it has not been used.\n                If None, no timeout is applied.\n        '''\n        #check whether obj should not be cached first\n        if getattr(obj, '_no_cache', False):\n            return\n        try:\n            cat = Cache._categories[category]\n        except KeyError:\n            Logger.warning('Cache: category <%s> not exist' % category)\n            return\n        timeout = timeout or cat['timeout']\n        # FIXME: activate purge when limit is hit\n        #limit = cat['limit']\n        #if limit is not None and len(Cache._objects[category]) >= limit:\n        #    Cache._purge_oldest(category)\n        Cache._objects[category][key] = {\n            'object': obj,\n            'timeout': timeout,\n            'lastaccess': Clock.get_time(),\n            'timestamp': Clock.get_time()}\n\n    @staticmethod\n    def get(category, key, default=None):\n        '''Get a object from the cache.\n\n        :Parameters:\n            `category` : str\n                Identifier of the category.\n            `key` : str\n                Unique identifier of the object in the store.\n            `default` : anything, defaults to None\n                Default value to be returned if the key is not found.\n        '''\n        try:\n            Cache._objects[category][key]['lastaccess'] = Clock.get_time()\n            return Cache._objects[category][key]['object']\n        except Exception:\n            return default\n\n    @staticmethod\n    def get_timestamp(category, key, default=None):\n        '''Get the object timestamp in the cache.\n\n        :Parameters:\n            `category` : str\n                Identifier of the category.\n            `key` : str\n                Unique identifier of the object in the store.\n            `default` : anything, defaults to None\n                Default value to be returned if the key is not found.\n        '''\n        try:\n            return Cache._objects[category][key]['timestamp']\n        except Exception:\n            return default\n\n    @staticmethod\n    def get_lastaccess(category, key, default=None):\n        '''Get the objects last access time in the cache.\n\n        :Parameters:\n            `category` : str\n                Identifier of the category.\n            `key` : str\n                Unique identifier of the object in the store.\n            `default` : anything, defaults to None\n                Default value to be returned if the key is not found.\n        '''\n        try:\n            return Cache._objects[category][key]['lastaccess']\n        except Exception:\n            return default\n\n    @staticmethod\n    def remove(category, key=None):\n        '''Purge the cache.\n\n        :Parameters:\n            `category` : str\n                Identifier of the category.\n            `key` : str (optional)\n                Unique identifier of the object in the store. If this\n                arguement is not supplied, the entire category will be purged.\n        '''\n        try:\n            if key is not None:\n                del Cache._objects[category][key]\n            else:\n                Cache._objects[category] = {}\n        except Exception:\n            pass\n\n    @staticmethod\n    def _purge_oldest(category, maxpurge=1):\n        print('PURGE', category)\n        import heapq\n        heap_list = []\n        for key in Cache._objects[category]:\n            obj = Cache._objects[category][key]\n            if obj['lastaccess'] == obj['timestamp']:\n                continue\n            heapq.heappush(heap_list, (obj['lastaccess'], key))\n            print('<<<', obj['lastaccess'])\n        n = 0\n        while n < maxpurge:\n            try:\n                lastaccess, key = heapq.heappop(heap_list)\n                print('=>', key, lastaccess, Clock.get_time())\n            except Exception:\n                return\n            del Cache._objects[category][key]\n\n    @staticmethod\n    def _purge_by_timeout(dt):\n        curtime = Clock.get_time()\n\n        for category in Cache._objects:\n            if category not in Cache._categories:\n                continue\n            timeout = Cache._categories[category]['timeout']\n            if timeout is not None and dt > timeout:\n                # XXX got a lag ! that may be because the frame take lot of\n                # time to draw. and the timeout is not adapted to the current\n                # framerate. So, increase the timeout by two.\n                # ie: if the timeout is 1 sec, and framerate go to 0.7, newly\n                # object added will be automaticly trashed.\n                timeout *= 2\n                Cache._categories[category]['timeout'] = timeout\n                continue\n\n            for key in list(Cache._objects[category].keys())[:]:\n                lastaccess = Cache._objects[category][key]['lastaccess']\n                objtimeout = Cache._objects[category][key]['timeout']\n\n                # take the object timeout if available\n                if objtimeout is not None:\n                    timeout = objtimeout\n\n                # no timeout, cancel\n                if timeout is None:\n                    continue\n\n                if curtime - lastaccess > timeout:\n                    del Cache._objects[category][key]\n\n    @staticmethod\n    def print_usage():\n        '''Print the cache usage to the console.'''\n        print('Cache usage :')\n        for category in Cache._categories:\n            print(' * %s : %d / %s, timeout=%s' % (\n                category.capitalize(),\n                len(Cache._objects[category]),\n                str(Cache._categories[category]['limit']),\n                str(Cache._categories[category]['timeout'])))\n\nif 'KIVY_DOC_INCLUDE' not in environ:\n    # install the schedule clock for purging\n    Clock.schedule_interval(Cache._purge_by_timeout, 1)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/clock.py",
    "content": "'''\nClock object\n============\n\nThe :class:`Clock` object allows you to schedule a function call in the\nfuture; once or repeatedly at specified intervals. You can get the time\nelapsed between the scheduling and the calling of the callback via the\n`dt` argument::\n\n    # dt means delta-time\n    def my_callback(dt):\n        pass\n\n    # call my_callback every 0.5 seconds\n    Clock.schedule_interval(my_callback, 0.5)\n\n    # call my_callback in 5 seconds\n    Clock.schedule_once(my_callback, 5)\n\n    # call my_callback as soon as possible (usually next frame.)\n    Clock.schedule_once(my_callback)\n\n.. note::\n\n    If the callback returns False, the schedule will be removed.\n\nIf you want to schedule a function to call with default arguments, you can use\nthe `functools.partial\n<http://docs.python.org/library/functools.html#functools.partial>`_ python\nmodule::\n\n    from functools import partial\n\n    def my_callback(value, key, *largs):\n        pass\n\n    Clock.schedule_interval(partial(my_callback, 'my value', 'my key'), 0.5)\n\nConversely, if you want to schedule a function that doesn't accept the dt\nargument, you can use a `lambda\n<http://docs.python.org/2/reference/expressions.html#lambda>`_ expression\nto write a short function that does accept dt. For Example::\n\n    def no_args_func():\n        print(\"I accept no arguments, so don't schedule me in the clock\")\n\n    Clock.schedule_once(lambda dt: no_args_func(), 0.5)\n\n.. note::\n\n    You cannot unschedule an anonymous function unless you keep a\n    reference to it. It's better to add \\*args to your function\n    definition so that it can be called with an arbitrary number of\n    parameters.\n\n.. important::\n\n    The callback is weak-referenced: you are responsible for keeping a\n    reference to your original object/callback. If you don't keep a\n    reference, the ClockBase will never execute your callback. For\n    example::\n\n        class Foo(object):\n            def start(self):\n                Clock.schedule_interval(self.callback, 0.5)\n\n            def callback(self, dt):\n                print('In callback')\n\n        # A Foo object is created and the method start is called.\n        # Because no reference is kept to the instance returned from Foo(),\n        # the object will be collected by the Python Garbage Collector and\n        # your callback will be never called.\n        Foo().start()\n\n        # So you should do the following and keep a reference to the instance\n        # of foo until you don't need it anymore!\n        foo = Foo()\n        foo.start()\n\n\n.. _schedule-before-frame:\n\nSchedule before frame\n---------------------\n\n.. versionadded:: 1.0.5\n\nSometimes you need to schedule a callback BEFORE the next frame. Starting\nfrom 1.0.5, you can use a timeout of -1::\n\n    Clock.schedule_once(my_callback, 0) # call after the next frame\n    Clock.schedule_once(my_callback, -1) # call before the next frame\n\nThe Clock will execute all the callbacks with a timeout of -1 before the\nnext frame even if you add a new callback with -1 from a running\ncallback. However, :class:`Clock` has an iteration limit for these\ncallbacks: it defaults to 10.\n\nIf you schedule a callback that schedules a callback that schedules a .. etc\nmore than 10 times, it will leave the loop and send a warning to the console,\nthen continue after the next frame. This is implemented to prevent bugs from\nhanging or crashing the application.\n\nIf you need to increase the limit, set the :attr:`max_iteration` property::\n\n    from kivy.clock import Clock\n    Clock.max_iteration = 20\n\n.. _triggered-events:\n\nTriggered Events\n----------------\n\n.. versionadded:: 1.0.5\n\nA triggered event is a way to defer a callback exactly like schedule_once(),\nbut with some added convenience. The callback will only be scheduled once per\nframe even if you call the trigger twice (or more). This is not the case\nwith :meth:`Clock.schedule_once`::\n\n    # will run the callback twice before the next frame\n    Clock.schedule_once(my_callback)\n    Clock.schedule_once(my_callback)\n\n    # will run the callback once before the next frame\n    t = Clock.create_trigger(my_callback)\n    t()\n    t()\n\nBefore triggered events, you may have used this approach in a widget::\n\n    def trigger_callback(self, *largs):\n        Clock.unschedule(self.callback)\n        Clock.schedule_once(self.callback)\n\nAs soon as you call `trigger_callback()`, it will correctly schedule the\ncallback once in the next frame. It is more convenient to create and bind to\nthe triggered event than using :meth:`Clock.schedule_once` in a function::\n\n    from kivy.clock import Clock\n    from kivy.uix.widget import Widget\n\n    class Sample(Widget):\n        def __init__(self, **kwargs):\n            self._trigger = Clock.create_trigger(self.cb)\n            super(Sample, self).__init__(**kwargs)\n            self.bind(x=self._trigger, y=self._trigger)\n\n        def cb(self, *largs):\n            pass\n\nEven if x and y changes within one frame, the callback is only run once.\n\n.. note::\n\n    :meth:`ClockBase.create_trigger` also has a timeout parameter that\n    behaves exactly like :meth:`ClockBase.schedule_once`.\n\nThreading\n----------\n\n.. versionadded:: 1.9.0\n\nOften, other threads are used to schedule callbacks with kivy's main thread\nusing :class:`ClockBase`. Therefore, it's important to know what is thread safe\nand what isn't.\n\nAll the :class:`ClockBase` and :class:`ClockEvent` methods are safe with\nrespect to kivy's thread. That is, it's always safe to call these methods\nfrom a single thread that is not the kivy thread. However, there are no\nguarantees as to the order in which these callbacks will be executed.\n\nCalling a previously created trigger from two different threads (even if one\nof them is the kivy thread), or calling the trigger and its\n:meth:`ClockEvent.cancel` method from two different threads at the same time is\nnot safe. That is, although no exception will be raised, there no guarantees\nthat calling the trigger from two different threads will not result in the\ncallback being executed twice, or not executed at all. Similarly, such issues\nmight arise when calling the trigger and canceling it with\n:meth:`ClockBase.unschedule` or :meth:`ClockEvent.cancel` from two threads\nsimultaneously.\n\nTherefore, it is safe to call :meth:`ClockBase.create_trigger`,\n:meth:`ClockBase.schedule_once`, :meth:`ClockBase.schedule_interval`, or\ncall or cancel a previously created trigger from an external thread.\nThe following code, though, is not safe because it calls or cancels\nfrom two threads simultaneously without any locking mechanism::\n\n    event = Clock.create_trigger(func)\n\n    # in thread 1\n    event()\n    # in thread 2\n    event()\n    # now, the event may be scheduled twice or once\n\n    # the following is also unsafe\n    # in thread 1\n    event()\n    # in thread 2\n    event.cancel()\n    # now, the event may or may not be scheduled and a subsequent call\n    # may schedule it twice\n\nNote, in the code above, thread 1 or thread 2 could be the kivy thread, not\njust an external thread.\n'''\n\n__all__ = ('Clock', 'ClockBase', 'ClockEvent', 'mainthread')\n\nfrom sys import platform\nfrom os import environ\nfrom functools import wraps, partial\nfrom kivy.context import register_context\nfrom kivy.weakmethod import WeakMethod\nfrom kivy.config import Config\nfrom kivy.logger import Logger\nimport time\n\ntry:\n    import ctypes\n    if platform in ('win32', 'cygwin'):\n        # Win32 Sleep function is only 10-millisecond resolution, so\n        # instead use a waitable timer object, which has up to\n        # 100-nanosecond resolution (hardware and implementation\n        # dependent, of course).\n\n        _kernel32 = ctypes.windll.kernel32\n\n        class _ClockBase(object):\n            def __init__(self):\n                self._timer = _kernel32.CreateWaitableTimerA(None, True, None)\n\n            def usleep(self, microseconds):\n                delay = ctypes.c_longlong(int(-microseconds * 10))\n                _kernel32.SetWaitableTimer(\n                    self._timer, ctypes.byref(delay), 0,\n                    ctypes.c_void_p(), ctypes.c_void_p(), False)\n                _kernel32.WaitForSingleObject(self._timer, 0xffffffff)\n\n        _default_time = time.clock\n    else:\n        if platform == 'darwin':\n            _libc = ctypes.CDLL('libc.dylib')\n        else:\n            _libc = ctypes.CDLL('libc.so')\n        _libc.usleep.argtypes = [ctypes.c_ulong]\n        _libc_usleep = _libc.usleep\n\n        class _ClockBase(object):\n            def usleep(self, microseconds):\n                _libc_usleep(int(microseconds))\n\n        _default_time = time.time\n\nexcept (OSError, ImportError):\n    # ImportError: ctypes is not available on python-for-android.\n    # OSError: if the libc cannot be readed (like with buildbot: invalid ELF\n    # header)\n\n    _default_time = time.time\n    _default_sleep = time.sleep\n\n    class _ClockBase(object):\n        def usleep(self, microseconds):\n            _default_sleep(microseconds / 1000000.)\n\n\ndef _hash(cb):\n    if hasattr(cb, '__self__') and cb.__self__ is not None:\n        return (id(cb.__self__) & 0xFF00) >> 8\n    return (id(cb) & 0xFF00) >> 8\n\n\nclass ClockEvent(object):\n    ''' A class that describes a callback scheduled with kivy's :attr:`Clock`.\n    This class is never created by the user; instead, kivy creates and returns\n    an instance of this class when scheduling a callback.\n\n    .. warning::\n        Most of the methods of this class are internal and can change without\n        notice. The only exception are the :meth:`cancel` and\n        :meth:`__call__` methods.\n    '''\n\n    def __init__(self, clock, loop, callback, timeout, starttime, cid,\n                 trigger=False):\n        self.clock = clock\n        self.cid = cid\n        self.loop = loop\n        self.weak_callback = None\n        self.callback = callback\n        self.timeout = timeout\n        self._is_triggered = trigger\n        self._last_dt = starttime\n        self._dt = 0.\n        if trigger:\n            clock._events[cid].append(self)\n\n    def __call__(self, *largs):\n        ''' Schedules the callback associated with this instance.\n        If the callback is already scheduled, it will not be scheduled again.\n        '''\n        # if the event is not yet triggered, do it !\n        if self._is_triggered is False:\n            self._is_triggered = True\n            # update starttime\n            self._last_dt = self.clock._last_tick\n            self.clock._events[self.cid].append(self)\n            return True\n\n    def get_callback(self):\n        callback = self.callback\n        if callback is not None:\n            return callback\n        callback = self.weak_callback\n        if callback.is_dead():\n            return None\n        return callback()\n\n    @property\n    def is_triggered(self):\n        return self._is_triggered\n\n    def cancel(self):\n        ''' Cancels the callback if it was scheduled to be called.\n        '''\n        if self._is_triggered:\n            self._is_triggered = False\n            try:\n                self.clock._events[self.cid].remove(self)\n            except ValueError:\n                pass\n\n    def release(self):\n        self.weak_callback = WeakMethod(self.callback)\n        self.callback = None\n\n    def tick(self, curtime, remove):\n        # timeout happened ? (check also if we would miss from 5ms) this\n        # 5ms increase the accuracy if the timing of animation for\n        # example.\n        if curtime - self._last_dt < self.timeout - 0.005:\n            return True\n\n        # calculate current timediff for this event\n        self._dt = curtime - self._last_dt\n        self._last_dt = curtime\n        loop = self.loop\n\n        # get the callback\n        callback = self.get_callback()\n        if callback is None:\n            self._is_triggered = False\n            try:\n                remove(self)\n            except ValueError:\n                pass\n            return False\n\n        # if it's a trigger, allow to retrigger inside the callback\n        # we have to remove event here, otherwise, if we remove later, the user\n        # might have canceled in the callback and then re-triggered. That'd\n        # result in the removal of the re-trigger\n        if not loop:\n            self._is_triggered = False\n            try:\n                remove(self)\n            except ValueError:\n                pass\n\n        # call the callback\n        ret = callback(self._dt)\n\n        # if the user returns False explicitly, remove the event\n        if loop and ret is False:\n            self._is_triggered = False\n            try:\n                remove(self)\n            except ValueError:\n                pass\n            return False\n        return loop\n\n    def __repr__(self):\n        return '<ClockEvent callback=%r>' % self.get_callback()\n\n\nclass ClockBase(_ClockBase):\n    '''A clock object with event support.\n    '''\n    __slots__ = ('_dt', '_last_fps_tick', '_last_tick', '_fps', '_rfps',\n                 '_start_tick', '_fps_counter', '_rfps_counter', '_events',\n                 '_frames', '_frames_displayed',\n                 '_max_fps', 'max_iteration')\n\n    MIN_SLEEP = 0.005\n    SLEEP_UNDERSHOOT = MIN_SLEEP - 0.001\n\n    def __init__(self):\n        super(ClockBase, self).__init__()\n        self._dt = 0.0001\n        self._start_tick = self._last_tick = self.time()\n        self._fps = 0\n        self._rfps = 0\n        self._fps_counter = 0\n        self._rfps_counter = 0\n        self._last_fps_tick = None\n        self._frames = 0\n        self._frames_displayed = 0\n        self._events = [[] for i in range(256)]\n        self._max_fps = float(Config.getint('graphics', 'maxfps'))\n\n        #: .. versionadded:: 1.0.5\n        #:     When a schedule_once is used with -1, you can add a limit on\n        #:     how iteration will be allowed. That is here to prevent too much\n        #:     relayout.\n        self.max_iteration = 10\n\n    @property\n    def frametime(self):\n        '''Time spent between the last frame and the current frame\n        (in seconds).\n\n        .. versionadded:: 1.8.0\n        '''\n        return self._dt\n\n    @property\n    def frames(self):\n        '''Number of internal frames (not necesseraly drawed) from the start of\n        the clock.\n\n        .. versionadded:: 1.8.0\n        '''\n        return self._frames\n\n    @property\n    def frames_displayed(self):\n        '''Number of displayed frames from the start of the clock.\n        '''\n        return self._frames_displayed\n\n    def tick(self):\n        '''Advance the clock to the next step. Must be called every frame.\n        The default clock has a tick() function called by the core Kivy\n        framework.'''\n\n        self._release_references()\n\n        # do we need to sleep ?\n        if self._max_fps > 0:\n            min_sleep = self.MIN_SLEEP\n            sleep_undershoot = self.SLEEP_UNDERSHOOT\n            fps = self._max_fps\n            usleep = self.usleep\n\n            sleeptime = 1 / fps - (self.time() - self._last_tick)\n            while sleeptime - sleep_undershoot > min_sleep:\n                usleep(1000000 * (sleeptime - sleep_undershoot))\n                sleeptime = 1 / fps - (self.time() - self._last_tick)\n\n        # tick the current time\n        current = self.time()\n        self._dt = current - self._last_tick\n        self._frames += 1\n        self._fps_counter += 1\n        self._last_tick = current\n\n        # calculate fps things\n        if self._last_fps_tick is None:\n            self._last_fps_tick = current\n        elif current - self._last_fps_tick > 1:\n            d = float(current - self._last_fps_tick)\n            self._fps = self._fps_counter / d\n            self._rfps = self._rfps_counter\n            self._last_fps_tick = current\n            self._fps_counter = 0\n            self._rfps_counter = 0\n\n        # process event\n        self._process_events()\n\n        return self._dt\n\n    def tick_draw(self):\n        '''Tick the drawing counter.\n        '''\n        self._process_events_before_frame()\n        self._rfps_counter += 1\n        self._frames_displayed += 1\n\n    def get_fps(self):\n        '''Get the current average FPS calculated by the clock.\n        '''\n        return self._fps\n\n    def get_rfps(self):\n        '''Get the current \"real\" FPS calculated by the clock.\n        This counter reflects the real framerate displayed on the screen.\n\n        In contrast to get_fps(), this function returns a counter of the\n        number of frames, not the average of frames per second.\n        '''\n        return self._rfps\n\n    def get_time(self):\n        '''Get the last tick made by the clock.'''\n        return self._last_tick\n\n    def get_boottime(self):\n        '''Get the time in seconds from the application start.'''\n        return self._last_tick - self._start_tick\n\n    def create_trigger(self, callback, timeout=0):\n        '''Create a Trigger event. Check module documentation for more\n        information.\n\n        :returns:\n\n            A :class:`ClockEvent` instance. To schedule the callback of this\n            instance, you can call it.\n\n        .. versionadded:: 1.0.5\n        '''\n        ev = ClockEvent(self, False, callback, timeout, 0, _hash(callback))\n        ev.release()\n        return ev\n\n    def schedule_once(self, callback, timeout=0):\n        '''Schedule an event in <timeout> seconds. If <timeout> is unspecified\n        or 0, the callback will be called after the next frame is rendered.\n\n        :returns:\n\n            A :class:`ClockEvent` instance. As opposed to\n            :meth:`create_trigger` which only creates the trigger event, this\n            method also schedules it.\n\n        .. versionchanged:: 1.0.5\n            If the timeout is -1, the callback will be called before the next\n            frame (at :meth:`tick_draw`).\n        '''\n        if not callable(callback):\n            raise ValueError('callback must be a callable, got %s' % callback)\n        event = ClockEvent(\n            self, False, callback, timeout, self._last_tick, _hash(callback),\n            True)\n        return event\n\n    def schedule_interval(self, callback, timeout):\n        '''Schedule an event to be called every <timeout> seconds.\n\n        :returns:\n\n            A :class:`ClockEvent` instance. As opposed to\n            :meth:`create_trigger` which only creates the trigger event, this\n            method also schedules it.\n        '''\n        if not callable(callback):\n            raise ValueError('callback must be a callable, got %s' % callback)\n        event = ClockEvent(\n            self, True, callback, timeout, self._last_tick, _hash(callback),\n            True)\n        return event\n\n    def unschedule(self, callback, all=True):\n        '''Remove a previously scheduled event.\n\n        :parameters:\n\n            `callback`: :class:`ClockEvent` or a callable.\n                If it's a :class:`ClockEvent` instance, then the callback\n                associated with this event will be canceled if it is\n                scheduled. If it's a callable, then the callable will be\n                unscheduled if it is scheduled.\n            `all`: bool\n                If True and if `callback` is a callable, all instances of this\n                callable will be unscheduled (i.e. if this callable was\n                scheduled multiple times). Defaults to `True`.\n\n        .. versionchanged:: 1.9.0\n            The all parameter was added. Before, it behaved as if `all` was\n            `True`.\n        '''\n        if isinstance(callback, ClockEvent):\n            callback.cancel()\n        else:\n            if all:\n                for ev in self._events[_hash(callback)][:]:\n                    if ev.get_callback() == callback:\n                        ev.cancel()\n            else:\n                for ev in self._events[_hash(callback)][:]:\n                    if ev.get_callback() == callback:\n                        ev.cancel()\n                        break\n\n    def _release_references(self):\n        # call that function to release all the direct reference to any\n        # callback and replace it with a weakref\n        events = self._events\n        for events in self._events:\n            for event in events[:]:\n                if event.callback is not None:\n                    event.release()\n\n    def _process_events(self):\n        for events in self._events:\n            remove = events.remove\n            for event in events[:]:\n                # event may be already removed from original list\n                if event in events:\n                    event.tick(self._last_tick, remove)\n\n    def _process_events_before_frame(self):\n        found = True\n        count = self.max_iteration\n        events = self._events\n        while found:\n            count -= 1\n            if count == -1:\n                Logger.critical(\n                    'Clock: Warning, too much iteration done before'\n                    ' the next frame. Check your code, or increase'\n                    ' the Clock.max_iteration attribute')\n                break\n\n            # search event that have timeout = -1\n            found = False\n            for events in self._events:\n                remove = events.remove\n                for event in events[:]:\n                    if event.timeout != -1:\n                        continue\n                    found = True\n                    # event may be already removed from original list\n                    if event in events:\n                        event.tick(self._last_tick, remove)\n\n    time = staticmethod(partial(_default_time))\n\nClockBase.time.__doc__ = '''Proxy method for time.time() or time.clock(),\nwhichever is more suitable for the running OS'''\n\n\ndef mainthread(func):\n    '''Decorator that will schedule the call of the function for the next\n    available frame in the mainthread. It can be useful when you use\n    :class:`~kivy.network.urlrequest.UrlRequest` or when you do Thread\n    programming: you cannot do any OpenGL-related work in a thread.\n\n    Please note that this method will return directly and no result can be\n    returned::\n\n        @mainthread\n        def callback(self, *args):\n            print('The request succedded!',\n                  'This callback is called in the main thread.')\n\n        self.req = UrlRequest(url='http://...', on_success=callback)\n\n    .. versionadded:: 1.8.0\n    '''\n    @wraps(func)\n    def delayed_func(*args, **kwargs):\n        def callback_func(dt):\n            func(*args, **kwargs)\n        Clock.schedule_once(callback_func, 0)\n    return delayed_func\n\nif 'KIVY_DOC_INCLUDE' in environ:\n    #: Instance of :class:`ClockBase`.\n    Clock = None\nelse:\n    Clock = register_context('Clock', ClockBase)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/compat.py",
    "content": "'''\nCompatibility module for Python 2.7 and > 3.3\n=============================================\n'''\n\n__all__ = ('PY2', 'string_types', 'queue', 'iterkeys',\n           'itervalues', 'iteritems')\n\nimport sys\ntry:\n    import queue\nexcept ImportError:\n    import Queue as queue\n\n#: True if Python 2 intepreter is used\nPY2 = sys.version_info[0] == 2\n\n#: String types that can be used for checking if a object is a string\nstring_types = None\ntext_type = None\nif PY2:\n    string_types = basestring\n    text_type = unicode\nelse:\n    string_types = text_type = str\n\n#: unichr is just chr in py3, since all strings are unicode\nif PY2:\n    unichr = unichr\nelse:\n    unichr = chr\n\nif PY2:\n    iterkeys = lambda d: d.iterkeys()\n    itervalues = lambda d: d.itervalues()\n    iteritems = lambda d: d.iteritems()\nelse:\n    iterkeys = lambda d: iter(d.keys())\n    itervalues = lambda d: iter(d.values())\n    iteritems = lambda d: iter(d.items())\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/config.py",
    "content": "'''\nConfiguration object\n====================\n\nThe :class:`Config` object is an instance of a modified Python ConfigParser.\nSee the `ConfigParser documentation\n<http://docs.python.org/library/configparser.html>`_ for more information.\n\nKivy has a configuration file which determines the default settings. In\norder to change these settings, you can alter this file manually or use\nthe Config object. Please see the :ref:`Configure Kivy` section for more\ninformation.\n\nNote: To avoid instances where the config settings do not work or they are\nnot applied before window creation (like setting an initial window size),\nConfig.set should be used before importing any modules that affect the\napplication window (ie. importing Window). Ideally, these settings should\nbe declared right at the start of your main.py script.\n\nUsage of the Config object\n--------------------------\n\nTo read a configuration token from a particular section::\n\n    >>> from kivy.config import Config\n    >>> Config.getint('kivy', 'show_fps')\n    0\n\nChange the configuration and save it::\n\n    >>> Config.set('postproc', 'retain_time', '50')\n    >>> Config.write()\n\n.. versionchanged:: 1.7.1\n    The ConfigParser should work correctly with utf-8 now. The values are\n    converted from ascii to unicode only when needed. The method get() returns\n    utf-8 strings.\n\n.. _configuration-tokens:\n\nAvailable configuration tokens\n------------------------------\n\n.. |log_levels| replace:: 'debug', 'info', 'warning', 'error' or 'critical'\n\n:kivy:\n\n    `desktop`: int, 0 or 1\n        This option controls desktop OS specific features, such as enabling\n        drag-able scroll-bar in scroll views, disabling of bubbles in\n        TextInput etc. 0 is disabled, 1 is enabled.\n    `exit_on_escape`: int, 0 or 1\n        Enables exiting kivy when escape is pressed.\n        0 is disabled, 1 is enabled.\n    `pause_on_minimize`: int, 0 or 1\n        If set to `1`, the main loop is paused and the `on_pause` event\n        is dispatched when the window is minimized. This option is intended\n        for desktop use only. Defaults to `0`.\n    `keyboard_layout`: string\n        Identifier of the layout to use.\n    `keyboard_mode`: string\n        Specifies the keyboard mode to use. If can be one of the following:\n\n        * '' - Let Kivy choose the best option for your current platform.\n        * 'system' - real keyboard.\n        * 'dock' - one virtual keyboard docked to a screen side.\n        * 'multi' - one virtual keyboard for every widget request.\n        * 'systemanddock' - virtual docked keyboard plus input from real\n          keyboard.\n        * 'systemandmulti' - analogous.\n    `log_dir`: string\n        Path of log directory.\n    `log_enable`: int, 0 or 1\n        Activate file logging. 0 is disabled, 1 is enabled.\n    `log_level`: string, one of |log_levels|\n        Set the minimum log level to use.\n    `log_name`: string\n        Format string to use for the filename of log file.\n    `window_icon`: string\n        Path of the window icon. Use this if you want to replace the default\n        pygame icon.\n\n:postproc:\n\n    `double_tap_distance`: float\n        Maximum distance allowed for a double tap, normalized inside the range\n        0 - 1000.\n    `double_tap_time`: int\n        Time allowed for the detection of double tap, in milliseconds.\n    `ignore`: list of tuples\n        List of regions where new touches are ignored.\n        This configuration token can be used to resolve hotspot problems\n        with DIY hardware. The format of the list must be::\n\n            ignore = [(xmin, ymin, xmax, ymax), ...]\n\n        All the values must be inside the range 0 - 1.\n    `jitter_distance`: int\n        Maximum distance for jitter detection, normalized inside the range 0\n        - 1000.\n    `jitter_ignore_devices`: string, separated with commas\n        List of devices to ignore from jitter detection.\n    `retain_distance`: int\n        If the touch moves more than is indicated by retain_distance, it will\n        not be retained. Argument should be an int between 0 and 1000.\n    `retain_time`: int\n        Time allowed for a retain touch, in milliseconds.\n    `triple_tap_distance`: float\n        Maximum distance allowed for a triple tap, normalized inside the range\n        0 - 1000.\n    `triple_tap_time`: int\n        Time allowed for the detection of triple tap, in milliseconds.\n\n:graphics:\n    `borderless`: int , one of 0 or 1\n        If set to `1`, removes the window border/decoration.\n    `window_state`: string , one of 'visible', 'hidden', 'maximized'\n    or 'minimized'\n        Sets the window state, defaults to 'visible'. This option is available\n        only for the SDL2 window provider and it should be used on desktop\n        OSes.\n    `fbo`: string, one of 'hardware', 'software' or 'force-hardware'\n        Selects the FBO backend to use.\n    `fullscreen`: int or string, one of 0, 1, 'fake' or 'auto'\n        Activate fullscreen. If set to `1`, a resolution of `width`\n        times `height` pixels will be used.\n        If set to `auto`, your current display's resolution will be\n        used instead. This is most likely what you want.\n        If you want to place the window in another display,\n        use `fake`, or set the `borderless` option from the graphics section,\n        then adjust `width`, `height`, `top` and `left`.\n    `height`: int\n        Height of the :class:`~kivy.core.window.Window`, not used if\n        `fullscreen` is set to `auto`.\n    `left`: int\n        Left position of the :class:`~kivy.core.window.Window`.\n    `maxfps`: int, defaults to 60\n        Maximum FPS allowed.\n    'multisamples': int, defaults to 2\n        Sets the `MultiSample Anti-Aliasing (MSAA)\n        <http://en.wikipedia.org/wiki/Multisample_anti-aliasing>`_ level.\n        Increasing this value results in smoother graphics but at the cost of\n        processing time.\n\n        .. note::\n\n           This feature is limited by device hardware support and will have no\n           effect on devices which do not support the level of MSAA requested.\n\n    `position`: string, one of 'auto' or 'custom'\n        Position of the window on your display. If `auto` is used, you have no\n        control of the initial position: `top` and `left` are ignored.\n    `show_cursor`: int, one of 0 or 1\n        Show the cursor on the screen.\n    `top`: int\n        Top position of the :class:`~kivy.core.window.Window`.\n    `resizable`: int, one of 0 or 1\n        If 0, the window will have a fixed size. If 1, the window will be\n        resizable.\n    `rotation`: int, one of 0, 90, 180 or 270\n        Rotation of the :class:`~kivy.core.window.Window`.\n    `width`: int\n        Width of the :class:`~kivy.core.window.Window`, not used if\n        `fullscreen` is set to `auto`.\n\n:input:\n\n    You can create new input devices using this syntax::\n\n        # example of input provider instance\n        yourid = providerid,parameters\n\n        # example for tuio provider\n        default = tuio,127.0.0.1:3333\n        mytable = tuio,192.168.0.1:3334\n\n    .. seealso::\n\n        Check the providers in kivy.input.providers for the syntax to use\n        inside the configuration file.\n\n:widgets:\n\n    `scroll_distance`: int\n        Default value of the\n        :attr:`~kivy.uix.scrollview.ScrollView.scroll_distance`\n        property used by the :class:`~kivy.uix.scrollview.ScrollView` widget.\n        Check the widget documentation for more information.\n\n    `scroll_friction`: float\n        Default value of the\n        :attr:`~kivy.uix.scrollview.ScrollView.scroll_friction`\n        property used by the :class:`~kivy.uix.scrollview.ScrollView` widget.\n        Check the widget documentation for more information.\n\n    `scroll_timeout`: int\n        Default value of the\n        :attr:`~kivy.uix.scrollview.ScrollView.scroll_timeout`\n        property used by the  :class:`~kivy.uix.scrollview.ScrollView` widget.\n        Check the widget documentation for more information.\n\n    `scroll_stoptime`: int\n        Default value of the\n        :attr:`~kivy.uix.scrollview.ScrollView.scroll_stoptime`\n        property used by the :class:`~kivy.uix.scrollview.ScrollView` widget.\n        Check the widget documentation for more information.\n\n        .. deprecated:: 1.7.0\n            Please use\n            :class:`~kivy.uix.scrollview.ScrollView.effect_cls` instead.\n\n    `scroll_moves`: int\n        Default value of the\n        :attr:`~kivy.uix.scrollview.ScrollView.scroll_moves`\n        property used by the :class:`~kivy.uix.scrollview.ScrollView` widget.\n        Check the widget documentation for more information.\n\n        .. deprecated:: 1.7.0\n            Please use\n            :class:`~kivy.uix.scrollview.ScrollView.effect_cls` instead.\n\n:modules:\n\n    You can activate modules with this syntax::\n\n        modulename =\n\n    Anything after the = will be passed to the module as arguments.\n    Check the specific module's documentation for a list of accepted\n    arguments.\n\n.. note::\n\n    These options control only the initalization of the app and a restart\n    is required for value changes to take effect.\n\n.. versionchanged:: 1.9.0\n    `borderless` and `window_state` have been added to the graphics section.\n    The `fake` setting of the `fullscreen` option has been deprecated,\n    use the `borderless` option instead.\n    `pause_on_minimize` has been added to the kivy section.\n\n.. versionchanged:: 1.8.0\n    `systemanddock` and `systemandmulti` has been added as possible values for\n    `keyboard_mode` in the kivy section. `exit_on_escape` has been added\n    to the kivy section.\n\n.. versionchanged:: 1.2.0\n    `resizable` has been added to graphics section.\n\n.. versionchanged:: 1.1.0\n    tuio no longer listens by default. Window icons are not copied to\n    user directory anymore. You can still set a new window icon by using the\n    ``window_icon`` config setting.\n\n.. versionchanged:: 1.0.8\n    `scroll_timeout`, `scroll_distance` and `scroll_friction` have been added.\n    `list_friction`, `list_trigger_distance` and `list_friction_bound`\n    have been removed. `keyboard_type` and `keyboard_layout` have been\n    removed from the widget. `keyboard_mode` and `keyboard_layout` have\n    been added to the kivy section.\n'''\n\n__all__ = ('Config', 'ConfigParser')\n\ntry:\n    from ConfigParser import ConfigParser as PythonConfigParser\nexcept ImportError:\n    from configparser import RawConfigParser as PythonConfigParser\nfrom os import environ\nfrom os.path import exists\nfrom kivy import kivy_config_fn\nfrom kivy.logger import Logger, logger_config_update\nfrom collections import OrderedDict\nfrom kivy.utils import platform\nfrom kivy.compat import PY2, string_types\nfrom weakref import ref\n\n_is_rpi = exists('/opt/vc/include/bcm_host.h')\n\n# Version number of current configuration format\nKIVY_CONFIG_VERSION = 13\n\nConfig = None\n'''Kivy configuration object. Its :attr:`~kivy.config.ConfigParser.name` is\n`'kivy'`\n'''\n\n\nclass ConfigParser(PythonConfigParser, object):\n    '''Enhanced ConfigParser class that supports the addition of default\n    sections and default values.\n\n    By default, the kivy ConfigParser instance, :attr:`~kivy.config.Config`,\n    is given the name `'kivy'` and the ConfigParser instance used by App,\n    :meth:`~kivy.app.App.build_settings`, is given the name `'app'`.\n\n    :Parameters:\n        `name`: string\n            The name of the instance. See :attr:`name`. Defaults to `''`.\n\n    ..versionchanged:: 1.9.0\n        Each ConfigParser can now be named, :attr:`name`. You can get the\n        ConfigParser associated with a name using :meth:`get_configparser`.\n        In addition, you can now control the config values with\n        :class:`~kivy.properties.ConfigParserProperty`.\n\n    .. versionadded:: 1.0.7\n    '''\n\n    def __init__(self, name=''):\n        PythonConfigParser.__init__(self)\n        self._sections = OrderedDict()\n        self.filename = None\n        self._callbacks = []\n        self.name = name\n\n    def add_callback(self, callback, section=None, key=None):\n        '''Add a callback to be called when a specific section/key changed. If\n        you don't specify a section or a key, it will call the callback\n        for all section/keys changes.\n\n        Callbacks will receive 3 arguments: the section, key and value.\n\n        .. versionadded:: 1.4.1\n        '''\n        if section is None and key is not None:\n            raise Exception('You cannot specify a key without a section')\n        self._callbacks.append((callback, section, key))\n\n    def remove_callback(self, callback, section=None, key=None):\n        '''Removes a callback added with :meth:`add_callback`.\n        :meth:`remove_callback` must be called with the same parameters as\n        :meth:`add_callback`.\n\n        Raises a `ValueError` if not found.\n\n        .. versionadded:: 1.9.0\n        '''\n        self._callbacks.remove((callback, section, key))\n\n    def _do_callbacks(self, section, key, value):\n        for callback, csection, ckey in self._callbacks:\n            if csection is not None and csection != section:\n                continue\n            elif ckey is not None and ckey != key:\n                continue\n            callback(section, key, value)\n\n    def read(self, filename):\n        '''Read only one filename. In contrast to the original ConfigParser of\n        Python, this one is able to read only one file at a time. The last\n        read file will be used for the :meth:`write` method.\n\n        .. versionchanged:: 1.9.0\n            :meth:`read` now calls the callbacks if read changed any values.\n\n        '''\n        if not isinstance(filename, string_types):\n            raise Exception('Only one filename is accepted ({})'.format(\n                string_types.__name__))\n        self.filename = filename\n        # If we try to open directly the configuration file in utf-8,\n        # we correctly get the unicode value by default.\n        # But, when we try to save it again, all the values we didn't changed\n        # are still unicode, and then the PythonConfigParser internal do\n        # a str() conversion -> fail.\n        # Instead we currently to the conversion to utf-8 when value are\n        # \"get()\", but we internally store them in ascii.\n        #with codecs.open(filename, 'r', encoding='utf-8') as f:\n        #    self.readfp(f)\n        old_vals = {sect: {k: v for k, v in self.items(sect)} for sect in\n                    self.sections()}\n        PythonConfigParser.read(self, filename)\n\n        # when reading new file, sections/keys are only increased, not removed\n        f = self._do_callbacks\n        for section in self.sections():\n            if section not in old_vals:  # new section\n                for k, v in self.items(section):\n                    f(section, k, v)\n                continue\n\n            old_keys = old_vals[section]\n            for k, v in self.items(section):  # just update new/changed keys\n                if k not in old_keys or v != old_keys[k]:\n                    f(section, k, v)\n\n    def set(self, section, option, value):\n        '''Functions similarly to PythonConfigParser's set method, except that\n        the value is implicitly converted to a string.\n        '''\n        e_value = value\n        if not isinstance(value, string_types):\n            # might be boolean, int, etc.\n            e_value = str(value)\n        if PY2:\n            if isinstance(value, unicode):\n                e_value = value.encode('utf-8')\n        ret = PythonConfigParser.set(self, section, option, e_value)\n        self._do_callbacks(section, option, value)\n        return ret\n\n    def setall(self, section, keyvalues):\n        '''Set a lot of keys/values in one section at the same time.\n        '''\n        for key, value in keyvalues.items():\n            self.set(section, key, value)\n\n    def get(self, section, option, **kwargs):\n        value = PythonConfigParser.get(self, section, option, **kwargs)\n        if PY2:\n            if type(value) is str:\n                return value.decode('utf-8')\n        return value\n\n    def setdefaults(self, section, keyvalues):\n        '''Set a lot of keys/value defaults in one section at the same time.\n        '''\n        self.adddefaultsection(section)\n        for key, value in keyvalues.items():\n            self.setdefault(section, key, value)\n\n    def setdefault(self, section, option, value):\n        '''Set the default value of a particular option.\n        '''\n        if self.has_option(section, option):\n            return\n        self.set(section, option, value)\n\n    def getdefault(self, section, option, defaultvalue):\n        '''Get an option. If not found, it will return the default value.\n        '''\n        if not self.has_section(section):\n            return defaultvalue\n        if not self.has_option(section, option):\n            return defaultvalue\n        return self.get(section, option)\n\n    def getdefaultint(self, section, option, defaultvalue):\n        '''Get an option. If not found, it will return the default value.\n        The return value will be always converted as an integer.\n\n        .. versionadded:: 1.6.0\n        '''\n        return int(self.getdefault(section, option, defaultvalue))\n\n    def adddefaultsection(self, section):\n        '''Add a section if the section is missing.\n        '''\n        if self.has_section(section):\n            return\n        self.add_section(section)\n\n    def write(self):\n        '''Write the configuration to the last file opened using the\n         :meth:`read` method.\n\n        Return True if the write finished successfully.\n        '''\n        if self.filename is None:\n            return False\n        try:\n            with open(self.filename, 'w') as fd:\n                PythonConfigParser.write(self, fd)\n        except IOError:\n            Logger.exception('Unable to write the config <%s>' % self.filename)\n            return False\n        return True\n\n    def update_config(self, filename, overwrite=False):\n        '''Upgrade the configuration based on a new default config file.\n           Overwrite any existing values if overwrite is True.\n        '''\n        pcp = PythonConfigParser()\n        pcp.read(filename)\n        confset = self.setall if overwrite else self.setdefaults\n        for section in pcp.sections():\n            confset(section, dict(pcp.items(section)))\n        self.write()\n\n    @staticmethod\n    def _register_named_property(name, widget_ref, *largs):\n        ''' Called by the ConfigParserProperty to register a property which\n        was created with a config name instead of a config object.\n\n        When a ConfigParser with this name is later created, the properties\n        are then notified that this parser now exists so they can use it.\n        If the parser already exists, the property is notified here. See\n        :meth:`~kivy.properties.ConfigParserProperty.set_config`.\n\n        :Parameters:\n            `name`: a non-empty string\n                The name of the ConfigParser that is associated with the\n                property. See :attr:`name`.\n            `widget_ref`: 2-tuple.\n                The first element is a reference to the widget containing the\n                property, the second element is the name of the property. E.g.:\n\n                    class House(Widget):\n                        address = ConfigParserProperty('', 'info', 'street',\n                            'directory')\n\n                Then, the first element is a ref to a House instance, and the\n                second is `'address'`.\n        '''\n        configs = ConfigParser._named_configs\n        try:\n            config, props = configs[name]\n        except KeyError:\n            configs[name] = (None, [widget_ref])\n            return\n\n        props.append(widget_ref)\n        if config:\n            config = config()\n        widget = widget_ref[0]()\n\n        if config and widget:  # associate this config with property\n            widget.property(widget_ref[1]).set_config(config)\n\n    @staticmethod\n    def get_configparser(name):\n        '''Returns the :class:`ConfigParser` instance whose name is `name`, or\n        None if not found.\n\n        :Parameters:\n            `name`: string\n                The name of the :class:`ConfigParser` instance to return.\n        '''\n        try:\n            config = ConfigParser._named_configs[name][0]\n            return config() if config else None\n        except KeyError:\n            return None\n\n    # keys are configparser names, values are 2-tuple of (ref(configparser),\n    # widget_ref), where widget_ref is same as in _register_named_property\n    _named_configs = {}\n    _name = ''\n\n    @property\n    def name(self):\n        ''' The name associated with this ConfigParser instance, if not `''`.\n        Defaults to `''`. It can be safely dynamically changed or set to `''`.\n\n        When a ConfigParser is given a name, that config object can be\n        retrieved using :meth:`get_configparser`. In addition, that config\n        instance can also be used with a\n        :class:`~kivy.properties.ConfigParserProperty` instance that set its\n        `config` value to this name.\n\n        Setting more than one ConfigParser with the same name will raise a\n        `ValueError`.\n        '''\n        return self._name\n\n    @name.setter\n    def name(self, value):\n        old_name = self._name\n        if value is old_name:\n            return\n        self._name = value\n        configs = ConfigParser._named_configs\n\n        if old_name:  # disconnect this parser from previously connected props\n            _, props = configs.get(old_name, (None, []))\n            for widget, prop in props:\n                widget = widget()\n                if widget:\n                    widget.property(prop).set_config(None)\n            configs[old_name] = (None, props)\n\n        if not value:\n            return\n\n        # if given new name, connect it with property that used this name\n        try:\n            config, props = configs[value]\n        except KeyError:\n            configs[value] = (ref(self), [])\n            return\n\n        if config is not None:\n            raise ValueError('A parser named {} already exists'.format(value))\n        for widget, prop in props:\n            widget = widget()\n            if widget:\n                widget.property(prop).set_config(self)\n        configs[value] = (ref(self), props)\n\n\nif not environ.get('KIVY_DOC_INCLUDE'):\n\n    #\n    # Read, analyse configuration file\n    # Support upgrade of older config file versions\n    #\n\n    # Create default configuration\n    Config = ConfigParser(name='kivy')\n    Config.add_callback(logger_config_update, 'kivy', 'log_level')\n\n    # Read config file if exist\n    if (exists(kivy_config_fn) and\n            'KIVY_USE_DEFAULTCONFIG' not in environ and\n            'KIVY_NO_CONFIG' not in environ):\n        try:\n            Config.read(kivy_config_fn)\n        except Exception as e:\n            Logger.exception('Core: error while reading local'\n                             'configuration')\n\n    version = Config.getdefaultint('kivy', 'config_version', 0)\n\n    # Add defaults section\n    Config.adddefaultsection('kivy')\n    Config.adddefaultsection('graphics')\n    Config.adddefaultsection('input')\n    Config.adddefaultsection('postproc')\n    Config.adddefaultsection('widgets')\n    Config.adddefaultsection('modules')\n\n    # Upgrade default configuration until we have the current version\n    need_save = False\n    if version != KIVY_CONFIG_VERSION and 'KIVY_NO_CONFIG' not in environ:\n        Logger.warning('Config: Older configuration version detected'\n                       ' ({0} instead of {1})'.format(\n                           version, KIVY_CONFIG_VERSION))\n        Logger.warning('Config: Upgrading configuration in progress.')\n        need_save = True\n\n    while version < KIVY_CONFIG_VERSION:\n        Logger.debug('Config: Upgrading from %d to %d' %\n                     (version, version + 1))\n\n        if version == 0:\n\n            # log level\n            Config.setdefault('kivy', 'keyboard_repeat_delay', '300')\n            Config.setdefault('kivy', 'keyboard_repeat_rate', '30')\n            Config.setdefault('kivy', 'log_dir', 'logs')\n            Config.setdefault('kivy', 'log_enable', '1')\n            Config.setdefault('kivy', 'log_level', 'info')\n            Config.setdefault('kivy', 'log_name', 'kivy_%y-%m-%d_%_.txt')\n            Config.setdefault('kivy', 'window_icon', '')\n\n            # default graphics parameters\n            Config.setdefault('graphics', 'display', '-1')\n            Config.setdefault('graphics', 'fullscreen', 'no')\n            Config.setdefault('graphics', 'height', '600')\n            Config.setdefault('graphics', 'left', '0')\n            Config.setdefault('graphics', 'maxfps', '0')\n            Config.setdefault('graphics', 'multisamples', '2')\n            Config.setdefault('graphics', 'position', 'auto')\n            Config.setdefault('graphics', 'rotation', '0')\n            Config.setdefault('graphics', 'show_cursor', '1')\n            Config.setdefault('graphics', 'top', '0')\n            Config.setdefault('graphics', 'vsync', '1')\n            Config.setdefault('graphics', 'width', '800')\n\n            # input configuration\n            Config.setdefault('input', 'mouse', 'mouse')\n\n            # activate native input provider in configuration\n            # from 1.0.9, don't activate mactouch by default, or app are\n            # unusable.\n            if platform == 'win':\n                Config.setdefault('input', 'wm_touch', 'wm_touch')\n                Config.setdefault('input', 'wm_pen', 'wm_pen')\n            elif platform == 'linux':\n                probesysfs = 'probesysfs'\n                if _is_rpi:\n                    probesysfs += ',provider=hidinput'\n                Config.setdefault('input', '%(name)s', probesysfs)\n\n            # input postprocessing configuration\n            Config.setdefault('postproc', 'double_tap_distance', '20')\n            Config.setdefault('postproc', 'double_tap_time', '250')\n            Config.setdefault('postproc', 'ignore', '[]')\n            Config.setdefault('postproc', 'jitter_distance', '0')\n            Config.setdefault('postproc', 'jitter_ignore_devices',\n                              'mouse,mactouch,')\n            Config.setdefault('postproc', 'retain_distance', '50')\n            Config.setdefault('postproc', 'retain_time', '0')\n\n            # default configuration for keyboard repeatition\n            Config.setdefault('widgets', 'keyboard_layout', 'qwerty')\n            Config.setdefault('widgets', 'keyboard_type', '')\n            Config.setdefault('widgets', 'list_friction', '10')\n            Config.setdefault('widgets', 'list_friction_bound', '20')\n            Config.setdefault('widgets', 'list_trigger_distance', '5')\n\n        elif version == 1:\n            Config.remove_option('graphics', 'vsync')\n            Config.set('graphics', 'maxfps', '60')\n\n        elif version == 2:\n            # was a version to automatically copy windows icon in the user\n            # directory, but it's now not used anymore. User can still change\n            # the window icon by touching the config.\n            pass\n\n        elif version == 3:\n            # add token for scrollview\n            Config.setdefault('widgets', 'scroll_timeout', '55')\n            Config.setdefault('widgets', 'scroll_distance', '20')\n            Config.setdefault('widgets', 'scroll_friction', '1.')\n\n            # remove old list_* token\n            Config.remove_option('widgets', 'list_friction')\n            Config.remove_option('widgets', 'list_friction_bound')\n            Config.remove_option('widgets', 'list_trigger_distance')\n\n        elif version == 4:\n            Config.remove_option('widgets', 'keyboard_type')\n            Config.remove_option('widgets', 'keyboard_layout')\n\n            # add keyboard token\n            Config.setdefault('kivy', 'keyboard_mode', '')\n            Config.setdefault('kivy', 'keyboard_layout', 'qwerty')\n\n        elif version == 5:\n            Config.setdefault('graphics', 'resizable', '1')\n\n        elif version == 6:\n            # if the timeout is still the default value, change it\n            Config.setdefault('widgets', 'scroll_stoptime', '300')\n            Config.setdefault('widgets', 'scroll_moves', '5')\n\n        elif version == 7:\n            # desktop bool indicating whether to use desktop specific features\n            is_desktop = int(platform in ('win', 'macosx', 'linux'))\n            Config.setdefault('kivy', 'desktop', is_desktop)\n            Config.setdefault('postproc', 'triple_tap_distance', '20')\n            Config.setdefault('postproc', 'triple_tap_time', '375')\n\n        elif version == 8:\n            if Config.getint('widgets', 'scroll_timeout') == 55:\n                Config.set('widgets', 'scroll_timeout', '250')\n\n        elif version == 9:\n            Config.setdefault('kivy', 'exit_on_escape', '1')\n\n        elif version == 10:\n            Config.set('graphics', 'fullscreen', '0')\n            Config.setdefault('graphics', 'borderless', '0')\n\n        elif version == 11:\n            Config.setdefault('kivy', 'pause_on_minimize', '0')\n\n        elif version == 12:\n            Config.set('graphics', 'window_state', 'visible')\n\n        #elif version == 1:\n        #   # add here the command for upgrading from configuration 0 to 1\n        #\n        else:\n            # for future.\n            break\n\n        # Pass to the next version\n        version += 1\n\n    # Indicate to the Config that we've upgrade to the latest version.\n    Config.set('kivy', 'config_version', KIVY_CONFIG_VERSION)\n\n    # Now, activate log file\n    Logger.logfile_activated = bool(Config.getint('kivy', 'log_enable'))\n\n    # If no configuration exist, write the default one.\n    if ((not exists(kivy_config_fn) or need_save) and\n            'KIVY_NO_CONFIG' not in environ):\n        try:\n            Config.filename = kivy_config_fn\n            Config.write()\n        except Exception as e:\n            Logger.exception('Core: Error while saving default config file')\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/context.py",
    "content": "'''\nContext\n=======\n\n.. versionadded:: 1.8.0\n\n.. warning::\n\n    This is experimental and subject to change as long as this warning notice\n    is present.\n\nKivy has a few \"global\" instances that are used directly by many pieces of the\nframework: `Cache`, `Builder`, `Clock`.\n\nTODO: document this module.\n\n'''\n\n__all__ = ('Context', 'ProxyContext', 'register_context',\n           'get_current_context')\n\n_contexts = {}\n_default_context = None\n_context_stack = []\n\n\nclass ProxyContext(object):\n\n    __slots__ = ['_obj']\n\n    def __init__(self, obj):\n        object.__init__(self)\n        object.__setattr__(self, '_obj', obj)\n\n    def __getattribute__(self, name):\n        return getattr(object.__getattribute__(self, '_obj'), name)\n\n    def __delattr__(self, name):\n        delattr(object.__getattribute__(self, '_obj'), name)\n\n    def __setattr__(self, name, value):\n        setattr(object.__getattribute__(self, '_obj'), name, value)\n\n    def __bool__(self):\n        return bool(object.__getattribute__(self, '_obj'))\n\n    def __str__(self):\n        return str(object.__getattribute__(self, '_obj'))\n\n    def __repr__(self):\n        return repr(object.__getattribute__(self, '_obj'))\n\n\nclass Context(dict):\n\n    def __init__(self, init=False):\n        dict.__init__(self)\n        self.sandbox = None\n        if not init:\n            return\n\n        for name in _contexts:\n            context = _contexts[name]\n            instance = context['cls'](*context['args'], **context['kwargs'])\n            self[name] = instance\n\n    def push(self):\n        _context_stack.append(self)\n        for name, instance in self.items():\n            object.__setattr__(_contexts[name]['proxy'], '_obj', instance)\n\n    def pop(self):\n        # After poping context from stack. Update proxy's _obj with\n        # instances in current context\n        _context_stack.pop(-1)\n        for name, instance in get_current_context().items():\n            object.__setattr__(_contexts[name]['proxy'], '_obj', instance)\n\n\ndef register_context(name, cls, *args, **kwargs):\n    '''Register a new context.\n    '''\n    instance = cls(*args, **kwargs)\n    proxy = ProxyContext(instance)\n    _contexts[name] = {\n        'cls': cls,\n        'args': args,\n        'kwargs': kwargs,\n        'proxy': proxy}\n    _default_context[name] = instance\n    return proxy\n\n\ndef get_current_context():\n    '''Return the current context.\n    '''\n    if not _context_stack:\n        return _default_context\n    return _context_stack[-1]\n\n_default_context = Context(init=False)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/__init__.py",
    "content": "'''\nCore Abstraction\n================\n\nThis module defines the abstraction layers for our core providers and their\nimplementations. For further information, please refer to\n:ref:`architecture` and the :ref:`providers` section of the documentation.\n\nIn most cases, you shouldn't directly use a library that's already covered\nby the core abstraction. Always try to use our providers first.\nIn case we are missing a feature or method, please let us know by\nopening a new Bug report instead of relying on your library.\n\n.. warning::\n    These are **not** widgets! These are just abstractions of the respective\n    functionality. For example, you cannot add a core image to your window.\n    You have to use the image **widget** class instead. If you're really\n    looking for widgets, please refer to :mod:`kivy.uix` instead.\n'''\n\n\nimport os\nimport sys\nimport traceback\nimport kivy\nfrom kivy.logger import Logger\n\n\nclass CoreCriticalException(Exception):\n    pass\n\n\ndef core_select_lib(category, llist, create_instance=False, base='kivy.core'):\n    if 'KIVY_DOC' in os.environ:\n        return\n    category = category.lower()\n    libs_ignored = []\n    errs = []\n    for option, modulename, classname in llist:\n        try:\n            # module activated in config ?\n            try:\n                if option not in kivy.kivy_options[category]:\n                    libs_ignored.append(modulename)\n                    Logger.debug(\n                        '{0}: Provider <{1}> ignored by config'.format(\n                            category.capitalize(), option))\n                    continue\n            except KeyError:\n                pass\n\n            # import module\n            mod = __import__(name='{2}.{0}.{1}'.format(\n                category, modulename, base),\n                globals=globals(),\n                locals=locals(),\n                fromlist=[modulename], level=0)\n            cls = mod.__getattribute__(classname)\n\n            # ok !\n            Logger.info('{0}: Provider: {1}{2}'.format(\n                category.capitalize(), option,\n                '({0} ignored)'.format(libs_ignored) if libs_ignored else ''))\n            if create_instance:\n                cls = cls()\n            return cls\n\n        except ImportError as e:\n            errs.append((option, e, sys.exc_info()[2]))\n            libs_ignored.append(modulename)\n            Logger.debug('{0}: Ignored <{1}> (import error)'.format(\n                category.capitalize(), option))\n            Logger.trace('', exc_info=e)\n\n        except CoreCriticalException as e:\n            errs.append((option, e, sys.exc_info()[2]))\n            Logger.error('{0}: Unable to use {1}'.format(\n                category.capitalize(), option))\n            Logger.error(\n                '{0}: The module raised an important error: {1!r}'.format(\n                    category.capitalize(), e.message))\n            raise\n\n        except Exception as e:\n            errs.append((option, e, sys.exc_info()[2]))\n            libs_ignored.append(modulename)\n            Logger.trace('{0}: Unable to use {1}'.format(\n                category.capitalize(), option, category))\n            Logger.trace('', exc_info=e)\n\n    err = '\\n'.join(['{} - {}: {}\\n{}'.format(opt, e.__class__.__name__, e,\n                   ''.join(traceback.format_tb(tb))) for opt, e, tb in errs])\n    Logger.critical(\n        '{0}: Unable to find any valuable {0} provider at all!\\n{1}'.format(\n            category.capitalize(), err))\n\n\ndef core_register_libs(category, libs, base='kivy.core'):\n    if 'KIVY_DOC' in os.environ:\n        return\n    category = category.lower()\n    kivy_options = kivy.kivy_options[category]\n    libs_loadable = {}\n    libs_ignored = []\n\n    for option, lib in libs:\n        # module activated in config ?\n        if option not in kivy_options:\n            Logger.debug('{0}: option <{1}> ignored by config'.format(\n                category.capitalize(), option))\n            libs_ignored.append(lib)\n            continue\n        libs_loadable[option] = lib\n\n    libs_loaded = []\n    for item in kivy_options:\n        try:\n            # import module\n            try:\n                lib = libs_loadable[item]\n            except KeyError:\n                continue\n            __import__(name='{2}.{0}.{1}'.format(category, lib, base),\n                       globals=globals(),\n                       locals=locals(),\n                       fromlist=[lib],\n                       level=0)\n\n            libs_loaded.append(lib)\n\n        except Exception as e:\n            Logger.trace('{0}: Unable to use <{1}> as loader!'.format(\n                category.capitalize(), option))\n            Logger.trace('', exc_info=e)\n            libs_ignored.append(lib)\n\n    Logger.info('{0}: Providers: {1} {2}'.format(\n        category.capitalize(),\n        ', '.join(libs_loaded),\n        '({0} ignored)'.format(\n            ', '.join(libs_ignored)) if libs_ignored else ''))\n    return libs_loaded\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/audio/__init__.py",
    "content": "'''\nAudio\n=====\n\nLoad an audio sound and play it with::\n\n    from kivy.core.audio import SoundLoader\n\n    sound = SoundLoader.load('mytest.wav')\n    if sound:\n        print(\"Sound found at %s\" % sound.source)\n        print(\"Sound is %.3f seconds\" % sound.length)\n        sound.play()\n\nYou should not use the Sound class directly. The class returned by\n**SoundLoader.load** will be the best sound provider for that particular file\ntype, so it might return different Sound classes depending the file type.\n\n.. versionchanged:: 1.8.0\n    There are now 2 distinct Gstreamer implementations: one using Gi/Gst working\n    for both Python 2+3 with Gstreamer 1.0, and one using PyGST working\n    only for Python 2 + Gstreamer 0.10.\n    If you have issue with GStreamer, have a look at\n    :ref:`gstreamer-compatibility`\n\n.. note::\n\n    The core audio library does not support recording audio. If you require\n    this functionality, please refer to the\n    `audiostream <https://github.com/kivy/audiostream>`_ extension.\n\n'''\n\n__all__ = ('Sound', 'SoundLoader')\n\nfrom kivy.logger import Logger\nfrom kivy.event import EventDispatcher\nfrom kivy.core import core_register_libs\nfrom kivy.compat import PY2\nfrom kivy.resources import resource_find\nfrom kivy.properties import StringProperty, NumericProperty, OptionProperty, \\\n    AliasProperty, BooleanProperty\nfrom kivy.setupconfig import USE_SDL2\n\n\nclass SoundLoader:\n    '''Load a sound, using the best loader for the given file type.\n    '''\n\n    _classes = []\n\n    @staticmethod\n    def register(classobj):\n        '''Register a new class to load the sound.'''\n        Logger.debug('Audio: register %s' % classobj.__name__)\n        SoundLoader._classes.append(classobj)\n\n    @staticmethod\n    def load(filename):\n        '''Load a sound, and return a Sound() instance.'''\n        rfn = resource_find(filename)\n        if rfn is not None:\n            filename = rfn\n        ext = filename.split('.')[-1].lower()\n        if '?' in ext:\n            ext = ext.split('?')[0]\n        for classobj in SoundLoader._classes:\n            if ext in classobj.extensions():\n                return classobj(source=filename)\n        Logger.warning('Audio: Unable to find a loader for <%s>' %\n                       filename)\n        return None\n\n\nclass Sound(EventDispatcher):\n    '''Represents a sound to play. This class is abstract, and cannot be used\n    directly.\n\n    Use SoundLoader to load a sound.\n\n    :Events:\n        `on_play` : None\n            Fired when the sound is played.\n        `on_stop` : None\n            Fired when the sound is stopped.\n    '''\n\n    source = StringProperty(None)\n    '''Filename / source of your audio file.\n\n    .. versionadded:: 1.3.0\n\n    :attr:`source` is a :class:`~kivy.properties.StringProperty` that defaults\n    to None and is read-only. Use the :meth:`SoundLoader.load` for loading\n    audio.\n    '''\n\n    volume = NumericProperty(1.)\n    '''Volume, in the range 0-1. 1 means full volume, 0 means mute.\n\n    .. versionadded:: 1.3.0\n\n    :attr:`volume` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 1.\n    '''\n\n    state = OptionProperty('stop', options=('stop', 'play'))\n    '''State of the sound, one of 'stop' or 'play'.\n\n    .. versionadded:: 1.3.0\n\n    :attr:`state` is a read-only :class:`~kivy.properties.OptionProperty`.'''\n\n    loop = BooleanProperty(False)\n    '''Set to True if the sound should automatically loop when it finishes.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`loop` is a :class:`~kivy.properties.BooleanProperty` and defaults to\n    False.'''\n\n    #\n    # deprecated\n    #\n    def _get_status(self):\n        return self.state\n    status = AliasProperty(_get_status, None, bind=('state', ))\n    '''\n    .. deprecated:: 1.3.0\n        Use :attr:`state` instead.\n    '''\n\n    def _get_filename(self):\n        return self.source\n    filename = AliasProperty(_get_filename, None, bind=('source', ))\n    '''\n    .. deprecated:: 1.3.0\n        Use :attr:`source` instead.\n    '''\n\n    __events__ = ('on_play', 'on_stop')\n\n    def on_source(self, instance, filename):\n        self.unload()\n        if filename is None:\n            return\n        self.load()\n\n    def get_pos(self):\n        '''\n        Returns the current position of the audio file.\n        Returns 0 if not playing.\n\n        .. versionadded:: 1.4.1\n        '''\n        return 0\n\n    def _get_length(self):\n        return 0\n\n    length = property(lambda self: self._get_length(),\n                      doc='Get length of the sound (in seconds).')\n\n    def load(self):\n        '''Load the file into memory.'''\n        pass\n\n    def unload(self):\n        '''Unload the file from memory.'''\n        pass\n\n    def play(self):\n        '''Play the file.'''\n        self.state = 'play'\n        self.dispatch('on_play')\n\n    def stop(self):\n        '''Stop playback.'''\n        self.state = 'stop'\n        self.dispatch('on_stop')\n\n    def seek(self, position):\n        '''Go to the <position> (in seconds).'''\n        pass\n\n    def on_play(self):\n        pass\n\n    def on_stop(self):\n        pass\n\n\n# Little trick here, don't activate gstreamer on window\n# seem to have lot of crackle or something...\naudio_libs = []\n\n# from now on, prefer our gstplayer instead of gi/pygst.\ntry:\n    from kivy.lib.gstplayer import GstPlayer  # NOQA\n    audio_libs += [('gstplayer', 'audio_gstplayer')]\nexcept ImportError:\n    #audio_libs += [('gi', 'audio_gi')]\n    if PY2:\n        audio_libs += [('pygst', 'audio_pygst')]\naudio_libs += [('ffpyplayer', 'audio_ffpyplayer')]\nif USE_SDL2:\n    audio_libs += [('sdl2', 'audio_sdl2')]\nelse:\n    audio_libs += [('pygame', 'audio_pygame')]\n\ncore_register_libs('audio', audio_libs)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/audio/audio_ffpyplayer.py",
    "content": "'''\nFFmpeg based audio player\n=========================\n\nTo use, you need to install ffpyplyaer and have a compiled ffmpeg shared\nlibrary.\n\n    https://github.com/matham/ffpyplayer\n\nThe docs there describe how to set this up. But briefly, first you need to\ncompile ffmpeg using the shared flags while disabling the static flags (you'll\nprobably have to set the fPIC flag, e.g. CFLAGS=-fPIC). Here's some\ninstructions: https://trac.ffmpeg.org/wiki/CompilationGuide. For Windows, you\ncan download compiled GPL binaries from http://ffmpeg.zeranoe.com/builds/.\nSimilarly, you should download SDL.\n\nNow, you should a ffmpeg and sdl directory. In each, you should have a include,\nbin, and lib directory, where e.g. for Windows, lib contains the .dll.a files,\nwhile bin contains the actual dlls. The include directory holds the headers.\nThe bin directory is only needed if the shared libraries are not already on\nthe path. In the environment define FFMPEG_ROOT and SDL_ROOT, each pointing to\nthe ffmpeg, and SDL directories, respectively. (If you're using SDL2,\nthe include directory will contain a directory called SDL2, which then holds\nthe headers).\n\nOnce defined, download the ffpyplayer git and run\n\n    python setup.py build_ext --inplace\n\nFinally, before running you need to ensure that ffpyplayer is in python's path.\n\n..Note::\n\n    When kivy exits by closing the window while the audio is playing,\n    it appears that the __del__method of SoundFFPy\n    is not called. Because of this the SoundFFPy object is not\n    properly deleted when kivy exits. The consequence is that because\n    MediaPlayer creates internal threads which do not have their daemon\n    flag set, when the main threads exists it'll hang and wait for the other\n    MediaPlayer threads to exit. But since __del__ is not called to delete the\n    MediaPlayer object, those threads will remain alive hanging kivy. What this\n    means is that you have to be sure to delete the MediaPlayer object before\n    kivy exits by setting it to None.\n'''\n\n__all__ = ('SoundFFPy', )\n\ntry:\n    import ffpyplayer\n    from ffpyplayer.player import MediaPlayer\n    from ffpyplayer.tools import set_log_callback, loglevels,\\\n        get_log_callback, formats_in\nexcept:\n    raise\n\n\nfrom kivy.clock import Clock\nfrom kivy.logger import Logger\nfrom kivy.core.audio import Sound, SoundLoader\nfrom kivy.weakmethod import WeakMethod\nimport time\n\nLogger.info('SoundFFPy: Using ffpyplayer {}'.format(ffpyplayer.version))\n\n\nlogger_func = {'quiet': Logger.critical, 'panic': Logger.critical,\n               'fatal': Logger.critical, 'error': Logger.error,\n               'warning': Logger.warning, 'info': Logger.info,\n               'verbose': Logger.debug, 'debug': Logger.debug}\n\n\ndef _log_callback(message, level):\n    message = message.strip()\n    if message:\n        logger_func[level]('ffpyplayer: {}'.format(message))\n\n\nclass SoundFFPy(Sound):\n\n    @staticmethod\n    def extensions():\n        return formats_in\n\n    def __init__(self, **kwargs):\n        self._ffplayer = None\n        self.quitted = False\n        self._log_callback_set = False\n        self._state = ''\n        self.state = 'stop'\n        self._callback_ref = WeakMethod(self._player_callback)\n\n        if not get_log_callback():\n            set_log_callback(_log_callback)\n            self._log_callback_set = True\n\n        super(SoundFFPy, self).__init__(**kwargs)\n\n    def __del__(self):\n        self.unload()\n        if self._log_callback_set:\n            set_log_callback(None)\n\n    def _player_callback(self, selector, value):\n        if self._ffplayer is None:\n            return\n        if selector == 'quit':\n            def close(*args):\n                self.quitted = True\n                self.unload()\n            Clock.schedule_once(close, 0)\n        elif selector == 'eof':\n            Clock.schedule_once(self._do_eos, 0)\n\n    def load(self):\n        self.unload()\n        ff_opts = {'vn': True, 'sn': True}  # only audio\n        self._ffplayer = MediaPlayer(self.source,\n                                     callback=self._callback_ref,\n                                     loglevel='info', ff_opts=ff_opts)\n        player = self._ffplayer\n        player.set_volume(self.volume)\n        player.toggle_pause()\n        self._state = 'paused'\n        # wait until loaded or failed, shouldn't take long, but just to make\n        # sure metadata is available.\n        s = time.clock()\n        while ((not player.get_metadata()['duration'])\n               and not self.quitted and time.clock() - s < 10.):\n            time.sleep(0.005)\n\n    def unload(self):\n        if self._ffplayer:\n            self._ffplayer = None\n        self._state = ''\n        self.state = 'stop'\n        self.quitted = False\n\n    def play(self):\n        if self._state == 'playing':\n            super(SoundFFPy, self).play()\n            return\n        if not self._ffplayer:\n            self.load()\n        self._ffplayer.toggle_pause()\n        self._state = 'playing'\n        self.state = 'play'\n        super(SoundFFPy, self).play()\n\n    def stop(self):\n        if self._ffplayer and self._state == 'playing':\n            self._ffplayer.toggle_pause()\n            self._state = 'paused'\n            self.state = 'stop'\n        super(SoundFFPy, self).stop()\n\n    def seek(self, position):\n        if self._ffplayer is None:\n            return\n        self._ffplayer.seek(position, relative=False)\n\n    def get_pos(self):\n        if self._ffplayer is not None:\n            return self._ffplayer.get_pts()\n        return 0\n\n    def on_volume(self, instance, volume):\n        if self._ffplayer is not None:\n            self._ffplayer.set_volume(volume)\n\n    def _get_length(self):\n        if self._ffplayer is None:\n            return super(SoundFFPy, self)._get_length()\n        return self._ffplayer.get_metadata()['duration']\n\n    def _do_eos(self, *args):\n        if not self.loop:\n            self.stop()\n        else:\n            self.seek(0.)\n\nSoundLoader.register(SoundFFPy)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/audio/audio_gi.py",
    "content": "'''\nAudio Gi\n========\n\nImplementation of Sound with Gi. Gi is both compatible with Python 2 and 3.\n'''\n\nfrom gi.repository import Gst\nfrom kivy.core.audio import Sound, SoundLoader\nfrom kivy.logger import Logger\nfrom kivy.support import install_gobject_iteration\nimport os\nimport sys\n\n# initialize the audio/gi. if the older version is used, don't use audio_gi.\nGst.init(None)\nversion = Gst.version()\nif version < (1, 0, 0, 0):\n    raise Exception('Cannot use audio_gi, Gstreamer < 1.0 is not supported.')\nLogger.info('AudioGi: Using Gstreamer {}'.format(\n    '.'.join(['{}'.format(x) for x in Gst.version()])))\ninstall_gobject_iteration()\n\n\nclass SoundGi(Sound):\n\n    @staticmethod\n    def extensions():\n        return ('wav', 'ogg', 'mp3', )\n\n    def __init__(self, **kwargs):\n        self._data = None\n        super(SoundGi, self).__init__(**kwargs)\n\n    def __del__(self):\n        if self._data is not None:\n            self._data.set_state(Gst.State.NULL)\n\n    def _on_gst_message(self, bus, message):\n        t = message.type\n        if t == Gst.MessageType.EOS:\n            self._data.set_state(Gst.State.NULL)\n            if self.loop:\n                self.play()\n            else:\n                self.stop()\n        elif t == Gst.MessageType.ERROR:\n            self._data.set_state(Gst.State.NULL)\n            err, debug = message.parse_error()\n            Logger.error('AudioGi: %s' % err)\n            Logger.debug(str(debug))\n            self.stop()\n\n    def play(self):\n        if not self._data:\n            return\n        self._data.props.volume = self.volume\n        self._data.set_state(Gst.State.PLAYING)\n        super(SoundGi, self).play()\n\n    def stop(self):\n        if not self._data:\n            return\n        self._data.set_state(Gst.State.NULL)\n        super(SoundGi, self).stop()\n\n    def load(self):\n        self.unload()\n        fn = self.filename\n        if fn is None:\n            return\n\n        slash = ''\n        if sys.platform in ('win32', 'cygwin'):\n            slash = '/'\n\n        if fn[0] == '/':\n            uri = 'file://' + slash + fn\n        else:\n            uri = 'file://' + slash + os.path.join(os.getcwd(), fn)\n\n        self._data = Gst.ElementFactory.make('playbin', '')\n        fakesink = Gst.ElementFactory.make('fakesink', '')\n        self._data.props.video_sink = fakesink\n        bus = self._data.get_bus()\n        bus.add_signal_watch()\n        bus.connect('message', self._on_gst_message)\n        self._data.props.uri = uri\n        self._data.set_state(Gst.State.READY)\n\n    def unload(self):\n        self.stop()\n        self._data = None\n\n    def seek(self, position):\n        if self._data is None:\n            return\n        self._data.seek_simple(\n            Gst.Format.TIME, Gst.SeekFlags.SKIP, position * Gst.SECOND)\n\n    def get_pos(self):\n        if self._data is not None:\n            if self._data.get_state()[1] == Gst.State.PLAYING:\n                try:\n                    ret, value = self._data.query_position(Gst.Format.TIME)\n                    if ret:\n                        return value / float(Gst.SECOND)\n                except:\n                    pass\n        return 0\n\n    def on_volume(self, instance, volume):\n        if self._data is not None:\n            self._data.set_property('volume', volume)\n\n    def _get_length(self):\n        if self._data is not None:\n            if self._data.get_state()[1] != Gst.State.PLAYING:\n                volume_before = self._data.get_property('volume')\n                self._data.set_property('volume', 0)\n                self._data.set_state(Gst.State.PLAYING)\n                try:\n                    self._data.get_state()\n                    ret, value = self._data.query_duration(Gst.Format.TIME)\n                    if ret:\n                        return value / float(Gst.SECOND)\n                finally:\n                    self._data.set_state(Gst.State.NULL)\n                    self._data.set_property('volume', volume_before)\n            else:\n                ret, value = self._data.query_duration(Gst.Format.TIME)\n                if ret:\n                    return value / float(Gst.SECOND)\n        return super(SoundGi, self)._get_length()\n\nSoundLoader.register(SoundGi)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/audio/audio_gstplayer.py",
    "content": "'''\nAudio Gstplayer\n===============\n\n.. versionadded:: 1.8.0\n\nImplementation of a VideoBase with Kivy :class:`~kivy.lib.gstplayer.GstPlayer`\nThis player is the prefered player, using Gstreamer 1.0, working on both Python\n2 and 3.\n'''\n\nfrom kivy.lib.gstplayer import GstPlayer, get_gst_version\nfrom kivy.core.audio import Sound, SoundLoader\nfrom kivy.logger import Logger\nfrom kivy.compat import PY2\nfrom kivy.clock import Clock\nfrom os.path import realpath\n\nif PY2:\n    from urllib import pathname2url\nelse:\n    from urllib.request import pathname2url\n\nLogger.info('AudioGstplayer: Using Gstreamer {}'.format(\n    '.'.join(map(str, get_gst_version()))))\n\n\ndef _on_gstplayer_message(mtype, message):\n    if mtype == 'error':\n        Logger.error('AudioGstplayer: {}'.format(message))\n    elif mtype == 'warning':\n        Logger.warning('AudioGstplayer: {}'.format(message))\n    elif mtype == 'info':\n        Logger.info('AudioGstplayer: {}'.format(message))\n\n\nclass SoundGstplayer(Sound):\n\n    @staticmethod\n    def extensions():\n        return ('wav', 'ogg', 'mp3', 'm4a')\n\n    def __init__(self, **kwargs):\n        self.player = None\n        super(SoundGstplayer, self).__init__(**kwargs)\n\n    def _on_gst_eos_sync(self):\n        Clock.schedule_once(self._on_gst_eos, 0)\n\n    def _on_gst_eos(self, *dt):\n        if self.loop:\n            self.player.stop()\n            self.player.play()\n        else:\n            self.stop()\n\n    def load(self):\n        self.unload()\n        uri = self._get_uri()\n        self.player = GstPlayer(uri, None, self._on_gst_eos_sync,\n                                _on_gstplayer_message)\n        self.player.load()\n\n    def play(self):\n        # we need to set the volume everytime, it seems that stopping + playing\n        # the sound reset the volume.\n        self.player.set_volume(self.volume)\n        self.player.play()\n        super(SoundGstplayer, self).play()\n\n    def stop(self):\n        self.player.stop()\n        super(SoundGstplayer, self).stop()\n\n    def unload(self):\n        if self.player:\n            self.player.unload()\n            self.player = None\n\n    def seek(self, position):\n        self.player.seek(position / self.length)\n\n    def get_pos(self):\n        return self.player.get_position()\n\n    def _get_length(self):\n        return self.player.get_duration()\n\n    def on_volume(self, instance, volume):\n        self.player.set_volume(volume)\n\n    def _get_uri(self):\n        uri = self.filename\n        if not uri:\n            return\n        if not '://' in uri:\n            uri = 'file:' + pathname2url(realpath(uri))\n        return uri\n\nSoundLoader.register(SoundGstplayer)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/audio/audio_pygame.py",
    "content": "'''\nAudioPygame: implementation of Sound with Pygame\n'''\n\n__all__ = ('SoundPygame', )\n\nfrom kivy.clock import Clock\nfrom kivy.utils import platform\nfrom kivy.core.audio import Sound, SoundLoader\n\n_platform = platform\ntry:\n    if _platform == 'android':\n        try:\n            import android.mixer as mixer\n        except ImportError:\n            # old python-for-android version\n            import android_mixer as mixer\n    else:\n        from pygame import mixer\nexcept:\n    raise\n\n# init pygame sound\nmixer.pre_init(44100, -16, 2, 1024)\nmixer.init()\nmixer.set_num_channels(32)\n\n\nclass SoundPygame(Sound):\n\n    # XXX we don't set __slots__ here, to automaticly add\n    # a dictionary. We need that to be able to use weakref for\n    # SoundPygame object. Otherwise, it failed with:\n    # TypeError: cannot create weak reference to 'SoundPygame' object\n    # We use our clock in play() method.\n    # __slots__ = ('_data', '_channel')\n    @staticmethod\n    def extensions():\n        if _platform == 'android':\n            return ('wav', 'ogg', 'mp3', 'm4a')\n        return ('wav', 'ogg')\n\n    def __init__(self, **kwargs):\n        self._data = None\n        self._channel = None\n        super(SoundPygame, self).__init__(**kwargs)\n\n    def _check_play(self, dt):\n        if self._channel is None:\n            return False\n        if self._channel.get_busy():\n            return\n        if self.loop:\n            def do_loop(dt):\n                self.play()\n            Clock.schedule_once(do_loop)\n        else:\n            self.stop()\n        return False\n\n    def play(self):\n        if not self._data:\n            return\n        self._data.set_volume(self.volume)\n        self._channel = self._data.play()\n        self.start_time = Clock.time()\n        # schedule event to check if the sound is still playing or not\n        Clock.schedule_interval(self._check_play, 0.1)\n        super(SoundPygame, self).play()\n\n    def stop(self):\n        if not self._data:\n            return\n        self._data.stop()\n        # ensure we don't have anymore the callback\n        Clock.unschedule(self._check_play)\n        self._channel = None\n        super(SoundPygame, self).stop()\n\n    def load(self):\n        self.unload()\n        if self.filename is None:\n            return\n        self._data = mixer.Sound(self.filename)\n\n    def unload(self):\n        self.stop()\n        self._data = None\n\n    def seek(self, position):\n        if not self._data:\n            return\n        if _platform == 'android' and self._channel:\n            self._channel.seek(position)\n\n    def get_pos(self):\n        if self._data is not None and self._channel:\n            if _platform == 'android':\n                return self._channel.get_pos()\n            return  Clock.time() - self.start_time\n        return 0\n\n    def on_volume(self, instance, volume):\n        if self._data is not None:\n            self._data.set_volume(volume)\n\n    def _get_length(self):\n        if _platform == 'android' and self._channel:\n            return self._channel.get_length()\n        if self._data is not None:\n            return self._data.get_length()\n        return super(SoundPygame, self)._get_length()\n\nSoundLoader.register(SoundPygame)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/audio/audio_pygst.py",
    "content": "'''\nAudio Gstreamer\n===============\n\nImplementation of Sound with GStreamer\n'''\n\ntry:\n    import gi  # NOQA\nexcept ImportError:\n    gi_found = False\nelse:\n    raise Exception('Avoiding PyGST, Gi is better.')\n\ntry:\n    import pygst\n    if not hasattr(pygst, '_gst_already_checked'):\n        pygst.require('0.10')\n        pygst._gst_already_checked = True\n    import gst\nexcept:\n    raise\n\nfrom kivy.core.audio import Sound, SoundLoader\nimport os\nimport sys\nfrom kivy.logger import Logger\n\n# install the gobject iteration\nfrom kivy.support import install_gobject_iteration\ninstall_gobject_iteration()\n\n\nclass SoundPyGst(Sound):\n\n    @staticmethod\n    def extensions():\n        return ('wav', 'ogg', 'mp3', )\n\n    def __init__(self, **kwargs):\n        self._data = None\n        super(SoundPyGst, self).__init__(**kwargs)\n\n    def __del__(self):\n        if self._data is not None:\n            self._data.set_state(gst.STATE_NULL)\n\n    def _on_gst_message(self, bus, message):\n        t = message.type\n        if t == gst.MESSAGE_EOS:\n            self._data.set_state(gst.STATE_NULL)\n            if self.loop:\n                self.play()\n            else:\n                self.stop()\n        elif t == gst.MESSAGE_ERROR:\n            self._data.set_state(gst.STATE_NULL)\n            err, debug = message.parse_error()\n            Logger.error('AudioPyGst: %s' % err)\n            Logger.debug(str(debug))\n            self.stop()\n\n    def play(self):\n        if not self._data:\n            return\n        self._data.set_property('volume', self.volume)\n        self._data.set_state(gst.STATE_PLAYING)\n        super(SoundPyGst, self).play()\n\n    def stop(self):\n        if not self._data:\n            return\n        self._data.set_state(gst.STATE_NULL)\n        super(SoundPyGst, self).stop()\n\n    def load(self):\n        self.unload()\n        fn = self.filename\n        if fn is None:\n            return\n\n        slash = ''\n        if sys.platform in ('win32', 'cygwin'):\n            slash = '/'\n\n        if fn[0] == '/':\n            filepath = 'file://' + slash + fn\n        else:\n            filepath = 'file://' + slash + os.path.join(os.getcwd(), fn)\n\n        self._data = gst.element_factory_make('playbin2', 'player')\n        fakesink = gst.element_factory_make('fakesink', 'fakesink')\n        self._data.set_property('video-sink', fakesink)\n        bus = self._data.get_bus()\n        bus.add_signal_watch()\n        bus.connect('message', self._on_gst_message)\n\n        self._data.set_property('uri', filepath)\n        self._data.set_state(gst.STATE_READY)\n\n    def unload(self):\n        self.stop()\n        self._data = None\n\n    def seek(self, position):\n        if self._data is None:\n            return\n        self._data.seek_simple(gst.FORMAT_TIME, gst.SEEK_FLAG_SKIP,\n                               position * 1000000000.)\n\n    def get_pos(self):\n        if self._data is not None:\n            if self._data.get_state()[1] == gst.STATE_PLAYING:\n                try:\n                    return self._data.query_position(\n                        gst.Format(gst.FORMAT_TIME))[0] / 1000000000.\n                except:\n                    pass\n        return 0\n\n    def on_volume(self, instance, volume):\n        if self._data is not None:\n            self._data.set_property('volume', volume)\n\n    def _get_length(self):\n        if self._data is not None:\n            if self._data.get_state()[1] != gst.STATE_PLAYING:\n                volume_before = self._data.get_property('volume')\n                self._data.set_property('volume', 0)\n                self._data.set_state(gst.STATE_PLAYING)\n                try:\n                    self._data.get_state()\n                    return self._data.query_duration(gst.Format(\n                        gst.FORMAT_TIME))[0] / 1000000000.\n                finally:\n                    self._data.set_state(gst.STATE_NULL)\n                    self._data.set_property('volume', volume_before)\n            else:\n                return self._data.query_duration(\n                    gst.Format(gst.FORMAT_TIME))[0] / 1000000000.\n        return super(SoundPyGst, self)._get_length()\n\nSoundLoader.register(SoundPyGst)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/camera/__init__.py",
    "content": "'''\nCamera\n======\n\nCore class for acquiring the camera and converting its input into a\n:class:`~kivy.graphics.texture.Texture`.\n\n.. versionchanged:: 1.8.0\n    There is now 2 distinct Gstreamer implementation: one using Gi/Gst\n    working for both Python 2+3 with Gstreamer 1.0, and one using PyGST\n    working only for Python 2 + Gstreamer 0.10.\n    If you have issue with GStreamer, have a look at\n    :ref:`gstreamer-compatibility`\n\n'''\n\n__all__ = ('CameraBase', 'Camera')\n\nimport sys\n\nfrom kivy.event import EventDispatcher\nfrom kivy.logger import Logger\nfrom kivy.core import core_select_lib\n\n\nclass CameraBase(EventDispatcher):\n    '''Abstract Camera Widget class.\n\n    Concrete camera classes must implement initialization and\n    frame capturing to a buffer that can be uploaded to the gpu.\n\n    :Parameters:\n        `index`: int\n            Source index of the camera.\n        `size` : tuple (int, int)\n            Size at which the image is drawn. If no size is specified,\n            it defaults to the resolution of the camera image.\n        `resolution` : tuple (int, int)\n            Resolution to try to request from the camera.\n            Used in the gstreamer pipeline by forcing the appsink caps\n            to this resolution. If the camera doesnt support the resolution,\n            a negotiation error might be thrown.\n\n    :Events:\n        `on_load`\n            Fired when the camera is loaded and the texture has become\n            available.\n        `on_frame`\n            Fired each time the camera texture is updated.\n    '''\n\n    __events__ = ('on_load', 'on_texture')\n\n    def __init__(self, **kwargs):\n        kwargs.setdefault('stopped', False)\n        kwargs.setdefault('resolution', (640, 480))\n        kwargs.setdefault('index', 0)\n\n        self.stopped = kwargs.get('stopped')\n        self._resolution = kwargs.get('resolution')\n        self._index = kwargs.get('index')\n        self._buffer = None\n        self._format = 'rgb'\n        self._texture = None\n        self.capture_device = None\n        kwargs.setdefault('size', self._resolution)\n\n        super(CameraBase, self).__init__()\n\n        self.init_camera()\n\n        if not self.stopped:\n            self.start()\n\n    def _set_resolution(self, res):\n        self._resolution = res\n        self.init_camera()\n\n    def _get_resolution(self):\n        return self._resolution\n\n    resolution = property(lambda self: self._get_resolution(),\n                          lambda self, x: self._set_resolution(x),\n                          doc='Resolution of camera capture (width, height)')\n\n    def _set_index(self, x):\n        if x == self._index:\n            return\n        self._index = x\n        self.init_camera()\n\n    def _get_index(self):\n        return self._x\n\n    index = property(lambda self: self._get_index(),\n                     lambda self, x: self._set_index(x),\n                     doc='Source index of the camera')\n\n    def _get_texture(self):\n        return self._texture\n    texture = property(lambda self: self._get_texture(),\n                       doc='Return the camera texture with the latest capture')\n\n    def init_camera(self):\n        '''Initialise the camera (internal)'''\n        pass\n\n    def start(self):\n        '''Start the camera acquire'''\n        self.stopped = False\n\n    def stop(self):\n        '''Release the camera'''\n        self.stopped = True\n\n    def _update(self, dt):\n        '''Update the camera (internal)'''\n        pass\n\n    def _copy_to_gpu(self):\n        '''Copy the the buffer into the texture'''\n        if self._texture is None:\n            Logger.debug('Camera: copy_to_gpu() failed, _texture is None !')\n            return\n        self._texture.blit_buffer(self._buffer, colorfmt=self._format)\n        self._buffer = None\n        self.dispatch('on_texture')\n\n    def on_texture(self):\n        pass\n\n    def on_load(self):\n        pass\n\n# Load the appropriate providers\nproviders = ()\n\nif sys.platform == 'win32':\n    providers += (('videocapture', 'camera_videocapture',\n                   'CameraVideoCapture'), )\nelif sys.platform == 'darwin':\n    providers += (('avfoundation', 'camera_avfoundation',\n                   'CameraAVFoundation'), )\nelse:\n    #providers += (('gi', 'camera_gi', 'CameraGi'), )\n    providers += (('pygst', 'camera_pygst', 'CameraPyGst'), )\n\nproviders += (('opencv', 'camera_opencv', 'CameraOpenCV'), )\n\n\nCamera = core_select_lib('camera', (providers))\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/camera/camera_gi.py",
    "content": "'''\nGi Camera\n=========\n\nImplement CameraBase with Gi / Gstreamer, working on both Python 2 and 3\n'''\n\n__all__ = ('CameraGi', )\n\nfrom gi.repository import Gst\nfrom kivy.clock import Clock\nfrom kivy.graphics.texture import Texture\nfrom kivy.core.camera import CameraBase\nfrom kivy.support import install_gobject_iteration\nfrom kivy.logger import Logger\nfrom ctypes import Structure, c_void_p, c_int, string_at\nfrom weakref import ref\nimport atexit\n\n# initialize the camera/gi. if the older version is used, don't use camera_gi.\nGst.init(None)\nversion = Gst.version()\nif version < (1, 0, 0, 0):\n    raise Exception('Cannot use camera_gi, Gstreamer < 1.0 is not supported.')\nLogger.info('CameraGi: Using Gstreamer {}'.format(\n    '.'.join(['{}'.format(x) for x in Gst.version()])))\ninstall_gobject_iteration()\n\n\nclass _MapInfo(Structure):\n    _fields_ = [\n        ('memory', c_void_p),\n        ('flags', c_int),\n        ('data', c_void_p)]\n        # we don't care about the rest\n\n\ndef _on_cameragi_unref(obj):\n    if obj in CameraGi._instances:\n        CameraGi._instances.remove(obj)\n\n\nclass CameraGi(CameraBase):\n    '''Implementation of CameraBase using GStreamer\n\n    :Parameters:\n        `video_src` : str, default is 'v4l2src'\n            Other tested options are: 'dc1394src' for firewire\n            dc camera (e.g. firefly MV). Any gstreamer video source\n            should potentially work.\n            Theoretically a longer string using \"!\" can be used\n            describing the first part of a gstreamer pipeline.\n    '''\n\n    _instances = []\n\n    def __init__(self, **kwargs):\n        self._pipeline = None\n        self._camerasink = None\n        self._decodebin = None\n        self._texturesize = None\n        self._video_src = kwargs.get('video_src', 'v4l2src')\n        wk = ref(self, _on_cameragi_unref)\n        CameraGi._instances.append(wk)\n        super(CameraGi, self).__init__(**kwargs)\n\n    def init_camera(self):\n        # TODO: This doesn't work when camera resolution is resized at runtime.\n        # There must be some other way to release the camera?\n        if self._pipeline:\n            self._pipeline = None\n\n        video_src = self._video_src\n        if video_src == 'v4l2src':\n            video_src += ' device=/dev/video%d' % self._index\n        elif video_src == 'dc1394src':\n            video_src += ' camera-number=%d' % self._index\n\n        if Gst.version() < (1, 0, 0, 0):\n            caps = ('video/x-raw-rgb,red_mask=(int)0xff0000,'\n                    'green_mask=(int)0x00ff00,blue_mask=(int)0x0000ff')\n            pl = ('{} ! decodebin name=decoder ! ffmpegcolorspace ! '\n                  'appsink name=camerasink emit-signals=True caps={}')\n        else:\n            caps = 'video/x-raw,format=RGB'\n            pl = '{} ! decodebin name=decoder ! videoconvert ! appsink ' + \\\n                 'name=camerasink emit-signals=True caps={}'\n\n        self._pipeline = Gst.parse_launch(pl.format(video_src, caps))\n        self._camerasink = self._pipeline.get_by_name('camerasink')\n        self._camerasink.connect('new-sample', self._gst_new_sample)\n        self._decodebin = self._pipeline.get_by_name('decoder')\n\n        if self._camerasink and not self.stopped:\n            self.start()\n\n    def _gst_new_sample(self, *largs):\n        sample = self._camerasink.emit('pull-sample')\n        if sample is None:\n            return False\n\n        self._sample = sample\n\n        if self._texturesize is None:\n            # try to get the camera image size\n            for pad in self._decodebin.srcpads:\n                s = pad.get_current_caps().get_structure(0)\n                self._texturesize = (\n                    s.get_value('width'),\n                    s.get_value('height'))\n                Clock.schedule_once(self._update)\n                return False\n\n        Clock.schedule_once(self._update)\n        return False\n\n    def start(self):\n        super(CameraGi, self).start()\n        self._pipeline.set_state(Gst.State.PLAYING)\n\n    def stop(self):\n        super(CameraGi, self).stop()\n        self._pipeline.set_state(Gst.State.PAUSED)\n\n    def unload(self):\n        self._pipeline.set_state(Gst.State.NULL)\n\n    def _update(self, dt):\n        sample, self._sample = self._sample, None\n        if sample is None:\n            return\n\n        if self._texture is None and self._texturesize is not None:\n            self._texture = Texture.create(\n                size=self._texturesize, colorfmt='rgb')\n            self._texture.flip_vertical()\n            self.dispatch('on_load')\n\n        # decode sample\n        # read the data from the buffer memory\n        try:\n            buf = sample.get_buffer()\n            result, mapinfo = buf.map(Gst.MapFlags.READ)\n\n            # We cannot get the data out of mapinfo, using Gst 1.0.6 + Gi 3.8.0\n            # related bug report:\n            # https://bugzilla.gnome.org/show_bug.cgi?id=6t8663\n            # ie: mapinfo.data is normally a char*, but here, we have an int\n            # So right now, we use ctypes instead to read the mapinfo ourself.\n            addr = mapinfo.__hash__()\n            c_mapinfo = _MapInfo.from_address(addr)\n\n            # now get the memory\n            self._buffer = string_at(c_mapinfo.data, mapinfo.size)\n            self._copy_to_gpu()\n        finally:\n            if mapinfo is not None:\n                buf.unmap(mapinfo)\n\n\n@atexit.register\ndef camera_gi_clean():\n    # if we leave the python process with some video running, we can hit a\n    # segfault. This is forcing the stop/unload of all remaining videos before\n    # exiting the python process.\n    for weakcamera in CameraGi._instances:\n        camera = weakcamera()\n        if isinstance(camera, CameraGi):\n            camera.stop()\n            camera.unload()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/camera/camera_opencv.py",
    "content": "'''\nOpenCV Camera: Implement CameraBase with OpenCV\n'''\n\n#\n# TODO: make usage of thread or multiprocess\n#\n\n__all__ = ('CameraOpenCV')\n\nfrom kivy.logger import Logger\nfrom kivy.clock import Clock\nfrom kivy.graphics.texture import Texture\nfrom kivy.core.camera import CameraBase\n\ntry:\n    import opencv as cv\n    import opencv.highgui as hg\nexcept ImportError:\n    import cv\n\n    class Hg(object):\n        '''\n        On OSX, not only are the import names different, but the API also\n        differs. There is no module called 'highgui' but the names are directly\n        available in the 'cv' module. Some of them even have a different\n        names.\n\n        Therefore we use this proxy object.\n        '''\n\n        def __getattr__(self, attr):\n            if attr.startswith('cv'):\n                attr = attr[2:]\n            got = getattr(cv, attr)\n            return got\n\n    hg = Hg()\n\n\nclass CameraOpenCV(CameraBase):\n    '''Implementation of CameraBase using OpenCV\n    '''\n\n    def __init__(self, **kwargs):\n        self._device = None\n        super(CameraOpenCV, self).__init__(**kwargs)\n\n    def init_camera(self):\n        # create the device\n        self._device = hg.cvCreateCameraCapture(self._index)\n\n        # Set preferred resolution\n        cv.SetCaptureProperty(self._device, cv.CV_CAP_PROP_FRAME_WIDTH,\n                              self.resolution[0])\n        cv.SetCaptureProperty(self._device, cv.CV_CAP_PROP_FRAME_HEIGHT,\n                              self.resolution[1])\n\n        # and get frame to check if it's ok\n        frame = hg.cvQueryFrame(self._device)\n        # Just set the resolution to the frame we just got, but don't use\n        # self.resolution for that as that would cause an infinite recursion\n        # with self.init_camera (but slowly as we'd have to always get a\n        # frame).\n        self._resolution = (int(frame.width), int(frame.height))\n\n        #get fps\n        self.fps = cv.GetCaptureProperty(self._device, cv.CV_CAP_PROP_FPS)\n        if self.fps <= 0:\n            self.fps = 1 / 30.\n\n        if not self.stopped:\n            self.start()\n\n    def _update(self, dt):\n        if self.stopped:\n            return\n        if self._texture is None:\n            # Create the texture\n            self._texture = Texture.create(self._resolution)\n            self._texture.flip_vertical()\n            self.dispatch('on_load')\n        try:\n            frame = hg.cvQueryFrame(self._device)\n            self._format = 'bgr'\n            try:\n                self._buffer = frame.imageData\n            except AttributeError:\n                # On OSX there is no imageData attribute but a tostring()\n                # method.\n                self._buffer = frame.tostring()\n            self._copy_to_gpu()\n        except:\n            Logger.exception('OpenCV: Couldn\\'t get image from Camera')\n\n    def start(self):\n        super(CameraOpenCV, self).start()\n        Clock.unschedule(self._update)\n        Clock.schedule_interval(self._update, self.fps)\n\n    def stop(self):\n        super(CameraOpenCV, self).stop()\n        Clock.unschedule(self._update)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/camera/camera_pygst.py",
    "content": "'''\nGStreamer Camera\n================\n\nImplement CameraBase with GStreamer, based on PyGST\n'''\n\n__all__ = ('CameraPyGst', )\n\nfrom kivy.clock import Clock\nfrom kivy.graphics.texture import Texture\nfrom kivy.core.camera import CameraBase\n\ntry:\n    import pygst\n    if not hasattr(pygst, '_gst_already_checked'):\n        pygst.require('0.10')\n        pygst._gst_already_checked = True\n    import gst\nexcept:\n    raise\n\n# install the gobject iteration\nfrom kivy.support import install_gobject_iteration\ninstall_gobject_iteration()\n\n\nclass CameraPyGst(CameraBase):\n    '''Implementation of CameraBase using GStreamer\n\n    :Parameters:\n        `video_src` : str, default is 'v4l2src'\n            Other tested options are: 'dc1394src' for firewire\n            dc camera (e.g. firefly MV). Any gstreamer video source\n            should potentially work.\n            Theoretically a longer string using \"!\" can be used\n            describing the first part of a gstreamer pipeline.\n    '''\n\n    def __init__(self, **kwargs):\n        self._pipeline = None\n        self._camerasink = None\n        self._decodebin = None\n        self._texturesize = None\n        self._video_src = kwargs.get('video_src', 'v4l2src')\n        super(CameraPyGst, self).__init__(**kwargs)\n\n    def init_camera(self):\n        # TODO: This doesn't work when camera resolution is resized at runtime.\n        # There must be some other way to release the camera?\n        if self._pipeline:\n            self._pipeline = None\n\n        video_src = self._video_src\n        if video_src == 'v4l2src':\n            video_src += ' device=/dev/video%d' % self._index\n        elif video_src == 'dc1394src':\n            video_src += ' camera-number=%d' % self._index\n\n        GL_CAPS = 'video/x-raw-rgb,red_mask=(int)0xff0000,' + \\\n                  'green_mask=(int)0x00ff00,blue_mask=(int)0x0000ff'\n        pl = '%s ! decodebin name=decoder ! ffmpegcolorspace ! appsink ' + \\\n             'name=camerasink emit-signals=True caps=%s'\n        self._pipeline = gst.parse_launch(pl % (video_src, GL_CAPS))\n        self._camerasink = self._pipeline.get_by_name('camerasink')\n        self._camerasink.connect('new-buffer', self._gst_new_buffer)\n        self._decodebin = self._pipeline.get_by_name('decoder')\n\n        if self._camerasink and not self.stopped:\n            self.start()\n\n    def _gst_new_buffer(self, *largs):\n        self._format = 'rgb'\n        frame = self._camerasink.emit('pull-buffer')\n        if frame is None:\n            return\n        self._buffer = frame.data\n        if self._texturesize is None:\n            # try to get the camera image size\n            for x in self._decodebin.src_pads():\n                for cap in x.get_caps():\n                    self._texturesize = (cap['width'], cap['height'])\n                    Clock.schedule_once(self._update)\n                    return\n        Clock.schedule_once(self._update)\n\n    def start(self):\n        super(CameraPyGst, self).start()\n        self._pipeline.set_state(gst.STATE_PLAYING)\n\n    def stop(self):\n        super(CameraPyGst, self).stop()\n        self._pipeline.set_state(gst.STATE_PAUSED)\n\n    def _update(self, dt):\n        if self._buffer is None:\n            return\n        if self._texture is None and self._texturesize is not None:\n            self._texture = Texture.create(\n                size=self._texturesize, colorfmt='rgb')\n            self._texture.flip_vertical()\n            self.dispatch('on_load')\n        self._copy_to_gpu()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/camera/camera_videocapture.py",
    "content": "'''\nVideoCapture Camera: Implement CameraBase with VideoCapture\n'''\n\n#\n# TODO: make usage of thread or multiprocess\n#\n\n__all__ = ('CameraVideoCapture', )\n\nfrom kivy.core.camera import CameraBase\nfrom kivy.clock import Clock\n\ntry:\n    from VideoCapture import Device\nexcept:\n    raise\n\n\nclass CameraVideoCapture(CameraBase):\n    '''Implementation of CameraBase using VideoCapture\n    '''\n\n    def __init__(self, **kwargs):\n        self._device = None\n        super(CameraVideoCapture, self).__init__(**kwargs)\n        self._format = 'bgr'\n\n    def init_camera(self):\n        # create the device\n        self._device = Device(devnum=self._index, showVideoWindow=0)\n        # set resolution\n        try:\n            self._device.setResolution(self.resolution[0], self.resolution[1])\n        except:\n            raise Exception('VideoCapture: Resolution not supported')\n        self.fps = 1 / 30.\n\n    def _update(self, dt):\n        data, camera_width, camera_height = self._device.getBuffer()\n        if self._texture is None:\n            # first update, resize if necessary\n            self.size = camera_width, camera_height\n            # and create texture\n            from kivy.graphics.texture import Texture\n            self._texture = Texture.create(size=self.size, colorfmt='rgb')\n            self.dispatch('on_load')\n\n        # update buffer\n        self._buffer = data\n        self._copy_to_gpu()\n\n    def start(self):\n        super(CameraVideoCapture, self).start()\n        Clock.unschedule(self._update)\n        Clock.schedule_interval(self._update, self.fps)\n\n    def stop(self):\n        super(CameraVideoCapture, self).stop()\n        Clock.unschedule(self._update)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/clipboard/__init__.py",
    "content": "'''\nClipboard\n=========\n\nCore class for accessing the Clipboard. If we are not able to access the\nsystem clipboard, a fake one will be used.\n\nUsage example::\n\n    >>> from kivy.core.clipboard import Clipboard\n    >>> Clipboard.get_types()\n    ['TIMESTAMP', 'TARGETS', 'MULTIPLE', 'SAVE_TARGETS', 'UTF8_STRING',\n    'COMPOUND_TEXT', 'TEXT', 'STRING', 'text/plain;charset=utf-8',\n    'text/plain']\n    >>> Clipboard.get('TEXT')\n    'Hello World'\n    >>> Clipboard.put('Great', 'UTF8_STRING')\n    >>> Clipboard.get_types()\n    ['UTF8_STRING']\n    >>> Clipboard.get('UTF8_STRING')\n    'Great'\n\n.. note:: The main implementation relies on Pygame and works well with\n          text/strings. Anything else might not work the same on all platforms.\n'''\n\n__all__ = ('ClipboardBase', 'Clipboard')\n\nfrom kivy.core import core_select_lib\nfrom kivy.utils import platform\nfrom kivy.setupconfig import USE_SDL2\n\n\nclass ClipboardBase(object):\n\n    def get(self, mimetype):\n        '''Get the current data in clipboard, using the mimetype if possible.\n        You not use this method directly. Use :meth:`paste` instead.\n        '''\n        return None\n\n    def put(self, data, mimetype):\n        '''Put data on the clipboard, and attach a mimetype.\n        You should not use this method directly. Use :meth:`copy` instead.\n        '''\n        pass\n\n    def get_types(self):\n        '''Return a list of supported mimetypes\n        '''\n        return []\n\n    def _ensure_clipboard(self):\n        ''' Ensure that the clipboard has been properly initialised.\n        '''\n\n        if hasattr(self, '_clip_mime_type'):\n            return\n\n        if platform == 'win':\n            self._clip_mime_type = 'text/plain;charset=utf-8'\n            # windows clipboard uses a utf-16 little endian encoding\n            self._encoding = 'utf-16-le'\n        elif platform == 'linux':\n            self._clip_mime_type = 'text/plain;charset=utf-8'\n            self._encoding = 'utf-8'\n        else:\n            self._clip_mime_type = 'text/plain'\n            self._encoding = 'utf-8'\n\n    def copy(self, data=''):\n        ''' Copy the value provided in argument `data` into current clipboard.\n        If data is not of type string it will be converted to string.\n\n        .. versionadded:: 1.9.0\n\n        '''\n        if data:\n            self._copy(data)\n\n    def paste(self):\n        ''' Get text from the system clipboard and return it a usable string.\n\n        .. versionadded:: 1.9.0\n\n        '''\n        return self._paste()\n\n    def _copy(self, data):\n        # explicitly terminate strings with a null character\n        # so as to avoid putting spurious data after the end.\n        # MS windows issue.\n        self._ensure_clipboard()\n        if not isinstance(data, bytes):\n            data = data.encode(self._encoding)\n        if platform == 'win':\n            data += b'\\x00'\n        self.put(data, self._clip_mime_type)\n\n    def _paste(self):\n        self._ensure_clipboard()\n        _clip_types = Clipboard.get_types()\n\n        mime_type = self._clip_mime_type\n        if mime_type not in _clip_types:\n            mime_type = 'text/plain'\n\n        data = self.get(mime_type)\n        if data is not None:\n            # decode only if we don't have unicode\n            # we would still need to decode from utf-16 (windows)\n            # data is of type bytes in PY3\n            if isinstance(data, bytes):\n                data = data.decode(self._encoding, 'ignore')\n            # remove null strings mostly a windows issue\n            data = data.replace(u'\\x00', u'')\n            return data\n        return u''\n\n\n# load clipboard implementation\n_clipboards = []\nif platform == 'android':\n    _clipboards.append(\n        ('android', 'clipboard_android', 'ClipboardAndroid'))\nelif platform == 'macosx':\n    _clipboards.append(\n        ('nspaste', 'clipboard_nspaste', 'ClipboardNSPaste'))\nelif platform == 'win':\n    _clipboards.append(\n        ('winctypes', 'clipboard_winctypes', 'ClipboardWindows'))\nelif platform == 'linux':\n    _clipboards.append(\n        ('dbusklipper', 'clipboard_dbusklipper', 'ClipboardDbusKlipper'))\n    _clipboards.append(\n        ('gtk3', 'clipboard_gtk3', 'ClipboardGtk3'))\n    _clipboards.append(\n        ('xsel', 'clipboard_xsel', 'ClipboardXsel'))\n\nif USE_SDL2:\n    if platform != 'linux':\n        _clipboards.append(\n            ('sdl2', 'clipboard_sdl2', 'ClipboardSDL2'))\nelse:\n    _clipboards.append(\n        ('pygame', 'clipboard_pygame', 'ClipboardPygame'))\n\n_clipboards.append(\n    ('dummy', 'clipboard_dummy', 'ClipboardDummy'))\n\nClipboard = core_select_lib('clipboard', _clipboards, True)\n\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/clipboard/clipboard_android.py",
    "content": "'''\nClipboard Android\n=================\n\nAndroid implementation of Clipboard provider, using Pyjnius.\n'''\n\n__all__ = ('ClipboardAndroid', )\n\nfrom kivy.core.clipboard import ClipboardBase\nfrom jnius import autoclass\nfrom android.runnable import run_on_ui_thread\n\nAndroidString = autoclass('java.lang.String')\nPythonActivity = autoclass('org.renpy.android.PythonActivity')\nContext = autoclass('android.content.Context')\nVER = autoclass('android.os.Build$VERSION')\nsdk = VER.SDK_INT\n\n\nclass ClipboardAndroid(ClipboardBase):\n\n    def __init__(self):\n        super(ClipboardAndroid, self).__init__()\n        self._clipboard = None\n        self._data = dict()\n        self._data['text/plain'] = None\n        self._data['application/data'] = None\n        PythonActivity._clipboard = None\n\n    def get(self, mimetype='text/plain'):\n        return self._get(mimetype)\n\n    def put(self, data, mimetype='text/plain'):\n        self._set(data, mimetype)\n\n    def get_types(self):\n        return list(self._data.keys())\n\n    @run_on_ui_thread\n    def _initialize_clipboard(self):\n        PythonActivity._clipboard = PythonActivity.getSystemService(\n            Context.CLIPBOARD_SERVICE)\n\n    def _get_clipboard(f):\n        def called(*args, **kargs):\n            self = args[0]\n            if not PythonActivity._clipboard:\n                self._initialize_clipboard()\n                import time\n                while not PythonActivity._clipboard:\n                    time.sleep(.01)\n            return f(*args, **kargs)\n        return called\n\n    @_get_clipboard\n    def _get(self, mimetype='text/plain'):\n        clippy = PythonActivity._clipboard\n        if sdk < 11:\n            data = clippy.getText()\n        else:\n            ClipDescription = autoclass('android.content.ClipDescription')\n            primary_clip = clippy.getPrimaryClip()\n            if primary_clip and clippy.getPrimaryClipDescription().hasMimeType(\n                    ClipDescription.MIMETYPE_TEXT_PLAIN):\n                data = primary_clip.getItemAt(0).getText().toString()\n            else:\n                # TODO: non text data types Not yet implemented\n                data = ''\n        return data\n\n    @_get_clipboard\n    def _set(self, data, mimetype):\n        clippy = PythonActivity._clipboard\n\n        if sdk < 11:\n            #versions previous to honeycomb\n            clippy.setText(AndroidString(data))\n        else:\n            ClipData = autoclass('android.content.ClipData')\n            new_clip = ClipData.newPlainText(AndroidString(\"\"),\n                                         AndroidString(data))\n            # put text data onto clipboard\n            clippy.setPrimaryClip(new_clip)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/clipboard/clipboard_dbusklipper.py",
    "content": "'''\nClipboard Dbus: an implementation of the Clipboard using dbus and klipper.\n'''\n\n__all__ = ('ClipboardDbusKlipper', )\n\nfrom kivy.utils import platform\nfrom kivy.core.clipboard import ClipboardBase\n\nif platform != 'linux':\n    raise SystemError('unsupported platform for dbus kde clipboard')\n\ntry:\n    import dbus\n    bus = dbus.SessionBus()\n    proxy = bus.get_object(\"org.kde.klipper\", \"/klipper\")\nexcept:\n    raise\n\n\nclass ClipboardDbusKlipper(ClipboardBase):\n\n    _is_init = False\n\n    def init(self):\n        if ClipboardDbusKlipper._is_init:\n            return\n        self.iface = dbus.Interface(proxy, \"org.kde.klipper.klipper\")\n        ClipboardDbusKlipper._is_init = True\n\n    def get(self, mimetype='text/plain'):\n        self.init()\n        return str(self.iface.getClipboardContents())\n\n    def put(self, data, mimetype='text/plain'):\n        self.init()\n        self.iface.setClipboardContents(data.replace('\\x00', ''))\n\n    def get_types(self):\n        self.init()\n        return [u'text/plain']\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/clipboard/clipboard_dummy.py",
    "content": "'''\nClipboard Dummy: an internal implementation that does not use the system\nclipboard.\n'''\n\n__all__ = ('ClipboardDummy', )\n\nfrom kivy.core.clipboard import ClipboardBase\n\n\nclass ClipboardDummy(ClipboardBase):\n\n    def __init__(self):\n        super(ClipboardDummy, self).__init__()\n        self._data = dict()\n        self._data['text/plain'] = None\n        self._data['application/data'] = None\n\n    def get(self, mimetype='text/plain'):\n        return self._data.get(mimetype, None)\n\n    def put(self, data, mimetype='text/plain'):\n        self._data[mimetype] = data\n\n    def get_types(self):\n        return list(self._data.keys())\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/clipboard/clipboard_gtk3.py",
    "content": "'''\nClipboard Gtk3: an implementation of the Clipboard using Gtk3.\n'''\n\n__all__ = ('ClipboardGtk3',)\n\nfrom kivy.utils import platform\nfrom kivy.support import install_gobject_iteration\nfrom kivy.core.clipboard import ClipboardBase\n\nif platform != 'linux':\n    raise SystemError('unsupported platform for gtk3 clipboard')\n\nfrom gi.repository import Gtk, Gdk\nclipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)\n\n\nclass ClipboardGtk3(ClipboardBase):\n\n    _is_init = False\n\n    def init(self):\n        if self._is_init:\n            return\n        install_gobject_iteration()\n        self._is_init = True\n\n    def get(self, mimetype='text/plain;charset=utf-8'):\n        self.init()\n        if mimetype == 'text/plain;charset=utf-8':\n            contents = clipboard.wait_for_text()\n            if contents:\n                return contents\n        return ''\n\n    def put(self, data, mimetype='text/plain;charset=utf-8'):\n        self.init()\n        if mimetype == 'text/plain;charset=utf-8':\n            text = data.decode(self._encoding)\n            clipboard.set_text(text, -1)\n\n    def get_types(self):\n        self.init()\n        return ['text/plain;charset=utf-8']\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/clipboard/clipboard_nspaste.py",
    "content": "'''\nClipboard OsX: implementation of clipboard using Appkit\n'''\n\n__all__ = ('ClipboardNSPaste', )\n\nfrom kivy.core.clipboard import ClipboardBase\nfrom kivy.utils import platform\n\nif platform != 'macosx':\n    raise SystemError('Unsupported platform for appkit clipboard.')\ntry:\n    from pyobjus import autoclass\n    from pyobjus.dylib_manager import load_framework, INCLUDE\n    load_framework(INCLUDE.AppKit)\nexcept ImportError:\n    raise SystemError('Pyobjus not installed. Please run the following'\n        ' command to install it. `pip install --user pyobjus`')\n\nNSPasteboard = autoclass('NSPasteboard')\nNSString = autoclass('NSString')\n\n\nclass ClipboardNSPaste(ClipboardBase):\n\n    def __init__(self):\n        super(ClipboardNSPaste, self).__init__()\n        self._clipboard = NSPasteboard.generalPasteboard()\n\n    def get(self, mimetype='text/plain'):\n        pb = self._clipboard\n        data = pb.stringForType_('public.utf8-plain-text')\n        if not data:\n            return \"\"\n        return data.UTF8String()\n\n    def put(self, data, mimetype='text/plain'):\n        pb = self._clipboard\n        pb.clearContents()\n        pb.writeObjects_([data])\n\n    def get_types(self):\n        return list('text/plain',)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/clipboard/clipboard_pygame.py",
    "content": "'''\nClipboard Pygame: an implementation of the Clipboard using pygame.scrap.\n'''\n\n__all__ = ('ClipboardPygame', )\n\nfrom kivy.utils import platform\nfrom kivy.compat import PY2\nfrom kivy.core.clipboard import ClipboardBase\n\nif platform not in ('win', 'linux', 'macosx'):\n    raise SystemError('unsupported platform for pygame clipboard')\n\ntry:\n    import pygame\n    import pygame.scrap\nexcept:\n    raise\n\n\nclass ClipboardPygame(ClipboardBase):\n\n    _is_init = False\n    _types = None\n\n    _aliases = {\n        'text/plain;charset=utf-8': 'UTF8_STRING'\n    }\n\n    def init(self):\n        if ClipboardPygame._is_init:\n            return\n        pygame.scrap.init()\n        ClipboardPygame._is_init = True\n\n    def get(self, mimetype='text/plain'):\n        self.init()\n        mimetype = self._aliases.get(mimetype, mimetype)\n        text = pygame.scrap.get(mimetype)\n        return text\n\n    def put(self, data, mimetype='text/plain'):\n        self.init()\n        mimetype = self._aliases.get(mimetype, mimetype)\n        pygame.scrap.put(mimetype, data)\n\n    def get_types(self):\n        if not self._types:\n            self.init()\n            types = pygame.scrap.get_types()\n            for mime, pygtype in self._aliases.items()[:]:\n                if mime in types:\n                    del self._aliases[mime]\n                if pygtype in types:\n                    types.append(mime)\n            self._types = types\n        return self._types\n\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/clipboard/clipboard_sdl2.py",
    "content": "'''\nClipboard SDL2: an implementation of the Clipboard using sdl2.\n'''\n\n__all__ = ('ClipboardSDL2', )\n\nfrom kivy.utils import platform\nfrom kivy.core.clipboard import ClipboardBase\n\nif platform not in ('win', 'linux', 'macosx', 'android', 'ios'):\n    raise SystemError('unsupported platform for sdl2 clipboard')\n\ntry:\n    from kivy.core.clipboard._clipboard_sdl2 import (\n        _get_text, _has_text, _set_text)\nexcept ImportError:\n    raise SystemError('extension not compiled?')\n\n\nclass ClipboardSDL2(ClipboardBase):\n\n    def get(self, mimetype):\n        return _get_text() if _has_text() else ''\n\n    def _ensure_clipboard(self):\n        super(ClipboardSDL2, self)._ensure_clipboard()\n        self._encoding = 'utf8'\n\n    def put(self, data=b'', mimetype='text/plain'):\n        _set_text(data)\n\n    def get_types(self):\n        return ['text/plain']\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/clipboard/clipboard_winctypes.py",
    "content": "'''\nClipboard windows: an implementation of the Clipboard using ctypes.\n'''\n\n__all__ = ('ClipboardWindows', )\n\nfrom kivy.utils import platform\nfrom kivy.core.clipboard import ClipboardBase\n\nif platform != 'win':\n    raise SystemError('unsupported platform for Windows clipboard')\n\nimport ctypes\nuser32 = ctypes.windll.user32\nkernel32 = ctypes.windll.kernel32\nmsvcrt = ctypes.cdll.msvcrt\nc_char_p = ctypes.c_char_p\nc_wchar_p = ctypes.c_wchar_p\n\n\nclass ClipboardWindows(ClipboardBase):\n\n    def get(self, mimetype='text/plain'):\n        user32.OpenClipboard(0)\n        # 1 is CF_TEXT\n        pcontents = user32.GetClipboardData(13)\n        if not pcontents:\n            return ''\n        data = c_wchar_p(pcontents).value.encode(self._encoding)\n        #ctypes.windll.kernel32.GlobalUnlock(pcontents)\n        user32.CloseClipboard()\n        return data\n\n    def put(self, text, mimetype='text/plain'):\n        GMEM_DDESHARE = 0x2000\n        CF_UNICODETEXT = 13\n        user32.OpenClipboard(None)\n        user32.EmptyClipboard()\n        hCd = kernel32.GlobalAlloc(GMEM_DDESHARE, len(text) + 2)\n        pchData = kernel32.GlobalLock(hCd)\n        msvcrt.wcscpy(c_wchar_p(pchData), text)\n        kernel32.GlobalUnlock(hCd)\n        user32.SetClipboardData(CF_UNICODETEXT, hCd)\n        user32.CloseClipboard()\n\n    def get_types(self):\n        return list('text/plain',)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/clipboard/clipboard_xsel.py",
    "content": "'''\nClipboard xsel: an implementation of the Clipboard using xsel command line tool.\n'''\n\n__all__ = ('ClipboardXsel', )\n\nfrom kivy.utils import platform\nfrom kivy.core.clipboard import ClipboardBase\n\nif platform != 'linux':\n    raise SystemError('unsupported platform for xsel clipboard')\n\ntry:\n    import subprocess\n    p = subprocess.Popen(['xsel'], stdout=subprocess.PIPE)\n    p.communicate()\nexcept:\n    raise\n\n\nclass ClipboardXsel(ClipboardBase):\n\n    def get(self, mimetype='text/plain'):\n        p = subprocess.Popen(['xsel', '-bo'], stdout=subprocess.PIPE)\n        data, _ = p.communicate()\n        return data\n\n    def put(self, data, mimetype='text/plain'):\n        p = subprocess.Popen(['xsel', '-bi'], stdin=subprocess.PIPE)\n        p.communicate(data)\n\n    def get_types(self):\n        return [u'text/plain']\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/gl/__init__.py",
    "content": "# pylint: disable=W0611\n'''\nOpenGL\n======\n\nSelect and use the best OpenGL library available. Depending on your system, the\ncore provider can select an OpenGL ES or a 'classic' desktop OpenGL library.\n'''\n\nfrom os import environ\nfrom sys import platform as sysplatform, exit\n\n\nMIN_REQUIRED_GL_VERSION = (2, 0)\n\n\ndef msgbox(message):\n    if sysplatform == 'win32':\n        import ctypes\n        ctypes.windll.user32.MessageBoxW(\n                None, message, u\"Kivy Fatal Error\", 0)\n        exit(1)\n\nif 'KIVY_DOC' not in environ:\n\n    from kivy.logger import Logger\n    from kivy.graphics import gl_init_resources\n    from kivy.graphics.opengl_utils import gl_get_version\n    from kivy.graphics.opengl import GL_VERSION, GL_VENDOR, GL_RENDERER, \\\n        GL_MAX_TEXTURE_IMAGE_UNITS, GL_MAX_TEXTURE_SIZE, \\\n        GL_SHADING_LANGUAGE_VERSION,\\\n        glGetString, glGetIntegerv, gl_init_symbols\n    from kivy.utils import platform\n\n    def init_gl():\n        gl_init_symbols()\n        print_gl_version()\n        gl_init_resources()\n\n    def print_gl_version():\n        version = glGetString(GL_VERSION)\n        vendor = glGetString(GL_VENDOR)\n        renderer = glGetString(GL_RENDERER)\n        Logger.info('GL: OpenGL version <{0}>'.format(version))\n        Logger.info('GL: OpenGL vendor <{0}>'.format(vendor))\n        Logger.info('GL: OpenGL renderer <{0}>'.format(renderer))\n\n        # Let the user know if his graphics hardware/drivers are too old\n        major, minor = gl_get_version()\n        Logger.info('GL: OpenGL parsed version: %d, %d' % (major, minor))\n        if (major, minor) < MIN_REQUIRED_GL_VERSION:\n            msg = (\n                'GL: Minimum required OpenGL version (2.0) NOT found!\\n\\n'\n                'OpenGL version detected: {0}.{1}\\n\\n'\n                'Version: {2}\\nVendor: {3}\\nRenderer: {4}\\n\\n'\n                'Try upgrading your graphics drivers and/or your '\n                'graphics hardware in case of problems.\\n\\n'\n                'The application will leave now.').format(\n                    major, minor, version, vendor, renderer)\n            Logger.critical(msg)\n            msgbox(msg)\n\n        if platform != 'android':\n            # XXX in the android emulator (latest version at 22 march 2013),\n            # this call was segfaulting the gl stack.\n            Logger.info('GL: Shading version <{0}>'.format(\n                glGetString(GL_SHADING_LANGUAGE_VERSION)))\n        Logger.info('GL: Texture max size <{0}>'.format(\n            glGetIntegerv(GL_MAX_TEXTURE_SIZE)[0]))\n        Logger.info('GL: Texture max units <{0}>'.format(\n            glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS)[0]))\n\n    # To be able to use our GL provider, we must have a window\n    # Automaticly import window auto to ensure the default window creation\n    import kivy.core.window  # NOQA\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/image/__init__.py",
    "content": "'''\nImage\n=====\n\nCore classes for loading images and converting them to a\n:class:`~kivy.graphics.texture.Texture`. The raw image data can be keep in\nmemory for further access.\n\nIn-memory image loading\n-----------------------\n\n.. versionadded:: 1.9.0\n\n    Official support for in-memory loading. Not all the providers supports it,\n    but at the moment, pygame, pil and imageio works.\n\nTo load an image with a filename, you usually do::\n\n    from kivy.core.image import Image as CoreImage\n    im = CoreImage(\"image.png\")\n\nNow you can load from memory block. Instead of passing the filename, you'll need\nto pass the data as a BytesIO object + an \"ext\" parameters. Both are mandatory::\n\n    import io\n    from kivy.core.image import Image as CoreImage\n    data = io.BytesIO(open(\"image.png\", \"rb\").read())\n    im = CoreImage(data, ext=\"png\")\n\nBy default, the image will not be cached, as our internal cache require a\nfilename. If you want caching, add a filename that represent your file (it will\nbe used only for caching)::\n\n    import io\n    from kivy.core.image import Image as CoreImage\n    data = io.BytesIO(open(\"image.png\", \"rb\").read())\n    im = CoreImage(data, ext=\"png\", filename=\"image.png\")\n\n'''\n\n__all__ = ('Image', 'ImageLoader', 'ImageData')\n\nfrom kivy.event import EventDispatcher\nfrom kivy.core import core_register_libs\nfrom kivy.logger import Logger\nfrom kivy.cache import Cache\nfrom kivy.clock import Clock\nfrom kivy.atlas import Atlas\nfrom kivy.resources import resource_find\nfrom kivy.utils import platform\nfrom kivy.compat import string_types\nfrom kivy.setupconfig import USE_SDL2\nimport zipfile\nfrom io import BytesIO\n\n\n# late binding\nTexture = TextureRegion = None\n\n\n# register image caching only for keep_data=True\nCache.register('kv.image', timeout=60)\nCache.register('kv.atlas')\n\n\nclass ImageData(object):\n    '''Container for images and mipmap images.\n    The container will always have at least the mipmap level 0.\n    '''\n\n    __slots__ = ('fmt', 'mipmaps', 'source', 'flip_vertical', 'source_image')\n    _supported_fmts = ('rgb', 'rgba', 'bgr', 'bgra', 's3tc_dxt1', 's3tc_dxt3',\n                       's3tc_dxt5', 'pvrtc_rgb2', 'pvrtc_rgb4', 'pvrtc_rgba2',\n                       'pvrtc_rgba4', 'etc1_rgb8')\n\n    def __init__(self, width, height, fmt, data, source=None,\n                 flip_vertical=True, source_image=None,\n                 rowlength=0):\n        assert fmt in ImageData._supported_fmts\n\n        #: Decoded image format, one of a available texture format\n        self.fmt = fmt\n\n        #: Data for each mipmap.\n        self.mipmaps = {}\n        self.add_mipmap(0, width, height, data, rowlength)\n\n        #: Image source, if available\n        self.source = source\n\n        #: Indicate if the texture will need to be vertically flipped\n        self.flip_vertical = flip_vertical\n\n        # the original image, which we might need to save if it is a memoryview\n        self.source_image = source_image\n\n    def release_data(self):\n        mm = self.mipmaps\n        for item in mm.values():\n            item[2] = None\n            self.source_image = None\n\n    @property\n    def width(self):\n        '''Image width in pixels.\n        (If the image is mipmapped, it will use the level 0)\n        '''\n        return self.mipmaps[0][0]\n\n    @property\n    def height(self):\n        '''Image height in pixels.\n        (If the image is mipmapped, it will use the level 0)\n        '''\n        return self.mipmaps[0][1]\n\n    @property\n    def data(self):\n        '''Image data.\n        (If the image is mipmapped, it will use the level 0)\n        '''\n        return self.mipmaps[0][2]\n\n    @property\n    def rowlength(self):\n        '''Image rowlength.\n        (If the image is mipmapped, it will use the level 0)\n\n        .. versionadded:: 1.9.0\n        '''\n        return self.mipmaps[0][3]\n\n    @property\n    def size(self):\n        '''Image (width, height) in pixels.\n        (If the image is mipmapped, it will use the level 0)\n        '''\n        mm = self.mipmaps[0]\n        return mm[0], mm[1]\n\n    @property\n    def have_mipmap(self):\n        return len(self.mipmaps) > 1\n\n    def __repr__(self):\n        return ('<ImageData width=%d height=%d fmt=%s '\n                'source=%r with %d images>' % (\n                    self.width, self.height, self.fmt,\n                    self.source, len(self.mipmaps)))\n\n    def add_mipmap(self, level, width, height, data, rowlength):\n        '''Add a image for a specific mipmap level.\n\n        .. versionadded:: 1.0.7\n        '''\n        self.mipmaps[level] = [int(width), int(height), data, rowlength]\n\n    def get_mipmap(self, level):\n        '''Get the mipmap image at a specific level if it exists\n\n        .. versionadded:: 1.0.7\n        '''\n        if level == 0:\n            return (self.width, self.height, self.data, self.rowlength)\n        assert(level < len(self.mipmaps))\n        return self.mipmaps[level]\n\n    def iterate_mipmaps(self):\n        '''Iterate over all mipmap images available.\n\n        .. versionadded:: 1.0.7\n        '''\n        mm = self.mipmaps\n        for x in range(len(mm)):\n            item = mm.get(x, None)\n            if item is None:\n                raise Exception('Invalid mipmap level, found empty one')\n            yield x, item[0], item[1], item[2], item[3]\n\n\nclass ImageLoaderBase(object):\n    '''Base to implement an image loader.'''\n\n    __slots__ = ('_texture', '_data', 'filename', 'keep_data',\n                 '_mipmap', '_nocache', '_ext', '_inline')\n\n    def __init__(self, filename, **kwargs):\n        self._mipmap = kwargs.get('mipmap', False)\n        self.keep_data = kwargs.get('keep_data', False)\n        self._nocache = kwargs.get('nocache', False)\n        self._ext = kwargs.get('ext')\n        self._inline = kwargs.get('inline')\n        self.filename = filename\n        if self._inline:\n            self._data = self.load(kwargs.get('rawdata'))\n        else:\n            self._data = self.load(filename)\n        self._textures = None\n\n    def load(self, filename):\n        '''Load an image'''\n        return None\n\n    @staticmethod\n    def can_save():\n        '''Indicate if the loader can save the Image object\n        '''\n        return False\n\n    @staticmethod\n    def can_load_memory():\n        '''Indicate if the loader can load an image by passing data\n        '''\n        return False\n\n    @staticmethod\n    def save():\n        raise NotImplementedError()\n\n    def populate(self):\n        self._textures = []\n        fname = self.filename\n        if __debug__:\n            Logger.trace('Image: %r, populate to textures (%d)' %\n                         (fname, len(self._data)))\n\n        for count in range(len(self._data)):\n\n            # first, check if a texture with the same name already exist in the\n            # cache\n            chr = type(fname)\n            uid = chr(u'%s|%d|%d') % (fname, self._mipmap, count)\n            texture = Cache.get('kv.texture', uid)\n\n            # if not create it and append to the cache\n            if texture is None:\n                imagedata = self._data[count]\n                source = '{}{}|'.format(\n                    'zip|' if fname.endswith('.zip') else '',\n                    self._nocache)\n                imagedata.source = chr(source) + uid\n                texture = Texture.create_from_data(\n                    imagedata, mipmap=self._mipmap)\n                if not self._nocache:\n                    Cache.append('kv.texture', uid, texture)\n                if imagedata.flip_vertical:\n                    texture.flip_vertical()\n\n            # set as our current texture\n            self._textures.append(texture)\n\n            # release data if ask\n            if not self.keep_data:\n                self._data[count].release_data()\n\n    @property\n    def width(self):\n        '''Image width\n        '''\n        return self._data[0].width\n\n    @property\n    def height(self):\n        '''Image height\n        '''\n        return self._data[0].height\n\n    @property\n    def size(self):\n        '''Image size (width, height)\n        '''\n        return (self._data[0].width, self._data[0].height)\n\n    @property\n    def texture(self):\n        '''Get the image texture (created on the first call)\n        '''\n        if self._textures is None:\n            self.populate()\n        if self._textures is None:\n            return None\n        return self._textures[0]\n\n    @property\n    def textures(self):\n        '''Get the textures list (for mipmapped image or animated image)\n\n        .. versionadded:: 1.0.8\n        '''\n        if self._textures is None:\n            self.populate()\n        return self._textures\n\n    @property\n    def nocache(self):\n        '''Indicate if the texture will not be stored in the cache\n\n        .. versionadded:: 1.6.0\n        '''\n        return self._nocache\n\n\nclass ImageLoader(object):\n\n    loaders = []\n\n    @staticmethod\n    def zip_loader(filename, **kwargs):\n        '''Read images from an zip file.\n\n        .. versionadded:: 1.0.8\n\n        Returns an Image with a list of type ImageData stored in Image._data\n        '''\n        # read zip in menory for faster access\n        _file = BytesIO(open(filename, 'rb').read())\n        # read all images inside the zip\n        z = zipfile.ZipFile(_file)\n        image_data = []\n        # sort filename list\n        znamelist = z.namelist()\n        znamelist.sort()\n        image = None\n        for zfilename in znamelist:\n            try:\n                #read file and store it in mem with fileIO struct around it\n                tmpfile = BytesIO(z.read(zfilename))\n                ext = zfilename.split('.')[-1].lower()\n                im = None\n                for loader in ImageLoader.loaders:\n                    if (ext not in loader.extensions()\n                        or not loader.can_load_memory()):\n                        continue\n                    Logger.debug('Image%s: Load <%s> from <%s>' %\n                                 (loader.__name__[11:], zfilename, filename))\n                    try:\n                        im = loader(zfilename, ext=ext, rawdata=tmpfile,\n                                    inline=True, **kwargs)\n                    except:\n                        # Loader failed, continue trying.\n                        continue\n                    break\n                if im is not None:\n                    # append ImageData to local variable before it's\n                    # overwritten\n                    image_data.append(im._data[0])\n                    image = im\n                #else: if not image file skip to next\n            except:\n                Logger.warning('Image: Unable to load image'\n                               '<%s> in zip <%s> trying to continue...'\n                               % (zfilename, filename))\n        z.close()\n        if len(image_data) == 0:\n            raise Exception('no images in zip <%s>' % filename)\n        # replace Image.Data with the array of all the images in the zip\n        image._data = image_data\n        image.filename = filename\n        return image\n\n    @staticmethod\n    def register(defcls):\n        ImageLoader.loaders.append(defcls)\n\n    @staticmethod\n    def load(filename, **kwargs):\n\n        # atlas ?\n        if filename[:8] == 'atlas://':\n            # remove the url\n            rfn = filename[8:]\n            # last field is the ID\n            try:\n                rfn, uid = rfn.rsplit('/', 1)\n            except ValueError:\n                raise ValueError(\n                    'Image: Invalid %s name for atlas' % filename)\n\n            # search if we already got the atlas loaded\n            atlas = Cache.get('kv.atlas', rfn)\n\n            # atlas already loaded, so reupload the missing texture in cache,\n            # because when it's not in use, the texture can be removed from the\n            # kv.texture cache.\n            if atlas:\n                texture = atlas[uid]\n                fn = 'atlas://%s/%s' % (rfn, uid)\n                cid = '{}|{:d}|{:d}'.format(fn, False, 0)\n                Cache.append('kv.texture', cid, texture)\n                return Image(texture)\n\n            # search with resource\n            afn = rfn\n            if not afn.endswith('.atlas'):\n                afn += '.atlas'\n            afn = resource_find(afn)\n            if not afn:\n                raise Exception('Unable to found %r atlas' % afn)\n            atlas = Atlas(afn)\n            Cache.append('kv.atlas', rfn, atlas)\n            # first time, fill our texture cache.\n            for nid, texture in atlas.textures.items():\n                fn = 'atlas://%s/%s' % (rfn, nid)\n                cid = '{}|{:d}|{:d}'.format(fn, False, 0)\n                Cache.append('kv.texture', cid, texture)\n            return Image(atlas[uid])\n\n        # extract extensions\n        ext = filename.split('.')[-1].lower()\n\n        # prevent url querystrings\n        if filename.startswith((('http://', 'https://'))):\n            ext = ext.split('?')[0]\n\n        filename = resource_find(filename)\n\n        # special case. When we are trying to load a \"zip\" file with image, we\n        # will use the special zip_loader in ImageLoader. This might return a\n        # sequence of images contained in the zip.\n        if ext == 'zip':\n            return ImageLoader.zip_loader(filename)\n        else:\n            im = None\n            for loader in ImageLoader.loaders:\n                if ext not in loader.extensions():\n                    continue\n                Logger.debug('Image%s: Load <%s>' %\n                             (loader.__name__[11:], filename))\n                im = loader(filename, **kwargs)\n                break\n            if im is None:\n                raise Exception('Unknown <%s> type, no loader found.' % ext)\n            return im\n\n\nclass Image(EventDispatcher):\n    '''Load an image and store the size and texture.\n\n    .. versionchanged:: 1.0.7\n\n        `mipmap` attribute has been added. The `texture_mipmap` and\n        `texture_rectangle` have been deleted.\n\n    .. versionchanged:: 1.0.8\n\n        An Image widget can change its texture. A new event 'on_texture' has\n        been introduced. New methods for handling sequenced animation have been\n        added.\n\n    :Parameters:\n        `arg` : can be a string (str), Texture or Image object.\n            A string is interpreted as a path to the image to be loaded.\n            You can also provide a texture object or an already existing\n            image object. In the latter case, a real copy of the given\n            image object will be returned.\n        `keep_data` : bool, defaults to False.\n            Keep the image data when the texture is created.\n        `scale` : float, defaults to 1.0\n            Scale of the image.\n        `mipmap` : bool, defaults to False\n            Create mipmap for the texture.\n        `anim_delay`: float, defaults to .25\n            Delay in seconds between each animation frame. Lower values means\n            faster animation.\n    '''\n\n    copy_attributes = ('_size', '_filename', '_texture', '_image',\n                       '_mipmap', '_nocache')\n\n    def __init__(self, arg, **kwargs):\n        # this event should be fired on animation of sequenced img's\n        self.register_event_type('on_texture')\n\n        super(Image, self).__init__()\n\n        self._mipmap = kwargs.get('mipmap', False)\n        self._keep_data = kwargs.get('keep_data', False)\n        self._nocache = kwargs.get('nocache', False)\n        self._size = [0, 0]\n        self._image = None\n        self._filename = None\n        self._texture = None\n        self._anim_available = False\n        self._anim_index = 0\n        self._anim_delay = 0\n        self.anim_delay = kwargs.get('anim_delay', .25)\n        # indicator of images having been loded in cache\n        self._iteration_done = False\n\n        if isinstance(arg, Image):\n            for attr in Image.copy_attributes:\n                self.__setattr__(attr, arg.__getattribute__(attr))\n        elif type(arg) in (Texture, TextureRegion):\n            if not hasattr(self, 'textures'):\n                self.textures = []\n                self.textures.append(arg)\n            self._texture = arg\n            self._size = self.texture.size\n        elif isinstance(arg, ImageLoaderBase):\n            self.image = arg\n        elif isinstance(arg, BytesIO):\n            ext = kwargs.get('ext', None)\n            if not ext:\n                raise Exception('Inline loading require \"ext\" parameter')\n            filename = kwargs.get('filename')\n            if not filename:\n                self._nocache = True\n                filename = '__inline__'\n            self.load_memory(arg, ext, filename)\n        elif isinstance(arg, string_types):\n            self.filename = arg\n        else:\n            raise Exception('Unable to load image type {0!r}'.format(arg))\n\n    def remove_from_cache(self):\n        '''Remove the Image from cache. This facilitates re-loading of\n        images from disk in case the image content has changed.\n\n        .. versionadded:: 1.3.0\n\n        Usage::\n\n            im = CoreImage('1.jpg')\n            # -- do something --\n            im.remove_from_cache()\n            im = CoreImage('1.jpg')\n            # this time image will be re-loaded from disk\n\n        '''\n        count = 0\n        f = self.filename\n        pat = type(f)(u'%s|%d|%d')\n        uid = pat % (f, self._mipmap, count)\n        Cache.remove(\"kv.image\", uid)\n        while Cache.get(\"kv.texture\", uid):\n            Cache.remove(\"kv.texture\", uid)\n            count += 1\n            uid = pat % (f, self._mipmap, count)\n\n    def _anim(self, *largs):\n        if not self._image:\n            return\n        textures = self.image.textures\n        if self._anim_index >= len(textures):\n            self._anim_index = 0\n        self._texture = self.image.textures[self._anim_index]\n        self.dispatch('on_texture')\n        self._anim_index += 1\n        self._anim_index %= len(self._image.textures)\n\n    def anim_reset(self, allow_anim):\n        '''Reset an animation if available.\n\n        .. versionadded:: 1.0.8\n\n        :Parameters:\n            `allow_anim`: bool\n                Indicate whether the animation should restart playing or not.\n\n        Usage::\n\n            # start/reset animation\n            image.anim_reset(True)\n\n            # or stop the animation\n            image.anim_reset(False)\n\n        You can change the animation speed whilst it is playing::\n\n            # Set to 20 FPS\n            image.anim_delay = 1 / 20.\n\n        '''\n        # stop animation\n        Clock.unschedule(self._anim)\n        if allow_anim and self._anim_available:\n            Clock.schedule_interval(self._anim, self.anim_delay)\n            self._anim()\n\n    def _get_anim_delay(self):\n        return self._anim_delay\n\n    def _set_anim_delay(self, x):\n        if self._anim_delay == x:\n            return\n        self._anim_delay = x\n        if self._anim_available:\n            Clock.unschedule(self._anim)\n            if self._anim_delay >= 0:\n                Clock.schedule_interval(self._anim, self._anim_delay)\n\n    anim_delay = property(_get_anim_delay, _set_anim_delay)\n    '''Delay between each animation frame. A lower value means faster\n    animation.\n\n    .. versionadded:: 1.0.8\n    '''\n\n    @property\n    def anim_available(self):\n        '''Return True if this Image instance has animation available.\n\n        .. versionadded:: 1.0.8\n        '''\n        return self._anim_available\n\n    @property\n    def anim_index(self):\n        '''Return the index number of the image currently in the texture.\n\n        .. versionadded:: 1.0.8\n        '''\n        return self._anim_index\n\n    def _img_iterate(self, *largs):\n        if not self.image or self._iteration_done:\n            return\n        self._iteration_done = True\n        imgcount = len(self.image.textures)\n        if imgcount > 1:\n            self._anim_available = True\n            self.anim_reset(True)\n        self._texture = self.image.textures[0]\n\n    def on_texture(self, *largs):\n        '''This event is fired when the texture reference or content has\n           changed. It is normally used for sequenced images.\n\n        .. versionadded:: 1.0.8\n        '''\n        pass\n\n    @staticmethod\n    def load(filename, **kwargs):\n        '''Load an image\n\n        :Parameters:\n            `filename` : str\n                Filename of the image.\n            `keep_data` : bool, defaults to False\n                Keep the image data when the texture is created.\n        '''\n        kwargs.setdefault('keep_data', False)\n        return Image(filename, **kwargs)\n\n    def _get_image(self):\n        return self._image\n\n    def _set_image(self, image):\n        self._image = image\n        if hasattr(image, 'filename'):\n            self._filename = image.filename\n        if image:\n            self._size = (self.image.width, self.image.height)\n\n    image = property(_get_image, _set_image,\n                     doc='Get/set the data image object')\n\n    def _get_filename(self):\n        return self._filename\n\n    def _set_filename(self, value):\n        if value is None or value == self._filename:\n            return\n        self._filename = value\n\n        # construct uid as a key for Cache\n        f = self.filename\n        uid = type(f)(u'%s|%d|%d') % (f, self._mipmap, 0)\n\n        # in case of Image have been asked with keep_data\n        # check the kv.image cache instead of texture.\n        image = Cache.get('kv.image', uid)\n        if image:\n            # we found an image, yeah ! but reset the texture now.\n            self.image = image\n            # if image.__class__ is core image then it's a texture\n            # from atlas or other sources and has no data so skip\n            if (image.__class__ != self.__class__ and\n                    not image.keep_data and self._keep_data):\n                self.remove_from_cache()\n                self._filename = ''\n                self._set_filename(value)\n            else:\n                self._texture = None\n                self._img_iterate()\n            return\n        else:\n            # if we already got a texture, it will be automatically reloaded.\n            _texture = Cache.get('kv.texture', uid)\n            if _texture:\n                self._texture = _texture\n                return\n\n        # if image not already in cache then load\n        tmpfilename = self._filename\n        image = ImageLoader.load(\n            self._filename, keep_data=self._keep_data,\n            mipmap=self._mipmap, nocache=self._nocache)\n        self._filename = tmpfilename\n        # put the image into the cache if needed\n        if isinstance(image, Texture):\n            self._texture = image\n            self._size = image.size\n        else:\n            self.image = image\n            if not self._nocache:\n                Cache.append('kv.image', uid, self.image)\n\n    filename = property(_get_filename, _set_filename,\n                        doc='Get/set the filename of image')\n\n    def load_memory(self, data, ext, filename='__inline__'):\n        '''(internal) Method to load an image from raw data.\n        '''\n        self._filename = filename\n\n        # see if there is a available loader for it\n        loaders = [loader for loader in ImageLoader.loaders if\n                   loader.can_load_memory() and\n                   ext in loader.extensions()]\n        if not loaders:\n            raise Exception('No inline loader found to load {}'.format(ext))\n        image = loaders[0](filename, ext=ext, rawdata=data, inline=True,\n                nocache=self._nocache, mipmap=self._mipmap,\n                keep_data=self._keep_data)\n        if isinstance(image, Texture):\n            self._texture = image\n            self._size = image.size\n        else:\n            self.image = image\n\n    @property\n    def size(self):\n        '''Image size (width, height)\n        '''\n        return self._size\n\n    @property\n    def width(self):\n        '''Image width\n        '''\n        return self._size[0]\n\n    @property\n    def height(self):\n        '''Image height\n        '''\n        return self._size[1]\n\n    @property\n    def texture(self):\n        '''Texture of the image'''\n        if self.image:\n            if not self._iteration_done:\n                self._img_iterate()\n        return self._texture\n\n    @property\n    def nocache(self):\n        '''Indicate whether the texture will not be stored in the cache or not.\n\n        .. versionadded:: 1.6.0\n        '''\n        return self._nocache\n\n    def save(self, filename, flipped=False):\n        '''Save image texture to file.\n\n        The filename should have the '.png' extension because the texture data\n        read from the GPU is in the RGBA format. '.jpg' might work but has not\n        been heavilly tested so some providers might break when using it.\n        Any other extensions are not officially supported.\n\n        The flipped parameter flips the saved image vertically, and\n        defaults to True.\n\n        Example::\n\n            # Save an core image object\n            from kivy.core.image import Image\n            img = Image('hello.png')\n            img.save('hello2.png')\n\n            # Save a texture\n            texture = Texture.create(...)\n            img = Image(texture)\n            img.save('hello3.png')\n\n        .. versionadded:: 1.7.0\n\n        .. versionchanged:: 1.8.0\n            Parameter `flipped` added to flip the image before saving, default\n            to False.\n\n        '''\n        pixels = None\n        size = None\n        loaders = [x for x in ImageLoader.loaders if x.can_save()]\n        if not loaders:\n            return False\n        loader = loaders[0]\n\n        if self.image:\n            # we might have a ImageData object to use\n            data = self.image._data[0]\n            if data.data is not None:\n                if data.fmt not in ('rgba', 'rgb'):\n                    # fast path, use the \"raw\" data when keep_data is used\n                    size = data.width, data.height\n                    pixels = data.data\n\n                else:\n                    # the format is not rgba, we need to convert it.\n                    # use texture for that.\n                    self.populate()\n\n        if pixels is None and self._texture:\n            # use the texture pixels\n            size = self._texture.size\n            pixels = self._texture.pixels\n\n        if pixels is None:\n            return False\n\n        l_pixels = len(pixels)\n        if l_pixels == size[0] * size[1] * 3:\n            fmt = 'rgb'\n        elif l_pixels == size[0] * size[1] * 4:\n            fmt = 'rgba'\n        else:\n            raise Exception('Unable to determine the format of the pixels')\n        return loader.save(filename, size[0], size[1], fmt, pixels, flipped)\n\n    def read_pixel(self, x, y):\n        '''For a given local x/y position, return the pixel color at that\n        position.\n\n        .. warning::\n            This function can only be used with images loaded with the\n            keep_data=True keyword. For example::\n\n                m = Image.load('image.png', keep_data=True)\n                color = m.read_pixel(150, 150)\n\n        :Parameters:\n            `x` : int\n                Local x coordinate of the pixel in question.\n            `y` : int\n                Local y coordinate of the pixel in question.\n        '''\n        data = self.image._data[0]\n\n        # can't use this fonction without ImageData\n        if data.data is None:\n            raise EOFError('Image data is missing, make sure that image is'\n                           'loaded with keep_data=True keyword.')\n\n        # check bounds\n        x, y = int(x), int(y)\n        if not (0 <= x < data.width and 0 <= y < data.height):\n            raise IndexError('Position (%d, %d) is out of range.' % (x, y))\n\n        assert data.fmt in ImageData._supported_fmts\n        size = 3 if data.fmt in ('rgb', 'bgr') else 4\n        index = y * data.width * size + x * size\n        raw = bytearray(data.data[index:index + size])\n        color = [c / 255.0 for c in raw]\n\n        # conversion for BGR->RGB, BGR->RGBA format\n        if data.fmt in ('bgr', 'bgra'):\n            color[0], color[2] = color[2], color[0]\n\n        return color\n\n\ndef load(filename):\n    '''Load an image'''\n    return Image.load(filename)\n\n\n# load image loaders\nimage_libs = []\n\nif platform in ('macosx', 'ios'):\n    image_libs += [('imageio', 'img_imageio')]\n\nimage_libs += [\n    ('tex', 'img_tex'),\n    ('dds', 'img_dds')]\nif USE_SDL2:\n    image_libs += [('sdl2', 'img_sdl2')]\nelse:\n    image_libs += [('pygame', 'img_pygame')]\nimage_libs += [\n    ('ffpy', 'img_ffpyplayer'),\n    ('pil', 'img_pil'),\n    ('gif', 'img_gif')]\n\nlibs_loaded = core_register_libs('image', image_libs)\n\nfrom os import environ\nif not 'KIVY_DOC' in environ and not libs_loaded:\n    import sys\n\n    Logger.critical('App: Unable to get any Image provider, abort.')\n    sys.exit(1)\n\n# resolve binding.\nfrom kivy.graphics.texture import Texture, TextureRegion\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/image/img_dds.py",
    "content": "'''\nDDS: DDS image loader\n'''\n\n__all__ = ('ImageLoaderDDS', )\n\nfrom kivy.lib.ddsfile import DDSFile\nfrom kivy.logger import Logger\nfrom kivy.core.image import ImageLoaderBase, ImageData, ImageLoader\n\n\nclass ImageLoaderDDS(ImageLoaderBase):\n\n    @staticmethod\n    def extensions():\n        return ('dds', )\n\n    def load(self, filename):\n        try:\n            dds = DDSFile(filename=filename)\n        except:\n            Logger.warning('Image: Unable to load image <%s>' % filename)\n            raise\n\n        self.filename = filename\n        width, height = dds.size\n        im = ImageData(width, height, dds.dxt, dds.images[0], source=filename,\n                       flip_vertical=False)\n        if len(dds.images) > 1:\n            images = dds.images\n            images_size = dds.images_size\n            for index in range(1, len(dds.images)):\n                w, h = images_size[index]\n                data = images[index]\n                im.add_mipmap(index, w, h, data)\n        return [im]\n\n# register\nImageLoader.register(ImageLoaderDDS)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/image/img_ffpyplayer.py",
    "content": "'''\nFFPyPlayer: FFmpeg based image loader\n'''\n\n__all__ = ('ImageLoaderFFPy', )\n\nimport ffpyplayer\nfrom ffpyplayer.pic import ImageLoader as ffImageLoader, SWScale\nfrom ffpyplayer.tools import set_log_callback, loglevels, get_log_callback\n\nfrom kivy.logger import Logger\nfrom kivy.core.image import ImageLoaderBase, ImageData, ImageLoader\n\n\nLogger.info('ImageLoaderFFPy: Using ffpyplayer {}'.format(ffpyplayer.version))\n\n\nlogger_func = {'quiet': Logger.critical, 'panic': Logger.critical,\n               'fatal': Logger.critical, 'error': Logger.error,\n               'warning': Logger.warning, 'info': Logger.info,\n               'verbose': Logger.debug, 'debug': Logger.debug}\n\n\ndef _log_callback(message, level):\n    message = message.strip()\n    if message:\n        logger_func[level]('ffpyplayer: {}'.format(message))\n\nif not get_log_callback():\n    set_log_callback(_log_callback)\n\n\nclass ImageLoaderFFPy(ImageLoaderBase):\n    '''Image loader based on the ffpyplayer library.\n\n    .. versionadded:: 1.9.0\n\n    .. note:\n        This provider may support more formats than what is listed in\n        :meth:`extensions`.\n    '''\n\n    @staticmethod\n    def extensions():\n        '''Return accepted extensions for this loader'''\n        # See https://www.ffmpeg.org/general.html#Image-Formats\n        return ('bmp', 'dpx', 'exr', 'gif', 'ico', 'jpeg', 'jpg2000', 'jpg',\n                'jls', 'pam', 'pbm', 'pcx', 'pgm', 'pgmyuv', 'pic', 'png',\n                'ppm', 'ptx', 'sgi', 'ras', 'tga', 'tiff', 'webp', 'xbm',\n                'xface', 'xwd')\n\n    def load(self, filename):\n        try:\n            loader = ffImageLoader(filename)\n        except:\n            Logger.warning('Image: Unable to load image <%s>' % filename)\n            raise\n\n        # update internals\n        self.filename = filename\n        images = []\n\n        while True:\n            frame, t = loader.next_frame()\n            if frame is None:\n                break\n            images.append(frame)\n        if not len(images):\n            raise Exception('No image found in {}'.format(filename))\n\n        w, h = images[0].get_size()\n        ifmt = images[0].get_pixel_format()\n        if ifmt != 'rgba' and ifmt != 'rgb24':\n            fmt = 'rgba'\n            sws = SWScale(w, h, ifmt, ofmt=fmt)\n            for i, image in enumerate(images):\n                images[i] = sws.scale(image)\n        else:\n            fmt = ifmt if ifmt == 'rgba' else 'rgb'\n\n        return [ImageData(w, h, fmt, img.to_memoryview()[0], source_image=img)\n                for img in images]\n\n\n# register\nImageLoader.register(ImageLoaderFFPy)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/image/img_gif.py",
    "content": "#-*- coding: utf-8 -*-\n#\n#    this program is free software; you can redistribute it and/or modify\n#    it under the terms of the GNU General Public License as published by\n#    the Free Software Foundation; either version 2 of the License, or\n#    (at your option) any later version.\n#\n#    this program is distributed in the hope that it will be useful,\n#    but WITHOUT ANY WARRANTY; without even the implied warranty of\n#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n#    GNU General Public License for more details.\n#\n#    You should have received a copy of the GNU General Public License\n#    if not, write to the Free Software\n#    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n#\n#   The Graphics Interchange Format(c) is the Copyright property of\n#   CompuServe Incorporated. GIF(sm) is a Service Mark property of\n#   CompuServe Incorporated.\n#\n# The unisys/lzw patent has expired, yes. If anyone puts another patent\n# over this code, you must *burn* this file.\n\n'''pygif: gif implementation in python\n\nhttp://www.java2s.com/Open-Source/Python/Network/\\\n        emesene/emesene-1.6.2/pygif/pygif.py.htm'''\n\n\n#TODO issues to fix\n#optimize for speed  #partially done#  a lot of room for improvement\nimport struct\nfrom array import array\n\nKNOWN_FORMATS = ('GIF87a', 'GIF89a')\n\nfrom kivy.compat import PY2\nfrom kivy.logger import Logger\nfrom kivy.core.image import ImageLoaderBase, ImageData, ImageLoader\n\nDebug = False\n\n\nclass ImageLoaderGIF(ImageLoaderBase):\n    '''Image loader for gif'''\n\n    @staticmethod\n    def extensions():\n        '''Return accepted extension for this loader'''\n        return ('gif', )\n\n    def load(self, filename):\n        try:\n            try:\n                im = GifDecoder(open(filename, 'rb').read())\n            except UnicodeEncodeError:\n                if PY2:\n                    im = GifDecoder(open(filename.encode('utf8'), 'rb').read())\n        except:\n            Logger.warning('Image: Unable to load Image <%s>' % filename)\n            raise\n\n        if Debug:\n            print(im.print_info())\n        img_data = []\n        ls_width = im.ls_width\n        ls_height = im.ls_height\n        im_images = im.images\n        im_palette = im.palette\n        pixel_map = array('B', [0] * (ls_width * ls_height * 4))\n        for img in im_images:\n            palette = img.palette if img.local_color_table_flag\\\n                else im_palette\n            have_transparent_color = img.has_transparent_color\n            transparent_color = img.transparent_color\n            #draw_method_restore_previous =  1 \\\n            #    if img.draw_method == 'restore previous' else 0\n            draw_method_replace = 1 \\\n                if ((img.draw_method == 'replace') or\n                    (img.draw_method == 'restore background')) else 0\n            pixels = img.pixels\n            img_height = img.height\n            img_width = img.width\n            left = img.left\n            top = img.top\n            if img_height > ls_height or img_width > ls_width or\\\n                top > ls_height or left > ls_width:\n                Logger.warning('Image_GIF: decoding error on frame <%s>' %\n                        len(img_data))\n                img_height = ls_height\n                img_width = ls_width\n                left = top = 0\n            #reverse top to bottom and left to right\n            tmp_top = (ls_height - (img_height + top))\n            img_width_plus_left = (img_width + left)\n            ls_width_multiply_4 = ls_width * 4\n            left_multiply_4 = left * 4\n            img_data_append = img_data.append\n            while img_height > 0:\n                i = left\n                img_height -= 1\n                x = (img_height * img_width) - left\n                rgba_pos = (tmp_top * ls_width_multiply_4) + (left_multiply_4)\n                tmp_top += 1\n                while i < img_width_plus_left:\n                    #this should now display corrupted gif's\n                    #instead of crashing on gif's not decoded properly\n                    try:\n                        (r, g, b) = palette[pixels[x + i]]\n                    except:\n                        rgba_pos += 4\n                        i += 1\n                        continue\n                    # when not magic pink\n                    if (r, g, b) != (255, 0, 255):\n                        if have_transparent_color:\n                            if transparent_color == pixels[x + i]:\n                                if draw_method_replace:\n                                    #transparent pixel draw method replace\n                                    pixel_map[rgba_pos + 3] = 0\n                                    rgba_pos += 4\n                                    i += 1\n                                    continue\n                                #transparent pixel draw method combine\n                                rgba_pos += 4\n                                i += 1\n                                continue\n                           # this pixel isn't transparent\n                        #doesn't have transparent color\n                        (pixel_map[rgba_pos], pixel_map[rgba_pos + 1],\n                                pixel_map[rgba_pos + 2]) = (r, g, b)\n                        pixel_map[rgba_pos + 3] = 255\n                    # if magic pink move to next pixel\n                    rgba_pos += 4\n                    i += 1\n\n            img_data_append(ImageData(ls_width, ls_height,\n                'rgba', pixel_map.tostring(), flip_vertical=False))\n            if draw_method_replace:\n                pixel_map = array('B', [0] * (ls_width * ls_height * 4))\n\n        self.filename = filename\n\n        return img_data\n\n\nclass Gif(object):\n    '''Base class to decoder'''\n\n    # struct format strings\n\n    #17,18:\n    FMT_HEADER = '<6sHHBBB'\n    #20:\n    FMT_IMGDESC = '<HHHHB'\n\n    IMAGE_SEPARATOR = 0x2C\n    EXTENSION_INTRODUCER = 0x21\n    GIF_TRAILER = 0x3b\n\n    LABEL_GRAPHIC_CONTROL = 0xF9\n    LABEL_COMMENT = 0xFE\n    LABEL_PLAINTEXT = 0x01\n\n    FMT_EXT_GRAPHIC_CONTROL = '<BBHB'  # 89a\n\n    def __init__(self, data, debug):\n        self.data = data\n        self.pointer = 0\n\n        # default data for an empty file\n        self.header = 'GIF87a'\n        self.ls_width = 0\n        self.ls_height = 0\n        self.flags = 0\n        self.color_resolution = 0\n        self.sort_flag = 0\n        self.color_table_flag = 0\n        self.global_color_table_size = 0\n        self.background_color = 0\n        self.aspect_ratio = 0\n        # greyscale palette by default\n        self.palette = [(x, x, x) for x in range(0, 256)]\n        self.images = []\n\n        self.debug_enabled = False\n        return\n\n    def pop(self, data, length=1):\n        '''gets the next $len chars from the data stack import\n        and increment the pointer'''\n\n        start = self.pointer\n        end = self.pointer + length\n        self.pointer += length\n\n        return data[start:end]\n\n    def pops(self, format, data):\n        '''pop struct: get size, pop(), unpack()'''\n        size = struct.calcsize(format)\n        return struct.unpack(format, self.pop(data, size))\n\n    def print_info(self):\n        '''prints out some useful info (..debug?)'''\n\n        print(\"Version: %s\" % self.header)\n        print(\"Logical screen width: %d\" % self.ls_width)\n        print(\"Logical screen height: %d\" % self.ls_height)\n        print(\"Flags: %s\" % repr(self.flags))\n        print(\" \" * 6, \"Color resolution: %d\" % self.color_resolution)\n        print(\" \" * 6, \"Sort flag: %r\" % self.sort_flag)\n        print(\" \" * 6, \"Global color table flag: %r\" % self.color_table_flag)\n        print(\" \" * 22, \"...size: %d (%d bytes)\" %\n              (self.global_color_table_size, self.global_color_table_size * 3))\n        print(\"Background color: %d\" % self.background_color)\n        print(\"Aspect ratio info: %d\" % self.aspect_ratio)\n\n    def new_image(self, header=None):\n        '''adds a new image descriptor'''\n        image = ImageDescriptor(self, header)\n        self.images.append(image)\n        return image\n\n\nclass ImageDescriptor(object):\n    '''A class that represents a single image'''\n\n    def __init__(self, parent, header=None):\n\n        self.parent = parent\n        # this will be set when needed\n        self.codesize = 0\n\n        # compressed output codes\n        self.lzwcode = ''\n\n        # uncompressed pixels (decoded)\n        self.pixels = []\n\n        # we assume a \"fullscreen\" image\n        self.left = self.top = 0\n        self.width = parent.ls_width\n        self.height = parent.ls_height\n\n        # yes, these default flags work...\n        self.flags = [False for x in range(8)]\n        self.local_color_table_flag = False\n        self.interlace_flag = False\n        self.sort_flag = False\n        self.local_color_table_size = 0\n        self.draw_method = 'replace'\n        self.transparent_color = -1\n        self.has_transparent_color = 0\n        self.palette = []\n\n        if header:\n            self.setup_header(header)\n\n    def setup_header(self, header):\n        '''takes a header tuple and fills the attributes'''\n\n        self.left = header[0]\n        self.top = header[1]\n        self.width = header[2]\n        self.height = header[3]\n\n        self.flags = get_bits(header[4])\n        self.local_color_table_flag = self.flags[7]\n        self.interlace_flag = self.flags[6]\n        self.sort_flag = self.flags[5]\n        #-- flags 4 and 3 are reserved\n        self.local_color_table_size = 2 ** (pack_bits(self.flags[:3]) + 1)\n        if self.local_color_table_flag:\n            if Debug:\n                print('local color table true')\n            self.palette = self.parent.get_color_table(\n                self.local_color_table_size * 3)\n\n    def get_header(self):\n        '''builds a header dynamically'''\n        flags = [False for x in range(8)]\n        flags[7] = self.local_color_table_flag\n        flags[6] = self.interlace_flag\n        flags[5] = self.sort_flag\n\n        # useless!\n        flags[2], flags[1], flags[0] = get_bits(len(self.palette), bits=3)\n\n        return (self.left, self.top, self.width, self.height, pack_bits(flags))\n\n    header = property(fget=get_header)\n\n\nclass GifDecoder(Gif):\n    '''decodes a gif file into.. something.. else..'''\n\n    def __init__(self, data, debug=False):\n        Gif.__init__(self, data, debug)\n        self.fill()\n\n    def fill(self):\n        '''reads the data and fills each field of the file'''\n\n        # start reading from the beggining of the file\n        self.pointer = 0\n\n        #17. Header.\n        #18. Logical Screen Descriptor.\n        data = self.pops(Gif.FMT_HEADER, self.data)\n\n        self.header = data[0]\n        self.ls_width = data[1]\n        self.ls_height = data[2]\n        self.background_color = data[4]\n        self.aspect_ratio = data[5]\n\n        # flags field\n        self.flags = get_bits(data[3])\n        #1 bit\n        self.color_table_flag = self.flags[7]\n        self.sort_flag = self.flags[3]\n        #3 bit\n        self.color_resolution = pack_bits(self.flags[4:7])  # 7 not included\n        #3 bit\n        self.global_color_table_size = 2 ** (pack_bits(self.flags[:3]) + 1)\n\n        #19. Global Color Table.\n        if self.color_table_flag:\n            size = (self.global_color_table_size) * 3\n            self.palette = self.get_color_table(size)\n        else:\n            # generate a greyscale palette\n            self.palette = [(x, x, x) for x in range(256)]\n\n        # blocks\n        image = None\n        self_data = self.data\n        self_pops = self.pops\n        Gif_IMAGE_SEPARATOR = Gif.IMAGE_SEPARATOR\n        Gif_FMT_IMGDESC = Gif.FMT_IMGDESC\n        self_new_image = self.new_image\n        self_pop = self.pop\n        self_debug_enabled = self.debug_enabled\n        self_lzw_decode = self.lzw_decode\n        Gif_EXTENSION_INTRODUCER = Gif.EXTENSION_INTRODUCER\n        Gif_GIF_TRAILER = Gif.GIF_TRAILER\n        Gif_LABEL_GRAPHIC_CONTROL = Gif.LABEL_GRAPHIC_CONTROL\n        trans_color = 0\n        has_transparent_color = 0\n        drw_method = 'replace'\n        while True:\n            try:\n                nextbyte = self_pops('<B', self_data)[0]\n            except:\n                nextbyte = 0x3b  # force end\n\n            #20. Image Descriptor\n            if nextbyte == Gif_IMAGE_SEPARATOR:\n                descriptor = self_pops(Gif_FMT_IMGDESC, self_data)\n                image = self_new_image(descriptor)\n                image.transparent_color = trans_color\n                image.has_transparent_color = has_transparent_color\n                image.draw_method = drw_method\n                image.codesize = self_pops('<B', self_data)[0]\n                image.lzwcode = b''\n                image_lzwcode = image.lzwcode\n                ###TODO too many corner casses for gifs:(\n                table_size = image.local_color_table_size\\\n                    if image.local_color_table_flag and \\\n                    self.global_color_table_size < image.local_color_table_size\\\n                    else self.global_color_table_size\n\n                while True:\n                    try:\n                        blocksize = self_pops('<B', self_data)[0]\n                    except:\n                        break\n                    if blocksize == 0:\n                        break   # no more image data\n                    lzwdata = self_pop(self_data, blocksize)\n                    image_lzwcode = b''.join((image_lzwcode, lzwdata))\n\n                if self_debug_enabled:\n                    print('LZW length:', len(image_lzwcode))\n\n                image.lzwcode = image_lzwcode\n                image.pixels = self_lzw_decode(image.lzwcode, image.codesize,\n                        table_size)\n\n            # Extensions\n            elif nextbyte == Gif_EXTENSION_INTRODUCER:\n                pass\n            # Gif trailer\n            elif nextbyte == Gif_GIF_TRAILER:\n                return\n            elif nextbyte == Gif_LABEL_GRAPHIC_CONTROL:\n                nextbyte = self_pops('<B', self_data)[0]\n                drw_bits = (get_bits(self_pops('<B', self_data)[0]))\n                has_transparent_color = drw_bits[0]\n                if drw_bits[2:5] == array('B', [0, 0, 1]):\n                    drw_method = 'replace'\n                elif (drw_bits[2:5]) == array('B', [0, 1, 0]):\n                    drw_method = 'restore background'\n                else:\n                    drw_method = 'restore previous'\n                nextbyte = self_pops('<B', self_data)[0]\n                nextbyte = self_pops('<B', self_data)[0]\n                nextbyte = self_pops('<B', self_data)[0]\n                trans_color = nextbyte\n                pass\n            # \"No Idea What Is This\"\n            else:\n                pass\n\n    def string_to_bits(self, string):\n        '''high level string unpacker'''\n        ordarray = array('B', string)\n        bits = array('B')\n        bits_append = bits.append\n        _get_bits = get_bits\n        for byte in ordarray:\n            list(map(bits_append, _get_bits(byte)))\n        return bits\n\n    def readable(bool_list):\n        '''Converts a list of booleans to a readable list of ints\n        Useful for debug only'''\n        return [int(x) for x in bool_list]\n\n    def bits_to_int(self, bits):\n        '''high level bit list packer'''\n        c = 1\n        i = 0\n        for bit in bits:\n            if bit:\n                i += 2 ** (c - 1)\n            c += 1\n        return i\n\n    def get_color_table(self, size):\n        '''Returns a color table in the format [(r,g,b),(r,g,b), ...]'''\n\n        raw_color_table = self.pops(\"<%dB\" % size, self.data)\n        pos = 0\n        palette = []\n        palette_append = palette.append\n\n        while pos + 3 < (size + 1):\n            red = raw_color_table[pos]\n            green = raw_color_table[pos + 1]\n            blue = raw_color_table[pos + 2]\n            palette_append((red, green, blue))\n            pos += 3\n        return palette\n\n    def lzw_decode(self, input, initial_codesize, color_table_size):\n        '''Decodes a lzw stream from input import\n        Returns list of ints (pixel values)'''\n        string_table = {}\n        output = array('B')\n        output_append = output.append\n        output_extend = output.extend\n        old = ''\n        index = 0\n\n        bits = self.string_to_bits(input)\n        self.bitpointer = 0\n\n        codesize = initial_codesize + 1\n        clearcode, end_of_info = color_table_size, color_table_size + 1\n\n        if Debug:\n            print('codesize: %d' % codesize)\n            print('clearcode %d, end_of_info: %d' % (clearcode, end_of_info))\n\n        def pop(size, _bits):\n            ''' return bits '''\n            start = self.bitpointer\n            end = self.bitpointer = start + size\n            return _bits[start: end]\n\n        def clear():\n            '''Called on clear code'''\n            string_table.clear()\n            for index in range(color_table_size):\n                string_table[index] = chr(index)\n            index = end_of_info + 1\n            return index\n\n        index = clear()\n        # skip first (clear)code\n        bits = bits[codesize:]\n        # read first code, append to output\n        self_bits_to_int = self.bits_to_int\n\n        code = self_bits_to_int(pop(codesize, bits))\n        if code in string_table:\n            output_append(ord(string_table[code]))\n        else:\n            Logger.warning('Image_GIF: decoding error on code '\n                '<%d> aode size <%d>' % (code, codesize))\n            string_table[code] = string_table[0]\n            output_append(ord(string_table[code]))\n        old = string_table[code]\n        bitlen = len(bits)\n\n        while self.bitpointer < bitlen:\n            # read next code\n            code = self_bits_to_int(pop(codesize, bits))\n\n            # special code?\n            if code == clearcode:\n                index = clear()\n                codesize = initial_codesize + 1\n                code = self_bits_to_int(pop(codesize, bits))\n                if code in string_table:\n                    output_append(ord(string_table[code]))\n                else:\n                    Logger.warning('Image_GIF: decoding error on code '\n                        '<%d> aode size <%d>' % (code, codesize))\n                    string_table[code] = string_table[0]\n                    output_append(ord(string_table[code]))\n                old = string_table[code]\n                continue\n\n            elif code == end_of_info:\n                break\n\n            # code in stringtable?\n            if code in string_table:\n                c = string_table[code]\n                string_table[index] = ''.join((old, c[0]))\n            else:\n                c = ''.join((old, old[0]))\n                string_table[code] = c\n\n            index += 1\n            old = c\n            output_extend(list(map(ord, c)))\n\n            if index == 2 ** codesize:\n                codesize += 1\n                if codesize == 13:\n                    codesize = 12\n\n        if self.debug_enabled:\n            print('Output stream len: %d' % len(output))\n        return output\n\n\ndef get_bits(flags, reverse=False, bits=8):\n    '''return a list with $bits items, one for each enabled bit'''\n\n    mybits = (1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048)[:bits]\n\n    rev_num = 1\n    if reverse:\n        rev_num = -1\n    ret = array('B')\n    ret_append = ret.append\n    for bit in mybits[::rev_num]:\n        ret_append(flags & bit != 0)\n    return ret\n\n\ndef pack_bits(bits):\n    '''convert a bit (bool or int) tuple into a int'''\n    packed = 0\n    level = 0\n    for bit in bits:\n        if bit:\n            packed += 2 ** level\n        level += 1\n    return packed\n\n# register\nImageLoader.register(ImageLoaderGIF)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/image/img_pil.py",
    "content": "'''\nPIL: PIL image loader\n'''\n\n__all__ = ('ImageLoaderPIL', )\n\ntry:\n    from PIL import Image as PILImage\nexcept:\n    import Image as PILImage\n\nfrom kivy.logger import Logger\nfrom kivy.core.image import ImageLoaderBase, ImageData, ImageLoader\n\n\nclass ImageLoaderPIL(ImageLoaderBase):\n    '''Image loader based on the PIL library.\n\n    .. versionadded:: 1.0.8\n\n    Support for GIF animation added.\n\n    Gif animation has a lot of issues(transparency/color depths... etc).\n    In order to keep it simple, what is implimented here is what is\n    natively supported by the PIL library.\n\n    As a general rule, try to use gifs that have no transparency.\n    Gif's with transparency will work but be prepared for some\n    artifacts until transparency support is improved.\n\n    '''\n\n    @staticmethod\n    def can_save():\n        return True\n\n    @staticmethod\n    def can_load_memory():\n        return True\n\n    @staticmethod\n    def extensions():\n        '''Return accepted extensions for this loader'''\n        # See http://www.pythonware.com/library/pil/handbook/index.htm\n        return ('bmp', 'bufr', 'cur', 'dcx', 'fits', 'fl', 'fpx', 'gbr',\n                'gd', 'gif', 'grib', 'hdf5', 'ico', 'im', 'imt', 'iptc',\n                'jpeg', 'jpg', 'jpe', 'mcidas', 'mic', 'mpeg', 'msp',\n                'pcd', 'pcx', 'pixar', 'png', 'ppm', 'psd', 'sgi',\n                'spider', 'tga', 'tiff', 'wal', 'wmf', 'xbm', 'xpm',\n                'xv')\n\n    def _img_correct(self, _img_tmp):\n        '''Convert image to the correct format and orientation.\n        '''\n        # image loader work only with rgb/rgba image\n        if _img_tmp.mode.lower() not in ('rgb', 'rgba'):\n            try:\n                imc = _img_tmp.convert('RGBA')\n            except:\n                Logger.warning(\n                    'Image: Unable to convert image to rgba (was %s)' %\n                    (_img_tmp.mode.lower()))\n                raise\n            _img_tmp = imc\n\n        return _img_tmp\n\n    def _img_read(self, im):\n        '''Read images from an animated file.\n        '''\n        im.seek(0)\n\n        # Read all images inside\n        try:\n            img_ol = None\n            while True:\n                img_tmp = im\n                img_tmp = self._img_correct(img_tmp)\n                if img_ol and (hasattr(im, 'dispose') and not im.dispose):\n                    # paste new frame over old so as to handle\n                    # transparency properly\n                    img_ol.paste(img_tmp, (0, 0), img_tmp)\n                    img_tmp = img_ol\n                img_ol = img_tmp\n                yield ImageData(img_tmp.size[0], img_tmp.size[1],\n                                img_tmp.mode.lower(), img_tmp.tostring())\n                im.seek(im.tell() + 1)\n        except EOFError:\n            pass\n\n    def load(self, filename):\n        try:\n            im = PILImage.open(filename)\n        except:\n            Logger.warning('Image: Unable to load image <%s>' % filename)\n            raise\n        # update internals\n        if not self._inline:\n            self.filename = filename\n        # returns an array of type ImageData len 1 if not a sequence image\n        return list(self._img_read(im))\n\n    @staticmethod\n    def save(filename, width, height, fmt, pixels, flipped=False):\n        image = PILImage.fromstring(fmt.upper(), (width, height), pixels)\n        if flipped:\n            image = image.transpose(PILImage.FLIP_TOP_BOTTOM)\n        image.save(filename)\n        return True\n\n\n# register\nImageLoader.register(ImageLoaderPIL)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/image/img_pygame.py",
    "content": "'''\nPygame: Pygame image loader\n'''\n\n__all__ = ('ImageLoaderPygame', )\n\nfrom kivy.compat import PY2\nfrom kivy.logger import Logger\nfrom kivy.core.image import ImageLoaderBase, ImageData, ImageLoader\nfrom os.path import isfile\n\ntry:\n    import pygame\nexcept:\n    raise\n\n\nclass ImageLoaderPygame(ImageLoaderBase):\n    '''Image loader based on the PIL library'''\n\n    @staticmethod\n    def extensions():\n        '''Return accepted extensions for this loader'''\n        # under macosx, i got with \"pygame.error: File is not a Windows BMP\n        # file\". documentation said: The image module is a required dependency\n        # of Pygame, but it only optionally supports any extended file formats.\n        # By default it can only load uncompressed BMP image\n        if pygame.image.get_extended() == 0:\n            return ('bmp', )\n        return ('jpg', 'jpeg', 'jpe', 'png', 'bmp', 'pcx', 'tga', 'tiff',\n                'tif', 'lbm', 'pbm', 'ppm', 'xpm')\n\n    @staticmethod\n    def can_save():\n        return True\n\n    @staticmethod\n    def can_load_memory():\n        return True\n\n    def load(self, filename):\n        if not filename:\n            import traceback\n            traceback.print_stack()\n            return\n        try:\n            im = None\n            if self._inline:\n                im = pygame.image.load(filename, 'x.{}'.format(self._ext))\n            elif isfile(filename):\n                with open(filename, 'rb') as fd:\n                    im = pygame.image.load(fd)\n            elif isinstance(filename, bytes):\n                try:\n                    fname = filename.decode()\n                    if isfile(fname):\n                        with open(fname, 'rb') as fd:\n                            im = pygame.image.load(fd)\n                except UnicodeDecodeError:\n                    pass\n            if im is None:\n                im = pygame.image.load(filename)\n        except:\n            #Logger.warning(type(filename)('Image: Unable to load image <%s>')\n            #               % filename)\n            raise\n\n        fmt = ''\n        if im.get_bytesize() == 3:\n            fmt = 'rgb'\n        elif im.get_bytesize() == 4:\n            fmt = 'rgba'\n\n        # image loader work only with rgb/rgba image\n        if fmt not in ('rgb', 'rgba'):\n            try:\n                imc = im.convert(32)\n                fmt = 'rgba'\n            except:\n                try:\n                    imc = im.convert_alpha()\n                    fmt = 'rgba'\n                except:\n                    Logger.warning(\n                        'Image: Unable to convert image %r to rgba (was %r)' %\n                        (filename, im.fmt))\n                    raise\n            im = imc\n\n        # update internals\n        if not self._inline:\n            self.filename = filename\n        data = pygame.image.tostring(im, fmt.upper())\n        return [ImageData(im.get_width(), im.get_height(),\n                fmt, data, source=filename)]\n\n    @staticmethod\n    def save(filename, width, height, fmt, pixels, flipped):\n        surface = pygame.image.fromstring(\n            pixels, (width, height), fmt.upper(), flipped)\n        pygame.image.save(surface, filename)\n        return True\n\n\n# register\nImageLoader.register(ImageLoaderPygame)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/image/img_sdl2.py",
    "content": "'''\nSDL2 image loader\n=================\n'''\n\n__all__ = ('ImageLoaderSDL2', )\n\nfrom kivy.compat import PY2\nfrom kivy.logger import Logger\nfrom kivy.core.image import ImageLoaderBase, ImageData, ImageLoader\nfrom kivy.core.image import _img_sdl2\n\n\nclass ImageLoaderSDL2(ImageLoaderBase):\n    '''Image loader based on the PIL library'''\n\n    def _ensure_ext(self):\n        _img_sdl2.init()\n\n    @staticmethod\n    def extensions():\n        '''Return accepted extensions for this loader'''\n        return ('bmp', 'jpg', 'jpeg', 'lbm', 'pcx', 'png', 'pnm', 'tga', 'tiff',\n                'webp', 'xcf', 'xpm', 'xv')\n\n    @staticmethod\n    def can_save():\n        return True\n\n    @staticmethod\n    def can_load_memory():\n        return True\n\n    def load(self, filename):\n        if self._inline:\n            data = filename.read()\n            info = _img_sdl2.load_from_memory(data)\n        else:\n            info = _img_sdl2.load_from_filename(filename)\n        if not info:\n            Logger.warning('Image: Unable to load image <%s>' % filename)\n            raise Exception('SDL2: Unable to load image')\n\n        w, h, fmt, pixels, rowlength = info\n\n        # update internals\n        if not self._inline:\n            self.filename = filename\n        return [ImageData(\n            w, h, fmt, pixels, source=filename,\n            rowlength=rowlength)]\n\n    @staticmethod\n    def save(filename, width, height, fmt, pixels, flipped):\n        _img_sdl2.save(filename, width, height, fmt, pixels, flipped)\n        return True\n\n\n# register\nImageLoader.register(ImageLoaderSDL2)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/image/img_tex.py",
    "content": "'''\nTex: Compressed texture\n'''\n\n__all__ = ('ImageLoaderTex', )\n\nimport json\nfrom struct import unpack\nfrom kivy.logger import Logger\nfrom kivy.core.image import ImageLoaderBase, ImageData, ImageLoader\n\n\nclass ImageLoaderTex(ImageLoaderBase):\n\n    @staticmethod\n    def extensions():\n        return ('tex', )\n\n    def load(self, filename):\n        try:\n            fd = open(filename, 'rb')\n            if fd.read(4) != 'KTEX':\n                raise Exception('Invalid tex identifier')\n\n            headersize = unpack('I', fd.read(4))[0]\n            header = fd.read(headersize)\n            if len(header) != headersize:\n                raise Exception('Truncated tex header')\n\n            info = json.loads(header)\n            data = fd.read()\n            if len(data) != info['datalen']:\n                raise Exception('Truncated tex data')\n\n        except:\n            Logger.warning('Image: Image <%s> is corrupted' % filename)\n            raise\n\n        width, height = info['image_size']\n        tw, th = info['texture_size']\n\n        images = [data]\n        im = ImageData(width, height, str(info['format']), images[0],\n                       source=filename)\n        '''\n        if len(dds.images) > 1:\n            images = dds.images\n            images_size = dds.images_size\n            for index in range(1, len(dds.images)):\n                w, h = images_size[index]\n                data = images[index]\n                im.add_mipmap(index, w, h, data)\n        '''\n        return [im]\n\n# register\nImageLoader.register(ImageLoaderTex)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/spelling/__init__.py",
    "content": "'''\nSpelling\n========\n\nProvides abstracted access to a range of spellchecking backends as well as\nword suggestions. The API is inspired by enchant but other backends can be\nadded that implement the same API.\n\nSpelling currently requires `python-enchant` for all platforms except\nOSX, where a native implementation exists.\n\n::\n\n    >>> from kivy.core.spelling import Spelling\n    >>> s = Spelling()\n    >>> s.list_languages()\n    ['en', 'en_CA', 'en_GB', 'en_US']\n    >>> s.select_language('en_US')\n    >>> s.suggest('helo')\n    [u'hole', u'help', u'helot', u'hello', u'halo', u'hero', u'hell', u'held',\n     u'helm', u'he-lo']\n\n'''\n\n__all__ = ('Spelling', 'SpellingBase', 'NoSuchLangError',\n           'NoLanguageSelectedError')\n\nimport sys\nfrom kivy.core import core_select_lib\n\n\nclass NoSuchLangError(Exception):\n    '''\n    Exception to be raised when a specific language could not be found.\n    '''\n    pass\n\n\nclass NoLanguageSelectedError(Exception):\n    '''\n    Exception to be raised when a language-using method is called but no\n    language was selected prior to the call.\n    '''\n    pass\n\n\nclass SpellingBase(object):\n    '''\n    Base class for all spelling providers.\n    Supports some abstract methods for checking words and getting suggestions.\n    '''\n\n    def __init__(self, language=None):\n        '''\n        If a `language` identifier (such as 'en_US') is provided and a matching\n        language exists, it is selected. If an identifier is provided and no\n        matching language exists, a NoSuchLangError exception is raised by\n        self.select_language().\n        If no `language` identifier is provided, we just fall back to the first\n        one that is available.\n\n        :Parameters:\n            `language` : str, defaults to None\n                If provided, indicates the language to be used. This needs\n                to be a language identifier understood by select_language(),\n                i.e. one of the options returned by list_languages().\n                If nothing is provided, the first available language is used.\n                If no language is available, NoLanguageSelectedError is raised.\n        '''\n        langs = self.list_languages()\n        try:\n            # If no language was specified, we just use the first one\n            # that is available.\n            fallback_lang = langs[0]\n        except IndexError:\n            raise NoLanguageSelectedError(\"No languages available!\")\n        self.select_language(language or fallback_lang)\n\n    def select_language(self, language):\n        '''\n        From the set of registered languages, select the first language\n        for `language`.\n\n        :Parameters:\n            `language` : str\n                Language identifier. Needs to be one of the options returned by\n                list_languages(). Sets the language used for spell checking and\n                word suggestions.\n        '''\n        raise NotImplementedError('select_language() method not implemented '\n                                  'by abstract spelling base class!')\n\n    def list_languages(self):\n        '''\n        Return a list of all supported languages.\n        E.g. ['en', 'en_GB', 'en_US', 'de', ...]\n        '''\n        raise NotImplementedError('list_languages() is not implemented '\n                                  'by abstract spelling base class!')\n\n    def check(self, word):\n        '''\n        If `word` is a valid word in `self._language` (the currently active\n        language), returns True. If the word shouldn't be checked, returns\n        None (e.g. for ''). If it is not a valid word in `self._language`,\n        return False.\n\n        :Parameters:\n            `word` : str\n                The word to check.\n        '''\n        raise NotImplementedError('check() not implemented by abstract ' +\n                                  'spelling base class!')\n\n    def suggest(self, fragment):\n        '''\n        For a given `fragment` (i.e. part of a word or a word by itself),\n        provide corrections (`fragment` may be misspelled) or completions\n        as a list of strings.\n\n        :Parameters:\n            `fragment` : str\n                The word fragment to get suggestions/corrections for.\n                E.g. 'foo' might become 'of', 'food' or 'foot'.\n\n        '''\n        raise NotImplementedError('suggest() not implemented by abstract ' +\n                                  'spelling base class!')\n\n\n_libs = (('enchant', 'spelling_enchant', 'SpellingEnchant'), )\nif sys.platform == 'darwin':\n    _libs += (('osxappkit', 'spelling_osxappkit', 'SpellingOSXAppKit'), )\n\nSpelling = core_select_lib('spelling', _libs)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/spelling/spelling_enchant.py",
    "content": "'''\nEnchant Spelling: Implements spelling backend based on enchant.\n'''\n\n\nimport enchant\n\nfrom kivy.core.spelling import SpellingBase, NoSuchLangError\nfrom kivy.compat import PY2\n\n\nclass SpellingEnchant(SpellingBase):\n    '''\n    Spelling backend based on the enchant library.\n    '''\n\n    def __init__(self, language=None):\n        self._language = None\n        super(SpellingEnchant, self).__init__(language)\n\n    def select_language(self, language):\n        try:\n            self._language = enchant.Dict(language)\n        except enchant.DictNotFoundError:\n            err = 'Enchant Backend: No language for \"%s\"' % (language, )\n            raise NoSuchLangError(err)\n\n    def list_languages(self):\n        # Note: We do NOT return enchant.list_dicts because that also returns\n        #       the enchant dict objects and not only the language identifiers.\n        return enchant.list_languages()\n\n    def check(self, word):\n        if not word:\n            return None\n        return self._language.check(word)\n\n    def suggest(self, fragment):\n        suggestions = self._language.suggest(fragment)\n        # Don't show suggestions that are invalid\n        suggestions = [s for s in suggestions if self.check(s)]\n        if PY2:\n            suggestions = [s.decode('utf-8') for s in suggestions]\n        return suggestions\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/spelling/spelling_osxappkit.py",
    "content": "'''\nAppKit Spelling: Implements spelling backend based on OSX's spellchecking\n                 features provided by the ApplicationKit.\n\n                 NOTE:\n                    Requires pyobjc and setuptools to be installed!\n                    `sudo easy_install pyobjc setuptools`\n\n                 Developers should read:\n                    http://developer.apple.com/mac/library/documentation/\n                        Cocoa/Conceptual/SpellCheck/SpellCheck.html\n                    http://developer.apple.com/cocoa/pyobjc.html\n'''\n\n\nfrom AppKit import NSSpellChecker, NSMakeRange\n\nfrom kivy.core.spelling import SpellingBase, NoSuchLangError\n\n\nclass SpellingOSXAppKit(SpellingBase):\n    '''\n    Spelling backend based on OSX's spelling features provided by AppKit.\n    '''\n\n    def __init__(self, language=None):\n        self._language = NSSpellChecker.alloc().init()\n        super(SpellingOSXAppKit, self).__init__(language)\n\n    def select_language(self, language):\n        success = self._language.setLanguage_(language)\n        if not success:\n            err = 'AppKit Backend: No language \"%s\" ' % (language, )\n            raise NoSuchLangError(err)\n\n    def list_languages(self):\n        return list(self._language.availableLanguages())\n\n    def check(self, word):\n        # TODO Implement this!\n        #      NSSpellChecker provides several functions that look like what we\n        #      need, but they're a) slooow and b) return a strange result.\n        #      Might be a snow leopard bug. Have to test further.\n        #      See: http://paste.pocoo.org/show/217968/\n        if not word:\n            return None\n        err = 'check() not currently supported by the OSX AppKit backend'\n        raise NotImplementedError(err)\n\n    def suggest(self, fragment):\n        l = self._language\n        # XXX Both ways below work on OSX 10.6. It has not been tested on any\n        #     other version, but it should work.\n        try:\n            # This is deprecated as of OSX 10.6, hence the try-except\n            return list(l.guessesForWord_(fragment))\n        except AttributeError:\n            # From 10.6 onwards you're supposed to do it like this:\n            checkrange = NSMakeRange(0, len(fragment))\n            g = l.guessesForWordRange_inString_language_inSpellDocumentWithTag_(\n                checkrange, fragment, l.language(), 0)\n            # Right, this was much easier, Apple! :-)\n            return list(g)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/text/__init__.py",
    "content": "'''\nText\n====\n\nAn abstraction of text creation. Depending of the selected backend, the\naccuracy of text rendering may vary.\n\n.. versionchanged:: 1.5.0\n    :attr:`LabelBase.line_height` added.\n\n.. versionchanged:: 1.0.7\n    The :class:`LabelBase` does not generate any texture if the text has a\n    width <= 1.\n\nThis is the backend layer for getting text out of different text providers,\nyou should only be using this directly if your needs aren't fulfilled by the\n:class:`~kivy.uix.label.Label`.\n\nUsage example::\n\n    from kivy.core.label import Label as CoreLabel\n\n    ...\n    ...\n    my_label = CoreLabel()\n    my_label.text = 'hello'\n    # the label is usually not drawn until needed, so force it to draw.\n    my_label.refresh()\n    # Now access the texture of the label and use it wherever and\n    # however you may please.\n    hello_texture = my_label.texture\n\n'''\n\n__all__ = ('LabelBase', 'Label')\n\nimport re\nimport os\nfrom functools import partial\nfrom copy import copy\nfrom kivy import kivy_data_dir\nfrom kivy.utils import platform\nfrom kivy.graphics.texture import Texture\nfrom kivy.core import core_select_lib\nfrom kivy.core.text.text_layout import layout_text, LayoutWord\nfrom kivy.resources import resource_find, resource_add_path\nfrom kivy.compat import PY2\nfrom kivy.setupconfig import USE_SDL2\n\nDEFAULT_FONT = 'DroidSans'\n\nFONT_REGULAR = 0\nFONT_ITALIC = 1\nFONT_BOLD = 2\nFONT_BOLDITALIC = 3\n\n\nclass LabelBase(object):\n    '''Core text label.\n    This is the abstract class used by different backends to render text.\n\n    .. warning::\n        The core text label can't be changed at runtime. You must recreate one.\n\n    :Parameters:\n        `font_size`: int, defaults to 12\n            Font size of the text\n        `font_name`: str, defaults to DEFAULT_FONT\n            Font name of the text\n        `bold`: bool, defaults to False\n            Activate \"bold\" text style\n        `italic`: bool, defaults to False\n            Activate \"italic\" text style\n        `text_size`: tuple, defaults to (None, None)\n            Add constraint to render the text (inside a bounding box).\n            If no size is given, the label size will be set to the text size.\n        `padding`: float, defaults to None\n            If it's a float, it will set padding_x and padding_y\n        `padding_x`: float, defaults to 0.0\n            Left/right padding\n        `padding_y`: float, defaults to 0.0\n            Top/bottom padding\n        `halign`: str, defaults to \"left\"\n            Horizontal text alignment inside the bounding box\n        `valign`: str, defaults to \"bottom\"\n            Vertical text alignment inside the bounding box\n        `shorten`: bool, defaults to False\n            Indicate whether the label should attempt to shorten its textual\n            contents as much as possible if a `size` is given.\n            Setting this to True without an appropriately set size will lead to\n            unexpected results.\n        `shorten_from`: str, defaults to `center`\n            The side from which we should shorten the text from, can be left,\n            right, or center. E.g. if left, the ellipsis will appear towards\n            the left side and it will display as much text starting from the\n            right as possible.\n        `split_str`: string, defaults to `' '` (space)\n            The string to use to split the words by when shortening. If empty,\n            we can split after every character filling up the line as much as\n            possible.\n        `max_lines`: int, defaults to 0 (unlimited)\n            If set, this indicate how maximum line are allowed to render the\n            text. Works only if a limitation on text_size is set.\n        `mipmap` : bool, defaults to False\n            Create a mipmap for the texture\n        `strip` : bool, defaults to False\n            Whether each row of text has its leading and trailing spaces\n            stripped. If `halign` is `justify` it is implicitly True.\n        `strip_reflow` : bool, defaults to True\n            Whether text that has been reflowed into a second line should\n            be striped, even if `strip` is False. This is only in effect when\n            `size_hint_x` is not None, because otherwise lines are never\n            split.\n        `unicode_errors` : str, defaults to `'replace'`\n            How to handle unicode decode errors. Can be `'strict'`, `'replace'`\n            or `'ignore'`.\n\n    .. versionchanged:: 1.9.0\n        `strip`, `strip_reflow`, `shorten_from`, `split_str`, and\n        `unicode_errors` were added.\n\n    .. versionchanged:: 1.9.0\n        `padding_x` and `padding_y` has been fixed to work as expected.\n        In the past, the text was padded by the negative of their values.\n\n    .. versionchanged:: 1.8.0\n        `max_lines` parameters has been added.\n\n    .. versionchanged:: 1.0.8\n        `size` have been deprecated and replaced with `text_size`.\n\n    .. versionchanged:: 1.0.7\n        The `valign` is now respected. This wasn't the case previously\n        so you might have an issue in your application if you have not\n        considered this.\n\n    '''\n\n    __slots__ = ('options', 'texture', '_label', '_text_size')\n\n    _cached_lines = []\n\n    _fonts = {}\n\n    _fonts_cache = {}\n\n    _fonts_dirs = []\n\n    _texture_1px = None\n\n    def __init__(\n        self, text='', font_size=12, font_name=DEFAULT_FONT, bold=False,\n        italic=False, halign='left', valign='bottom', shorten=False,\n        text_size=None, mipmap=False, color=None, line_height=1.0, strip=False,\n        strip_reflow=True, shorten_from='center', split_str=' ',\n        unicode_errors='replace', **kwargs):\n\n        # Include system fonts_dir in resource paths.\n        # This allows us to specify a font from those dirs.\n        LabelBase.get_system_fonts_dir()\n\n        options = {'text': text, 'font_size': font_size,\n                   'font_name': font_name, 'bold': bold, 'italic': italic,\n                   'halign': halign, 'valign': valign, 'shorten': shorten,\n                   'mipmap': mipmap, 'line_height': line_height,\n                   'strip': strip, 'strip_reflow': strip_reflow,\n                   'shorten_from': shorten_from, 'split_str': split_str,\n                   'unicode_errors': unicode_errors}\n\n        options['color'] = color or (1, 1, 1, 1)\n        options['padding'] = kwargs.get('padding', (0, 0))\n        if not isinstance(options['padding'], (list, tuple)):\n            options['padding'] = (options['padding'], options['padding'])\n        options['padding_x'] = kwargs.get('padding_x', options['padding'][0])\n        options['padding_y'] = kwargs.get('padding_y', options['padding'][1])\n\n        if 'size' in kwargs:\n            options['text_size'] = kwargs['size']\n        else:\n            if text_size is None:\n                options['text_size'] = (None, None)\n            else:\n                options['text_size'] = text_size\n\n        self._text_size = options['text_size']\n        self._text = options['text']\n        self._internal_size = 0, 0  # the real computed text size (inclds pad)\n        self._cached_lines = []\n\n        self.options = options\n        self.texture = None\n        self.resolve_font_name()\n\n    @staticmethod\n    def register(name, fn_regular, fn_italic=None, fn_bold=None,\n                 fn_bolditalic=None):\n        '''Register an alias for a Font.\n\n        .. versionadded:: 1.1.0\n\n        If you're using a ttf directly, you might not be able to use the\n        bold/italic properties of\n        the ttf version. If the font is delivered in multiple files\n        (one regular, one italic and one bold), then you need to register these\n        files and use the alias instead.\n\n        All the fn_regular/fn_italic/fn_bold parameters are resolved with\n        :func:`kivy.resources.resource_find`. If fn_italic/fn_bold are None,\n        fn_regular will be used instead.\n        '''\n\n        fonts = []\n\n        for font_type in fn_regular, fn_italic, fn_bold, fn_bolditalic:\n            if font_type is not None:\n                font = resource_find(font_type)\n\n                if font is None:\n                    raise IOError('File {0}s not found'.format(font_type))\n                else:\n                    fonts.append(font)\n            else:\n                fonts.append(fonts[-1])  # add regular font to list again\n\n        LabelBase._fonts[name] = tuple(fonts)\n\n    def resolve_font_name(self):\n        options = self.options\n        fontname = options['font_name']\n        fonts = self._fonts\n        fontscache = self._fonts_cache\n\n        # is the font is registered ?\n        if fontname in fonts:\n            # return the prefered font for the current bold/italic combinaison\n            italic = int(options['italic'])\n            if options['bold']:\n                bold = FONT_BOLD\n            else:\n                bold = FONT_REGULAR\n\n            options['font_name_r'] = fonts[fontname][italic | bold]\n\n        elif fontname in fontscache:\n            options['font_name_r'] = fontscache[fontname]\n        else:\n            filename = resource_find(fontname)\n            if not filename:\n                fontname = fontname + \\\n                    ('' if fontname.endswith('.ttf') else '.ttf')\n                filename = resource_find(fontname)\n\n            if filename is None:\n                # XXX for compatibility, check directly in the data dir\n                filename = os.path.join(kivy_data_dir, fontname)\n                if not os.path.exists(filename):\n                    raise IOError('Label: File %r not found' % fontname)\n            fontscache[fontname] = filename\n            options['font_name_r'] = filename\n\n    @staticmethod\n    def get_system_fonts_dir():\n        '''Return the Directory used by the system for fonts.\n        '''\n        if LabelBase._fonts_dirs:\n            return LabelBase._fonts_dirs\n\n        fdirs = []\n        if platform == 'linux':\n            fdirs = [\n                '/usr/share/fonts/truetype', '/usr/local/share/fonts',\n                os.path.expanduser('~/.fonts'),\n                os.path.expanduser('~/.local/share/fonts')]\n        elif platform == 'macosx':\n            fdirs = ['/Library/Fonts', '/System/Library/Fonts',\n                os.path.expanduser('~/Library/Fonts')]\n        elif platform == 'win':\n            fdirs = [os.environ['SYSTEMROOT'] + os.sep + 'Fonts']\n        elif platform == 'ios':\n            fdirs = ['/System/Library/Fonts']\n        elif platform == 'android':\n            fdirs = ['/system/fonts']\n\n        if fdirs:\n            fdirs.append(kivy_data_dir + os.sep + 'fonts')\n            # let's register the font dirs\n            rdirs = []\n            for _dir in fdirs:\n                if os.path.exists(_dir):\n                    resource_add_path(_dir)\n                    rdirs.append(_dir)\n            LabelBase._fonts_dirs = rdirs\n            return rdirs\n        raise Exception(\"Unknown Platform {}\".format(platform))\n\n    def get_extents(self, text):\n        '''Return a tuple (width, height) indicating the size of the specified\n        text'''\n        return (0, 0)\n\n    def get_cached_extents(self):\n        '''Returns a cached version of the :meth:`get_extents` function.\n\n        ::\n\n            >>> func = self._get_cached_extents()\n            >>> func\n            <built-in method size of pygame.font.Font object at 0x01E45650>\n            >>> func('a line')\n            (36, 18)\n\n        .. warning::\n\n            This method returns a size measuring function that is valid\n            for the font settings used at the time :meth:`get_cached_extents`\n            was called. Any change in the font settings will render the\n            returned function incorrect. You should only use this if you know\n            what you're doing.\n\n        .. versionadded:: 1.9.0\n        '''\n        return self.get_extents\n\n    def _render_begin(self):\n        pass\n\n    def _render_text(self, text, x, y):\n        pass\n\n    def _render_end(self):\n        pass\n\n    def shorten(self, text, margin=2):\n        ''' Shortens the text to fit into a single line by the width specified\n        by :attr:`text_size` [0]. If :attr:`text_size` [0] is None, it returns\n        text text unchanged.\n\n        :attr:`split_str` and :attr:`shorten_from` determines how the text is\n        shortened.\n\n        :params:\n\n            `text` str, the text to be shortened.\n            `margin` int, the amount of space to leave between the margins\n            and the text. This is in addition to :attr:`padding_x`.\n\n        :retruns:\n            the text shortened to fit into a single line.\n        '''\n        textwidth = self.get_cached_extents()\n        uw = self.text_size[0]\n        if uw is None or not text:\n            return text\n\n        opts = self.options\n        uw = max(0, int(uw - opts['padding_x'] * 2 - margin))\n        # if larger, it won't fit so don't even try extents\n        chr = type(text)\n        text = text.replace(chr('\\n'), chr(' '))\n        if len(text) <= uw and textwidth(text)[0] <= uw:\n            return text\n        c = opts['split_str']\n        offset = 0 if len(c) else 1\n        dir = opts['shorten_from'][0]\n        elps = textwidth('...')[0]\n        if elps > uw:\n            if textwidth('..')[0] <= uw:\n                return '..'\n            else:\n                return '.'\n        uw -= elps\n\n        f = partial(text.find, c)\n        f_rev = partial(text.rfind, c)\n        # now find the first and last word\n        e1, s2 = f(), f_rev()\n\n        if dir != 'l':  # center or right\n            # no split, or the first word doesn't even fit\n            if e1 != -1:\n                l1 = textwidth(text[:e1])[0]\n                l2 = textwidth(text[s2 + 1:])[0]\n            if e1 == -1 or l1 + l2 > uw:\n                if len(c):\n                    opts['split_str'] = ''\n                    res = self.shorten(text, margin)\n                    opts['split_str'] = c\n                    return res\n                # at this point we do char by char so e1 must be zero\n                if l1 <= uw:\n                    return chr('{0}...').format(text[:e1])\n                return chr('...')\n\n            # both word fits, and there's at least on split_str\n            if s2 == e1:  # there's only on split_str\n                return chr('{0}...{1}').format(text[:e1], text[s2 + 1:])\n\n            # both the first and last word fits, and they start/end at diff pos\n            if dir == 'r':\n                ee1 = f(e1 + 1)\n                while l2 + textwidth(text[:ee1])[0] <= uw:\n                    e1 = ee1\n                    if e1 == s2:\n                        break\n                    ee1 = f(e1 + 1)\n            else:\n                while True:\n                    if l1 <= l2:\n                        ee1 = f(e1 + 1)\n                        l1 = textwidth(text[:ee1])[0]\n                        if l2 + l1 > uw:\n                            break\n                        e1 = ee1\n                        if e1 == s2:\n                            break\n                    else:\n                        ss2 = f_rev(0, s2 - offset)\n                        l2 = textwidth(text[ss2 + 1:])[0]\n                        if l2 + l1 > uw:\n                            break\n                        s2 = ss2\n                        if e1 == s2:\n                            break\n        else:  # left\n            # no split, or the last word doesn't even fit\n            if s2 != -1:\n                l2 = textwidth(text[s2 + (1 if len(c) else -1):])[0]\n                l1 = textwidth(text[:max(0, e1)])[0]\n            # if split_str\n            if s2 == -1 or l2 + l1 > uw:\n                if len(c):\n                    opts['split_str'] = ''\n                    res = self.shorten(text, margin)\n                    opts['split_str'] = c\n                    return res\n\n                return chr('...')\n\n            # both word fits, and there's at least on split_str\n            if s2 == e1:  # there's only on split_str\n                return chr('{0}...{1}').format(text[:e1], text[s2 + 1:])\n\n            # both the first and last word fits, and they start/end at diff pos\n            ss2 = f_rev(0, s2 - offset)\n            while l1 + textwidth(text[ss2 + 1:])[0] <= uw:\n                s2 = ss2\n                if s2 == e1:\n                    break\n                ss2 = f_rev(0, s2 - offset)\n\n        return chr('{0}...{1}').format(text[:e1], text[s2 + 1:])\n\n    def _render_real(self):\n        lines = self._cached_lines\n        options = None\n        for line in lines:\n            if len(line.words):  # get opts from first line, first word\n                options = line.words[0].options\n                break\n        if not options:  # there was no text to render\n            self._render_begin()\n            data = self._render_end()\n            assert(data)\n            if data is not None and data.width > 1:\n                self.texture.blit_data(data)\n            return\n\n        render_text = self._render_text\n        get_extents = self.get_cached_extents()\n        uw, uh = options['text_size']\n        xpad, ypad = options['padding_x'], options['padding_y']\n        x, y = xpad, ypad   # pos in the texture\n        iw, ih = self._internal_size  # the real size of text, not texture\n        if uw is not None:\n            uww = uw - 2 * xpad  # real width of just text\n        w, h = self.size\n        sw = options['space_width']\n        halign = options['halign']\n        valign = options['valign']\n        split = re.split\n        pat = re.compile('( +)')\n        self._render_begin()\n\n        if valign == 'bottom':\n            y = h - ih + ypad\n        elif valign == 'middle':\n            y = int((h - ih) / 2 + ypad)\n\n        for layout_line in lines:  # for plain label each line has only one str\n            lw, lh = layout_line.w, layout_line.h\n            line = ''\n            assert len(layout_line.words) < 2\n            if len(layout_line.words):\n                last_word = layout_line.words[0]\n                line = last_word.text\n            x = xpad\n            if halign[0] == 'c':  # center\n                x = int((w - lw) / 2.)\n            elif halign[0] == 'r':  # right\n                x = max(0, int(w - lw - xpad))\n\n            # right left justify\n            # divide left over space between `spaces`\n            # TODO implement a better method of stretching glyphs?\n            if (uw is not None and halign[-1] == 'y' and line and not\n                layout_line.is_last_line):\n                # number spaces needed to fill, and remainder\n                n, rem = divmod(max(uww - lw, 0), sw)\n                n = int(n)\n                words = None\n                if n or rem:\n                    # there's no trailing space when justify is selected\n                    words = split(pat, line)\n                if words is not None and len(words) > 1:\n                    space = type(line)(' ')\n                    # words: every even index is spaces, just add ltr n spaces\n                    for i in range(n):\n                        idx = (2 * i + 1) % (len(words) - 1)\n                        words[idx] = words[idx] + space\n                    if rem:\n                        # render the last word at the edge, also add it to line\n                        ext = get_extents(words[-1])\n                        word = LayoutWord(last_word.options, ext[0], ext[1],\n                                          words[-1])\n                        layout_line.words.append(word)\n                        last_word.lw = uww - ext[0]  # word was stretched\n                        render_text(words[-1], x + last_word.lw, y)\n                        last_word.text = line = ''.join(words[:-2])\n                    else:\n                        last_word.lw = uww  # word was stretched\n                        last_word.text = line = ''.join(words)\n                    layout_line.w = uww  # the line occupies full width\n\n            if len(line):\n                layout_line.x = x\n                layout_line.y = y\n                render_text(line, x, y)\n            y += lh\n\n        # get data from provider\n        data = self._render_end()\n        assert(data)\n\n        # If the text is 1px width, usually, the data is black.\n        # Don't blit that kind of data, otherwise, you have a little black bar.\n        if data is not None and data.width > 1:\n            self.texture.blit_data(data)\n\n    def render(self, real=False):\n        '''Return a tuple (width, height) to create the image\n        with the user constraints. (width, height) includes the padding.\n        '''\n        if real:\n            return self._render_real()\n\n        options = copy(self.options)\n        options['space_width'] = self.get_extents(' ')[0]\n        options['strip'] = strip = (options['strip'] or\n                                    options['halign'][-1] == 'y')\n        uw, uh = options['text_size'] = self._text_size\n        text = self.text\n        if strip:\n            text = text.strip()\n        if uw is not None and options['shorten']:\n            text = self.shorten(text)\n        self._cached_lines = lines = []\n        if not text:\n            return 0, 0\n\n        if uh is not None and options['valign'][-1] == 'e':  # middle\n            center = -1  # pos of newline\n            if len(text) > 1:\n                middle = int(len(text) // 2)\n                l, r = text.rfind('\\n', 0, middle), text.find('\\n', middle)\n                if l != -1 and r != -1:\n                    center = l if center - l <= r - center else r\n                elif l != -1:\n                    center = l\n                elif r != -1:\n                    center = r\n            # if a newline split text, render from center down and up til uh\n            if center != -1:\n                # layout from center down until half uh\n                w, h, clipped = layout_text(text[center + 1:], lines, (0, 0),\n                (uw, uh / 2), options, self.get_cached_extents(), True, True)\n                # now layout from center upwards until uh is reached\n                w, h, clipped = layout_text(text[:center + 1], lines, (w, h),\n                (uw, uh), options, self.get_cached_extents(), False, True)\n            else:  # if there's no new line, layout everything\n                w, h, clipped = layout_text(text, lines, (0, 0), (uw, None),\n                options, self.get_cached_extents(), True, True)\n        else:  # top or bottom\n            w, h, clipped = layout_text(text, lines, (0, 0), (uw, uh), options,\n                self.get_cached_extents(), options['valign'][-1] == 'p', True)\n        self._internal_size = w, h\n        if uw:\n            w = uw\n        if uh:\n            h = uh\n        if h > 1 and w < 2:\n            w = 2\n        return int(w), int(h)\n\n    def _texture_refresh(self, *l):\n        self.refresh()\n\n    def _texture_fill(self, texture):\n        # second pass, render for real\n        self.render(real=True)\n\n    def refresh(self):\n        '''Force re-rendering of the text\n        '''\n        self.resolve_font_name()\n\n        # first pass, calculating width/height\n        sz = self.render()\n        self._size_texture = sz\n        self._size = (sz[0], sz[1])\n\n        # if no text are rendered, return nothing.\n        width, height = self._size\n        if width <= 1 or height <= 1:\n            self.texture = self.texture_1px\n            return\n\n        # create a delayed texture\n        texture = self.texture\n        if texture is None or \\\n                width != texture.width or \\\n                height != texture.height:\n            texture = Texture.create(size=(width, height),\n                                     mipmap=self.options['mipmap'],\n                                     callback=self._texture_fill)\n            texture.flip_vertical()\n            texture.add_reload_observer(self._texture_refresh)\n            self.texture = texture\n        else:\n            texture.ask_update(self._texture_fill)\n\n    def _get_text(self):\n        if PY2:\n            try:\n                if isinstance(self._text, unicode):\n                    return self._text\n                return self._text.decode('utf8')\n            except AttributeError:\n                # python 3 support\n                return str(self._text)\n            except UnicodeDecodeError:\n                return self._text\n        else:\n            return self._text\n\n    def _set_text(self, text):\n        if text != self._text:\n            self._text = text\n\n    text = property(_get_text, _set_text, doc='Get/Set the text')\n    label = property(_get_text, _set_text, doc='Get/Set the text')\n\n    @property\n    def texture_1px(self):\n        if LabelBase._texture_1px is None:\n            tex = Texture.create(size=(1, 1), colorfmt='rgba')\n            tex.blit_buffer(b'\\x00\\x00\\x00\\x00', colorfmt='rgba')\n            LabelBase._texture_1px = tex\n        return LabelBase._texture_1px\n\n    @property\n    def size(self):\n        return self._size\n\n    @property\n    def width(self):\n        return self._size[0]\n\n    @property\n    def height(self):\n        return self._size[1]\n\n    @property\n    def content_width(self):\n        '''Return the content width; i.e. the width of the text without\n        any padding.'''\n        if self.texture is None:\n            return 0\n        return self.texture.width - 2 * self.options['padding_x']\n\n    @property\n    def content_height(self):\n        '''Return the content height; i.e. the height of the text without\n        any padding.'''\n        if self.texture is None:\n            return 0\n        return self.texture.height - 2 * self.options['padding_y']\n\n    @property\n    def content_size(self):\n        '''Return the content size (width, height)'''\n        if self.texture is None:\n            return (0, 0)\n        return (self.content_width, self.content_height)\n\n    @property\n    def fontid(self):\n        '''Return a unique id for all font parameters'''\n        return str([self.options[x] for x in (\n            'font_size', 'font_name_r', 'bold', 'italic')])\n\n    def _get_text_size(self):\n        return self._text_size\n\n    def _set_text_size(self, x):\n        self._text_size = x\n\n    text_size = property(_get_text_size, _set_text_size,\n                         doc='''Get/set the (width, height) of the '\n                         'contrained rendering box''')\n\n    usersize = property(_get_text_size, _set_text_size,\n                        doc='''(deprecated) Use text_size instead.''')\n\n# Load the appropriate provider\nlabel_libs = []\nif USE_SDL2:\n    label_libs += [('sdl2', 'text_sdl2', 'LabelSDL2')]\nelse:\n    label_libs += [('pygame', 'text_pygame', 'LabelPygame')]\nlabel_libs += [\n    ('pil', 'text_pil', 'LabelPIL')]\nLabel = core_select_lib('text', label_libs)\n\nif 'KIVY_DOC' not in os.environ:\n    if not Label:\n        from kivy.logger import Logger\n        import sys\n        Logger.critical('App: Unable to get a Text provider, abort.')\n        sys.exit(1)\n\n# For the first initalization, register the default font\n    Label.register('DroidSans',\n                   'data/fonts/DroidSans.ttf',\n                   'data/fonts/DroidSans-Italic.ttf',\n                   'data/fonts/DroidSans-Bold.ttf',\n                   'data/fonts/DroidSans-BoldItalic.ttf')\n\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/text/markup.py",
    "content": "'''\nText Markup\n===========\n\n.. versionadded:: 1.1.0\n\nWe provide a simple text-markup for inline text styling. The syntax look the\nsame as the `BBCode <http://en.wikipedia.org/wiki/BBCode>`_.\n\nA tag is defined as ``[tag]``, and might have a closed tag associated:\n``[/tag]``. Example of a markup text::\n\n    [b]Hello [color=ff0000]world[/b][/color]\n\nThe following tags are availables:\n\n``[b][/b]``\n    Activate bold text\n``[i][/i]``\n    Activate italic text\n``[font=<str>][/font]``\n    Change the font\n``[size=<integer>][/size]``\n    Change the font size\n``[color=#<color>][/color]``\n    Change the text color\n``[ref=<str>][/ref]``\n    Add an interactive zone. The reference + all the word box inside the\n    reference will be available in :attr:`MarkupLabel.refs`\n``[anchor=<str>]``\n    Put an anchor in the text. You can get the position of your anchor within\n    the text with :attr:`MarkupLabel.anchors`\n``[sub][/sub]``\n    Display the text at a subscript position relative to the text before it.\n``[sup][/sup]``\n    Display the text at a superscript position relative to the text before it.\n\nIf you need to escape the markup from the current text, use\n:func:`kivy.utils.escape_markup`.\n'''\n\n__all__ = ('MarkupLabel', )\n\nimport re\nfrom kivy.properties import dpi2px\nfrom kivy.parser import parse_color\nfrom kivy.logger import Logger\nfrom kivy.core.text import Label, LabelBase\nfrom kivy.core.text.text_layout import layout_text, LayoutWord, LayoutLine\nfrom copy import copy\nfrom math import ceil\nfrom functools import partial\n\n# We need to do this trick when documentation is generated\nMarkupLabelBase = Label\nif Label is None:\n    MarkupLabelBase = LabelBase\n\n\nclass MarkupLabel(MarkupLabelBase):\n    '''Markup text label.\n\n    See module documentation for more informations.\n    '''\n\n    def __init__(self, *largs, **kwargs):\n        self._style_stack = {}\n        self._refs = {}\n        self._anchors = {}\n        super(MarkupLabel, self).__init__(*largs, **kwargs)\n        self._internal_size = 0, 0\n        self._cached_lines = []\n\n    @property\n    def refs(self):\n        '''Get the bounding box of all the ``[ref=...]``::\n\n            { 'refA': ((x1, y1, x2, y2), (x1, y1, x2, y2)), ... }\n        '''\n        return self._refs\n\n    @property\n    def anchors(self):\n        '''Get the position of all the ``[anchor=...]``::\n\n            { 'anchorA': (x, y), 'anchorB': (x, y), ... }\n        '''\n        return self._anchors\n\n    @property\n    def markup(self):\n        '''Return the text with all the markup splitted::\n\n            >>> MarkupLabel('[b]Hello world[/b]').markup\n            >>> ('[b]', 'Hello world', '[/b]')\n\n        '''\n        s = re.split('(\\[.*?\\])', self.label)\n        s = [x for x in s if x != '']\n        return s\n\n    def _push_style(self, k):\n        if not k in self._style_stack:\n            self._style_stack[k] = []\n        self._style_stack[k].append(self.options[k])\n\n    def _pop_style(self, k):\n        if k not in self._style_stack or len(self._style_stack[k]) == 0:\n            Logger.warning('Label: pop style stack without push')\n            return\n        v = self._style_stack[k].pop()\n        self.options[k] = v\n\n    def render(self, real=False):\n        options = copy(self.options)\n        if not real:\n            ret = self._pre_render()\n        else:\n            ret = self._real_render()\n        self.options = options\n        return ret\n\n    def _pre_render(self):\n        # split markup, words, and lines\n        # result: list of word with position and width/height\n        # during the first pass, we don't care about h/valign\n        self._cached_lines = lines = []\n        self._refs = {}\n        self._anchors = {}\n        clipped = False\n        w = h = 0\n        uw, uh = self.text_size\n        spush = self._push_style\n        spop = self._pop_style\n        opts = options = self.options\n        options['_ref'] = None\n        options['_anchor'] = None\n        options['script'] = 'normal'\n        shorten = options['shorten']\n        # if shorten, then don't split lines to fit uw, because it will be\n        # flattened later when shortening and broken up lines if broken\n        # mid-word will have space mid-word when lines are joined\n        uw_temp = None if shorten else uw\n        xpad = options['padding_x']\n        uhh = (None if uh is not None and options['valign'][-1] != 'p' or\n               options['shorten'] else uh)\n        options['strip'] = options['strip'] or options['halign'][-1] == 'y'\n        for item in self.markup:\n            if item == '[b]':\n                spush('bold')\n                options['bold'] = True\n                self.resolve_font_name()\n            elif item == '[/b]':\n                spop('bold')\n                self.resolve_font_name()\n            elif item == '[i]':\n                spush('italic')\n                options['italic'] = True\n                self.resolve_font_name()\n            elif item == '[/i]':\n                spop('italic')\n                self.resolve_font_name()\n            elif item[:6] == '[size=':\n                item = item[6:-1]\n                try:\n                    if item[-2:] in ('px', 'pt', 'in', 'cm', 'mm', 'dp', 'sp'):\n                        size = dpi2px(item[:-2], item[-2:])\n                    else:\n                        size = int(item)\n                except ValueError:\n                    raise\n                    size = options['font_size']\n                spush('font_size')\n                options['font_size'] = size\n            elif item == '[/size]':\n                spop('font_size')\n            elif item[:7] == '[color=':\n                color = parse_color(item[7:-1])\n                spush('color')\n                options['color'] = color\n            elif item == '[/color]':\n                spop('color')\n            elif item[:6] == '[font=':\n                fontname = item[6:-1]\n                spush('font_name')\n                options['font_name'] = fontname\n                self.resolve_font_name()\n            elif item == '[/font]':\n                spop('font_name')\n                self.resolve_font_name()\n            elif item[:5] == '[sub]':\n                spush('font_size')\n                spush('script')\n                options['font_size'] = options['font_size'] * .5\n                options['script'] = 'subscript'\n            elif item == '[/sub]':\n                spop('font_size')\n                spop('script')\n            elif item[:5] == '[sup]':\n                spush('font_size')\n                spush('script')\n                options['font_size'] = options['font_size'] * .5\n                options['script'] = 'superscript'\n            elif item == '[/sup]':\n                spop('font_size')\n                spop('script')\n            elif item[:5] == '[ref=':\n                ref = item[5:-1]\n                spush('_ref')\n                options['_ref'] = ref\n            elif item == '[/ref]':\n                spop('_ref')\n            elif not clipped and item[:8] == '[anchor=':\n                options['_anchor'] = item[8:-1]\n            elif not clipped:\n                item = item.replace('&bl;', '[').replace(\n                    '&br;', ']').replace('&amp;', '&')\n                opts = copy(options)\n                extents = self.get_cached_extents()\n                opts['space_width'] = extents(' ')[0]\n                w, h, clipped = layout_text(item, lines, (w, h),\n                    (uw_temp, uhh), opts, extents, True, False)\n\n        if len(lines):  # remove any trailing spaces from the last line\n            old_opts = self.options\n            self.options = copy(opts)\n            w, h, clipped = layout_text('', lines, (w, h), (uw_temp, uhh),\n                self.options, self.get_cached_extents(), True, True)\n            self.options = old_opts\n\n        if shorten:\n            options['_ref'] = None  # no refs for you!\n            options['_anchor'] = None\n            w, h, lines = self.shorten_post(lines, w, h)\n            self._cached_lines = lines\n        # when valign is not top, for markup we layout everything (text_size[1]\n        # is temporarily set to None) and after layout cut to size if too tall\n        elif uh != uhh and h > uh and len(lines) > 1:\n            if options['valign'][-1] == 'm':  # bottom\n                i = 0\n                while i < len(lines) - 1 and h > uh:\n                    h -= lines[i].h\n                    i += 1\n                del lines[:i]\n            else:  # middle\n                i = 0\n                top = int(h / 2. + uh / 2.)  # remove extra top portion\n                while i < len(lines) - 1 and h > top:\n                    h -= lines[i].h\n                    i += 1\n                del lines[:i]\n                i = len(lines) - 1  # remove remaining bottom portion\n                while i and h > uh:\n                    h -= lines[i].h\n                    i -= 1\n                del lines[i + 1:]\n\n        # now justify the text\n        if options['halign'][-1] == 'y' and uw is not None:\n            # XXX: update refs to justified pos\n            # when justify, each line shouldv'e been stripped already\n            split = partial(re.split, re.compile('( +)'))\n            uww = uw - 2 * xpad\n            chr = type(self.text)\n            space = chr(' ')\n            empty = chr('')\n\n            for i in range(len(lines)):\n                line = lines[i]\n                words = line.words\n                # if there's nothing to justify, we're done\n                if (not line.w or int(uww - line.w) <= 0 or not len(words) or\n                    line.is_last_line):\n                    continue\n\n                done = False\n                parts = [None, ] * len(words)  # contains words split by space\n                idxs = [None, ] * len(words)  # indices of the space in parts\n                # break each word into spaces and add spaces until it's full\n                # do first round of split in case we don't need to split all\n                for w in range(len(words)):\n                    word = words[w]\n                    sw = word.options['space_width']\n                    p = parts[w] = split(word.text)\n                    idxs[w] = [v for v in range(len(p)) if\n                               p[v].startswith(' ')]\n                    # now we have the indices of the spaces in split list\n                    for k in idxs[w]:\n                        # try to add single space at each space\n                        if line.w + sw > uww:\n                            done = True\n                            break\n                        line.w += sw\n                        word.lw += sw\n                        p[k] += space\n                    if done:\n                        break\n\n                # there's not a single space in the line?\n                if not any(idxs):\n                    continue\n\n                # now keep adding spaces to already split words until done\n                while not done:\n                    for w in range(len(words)):\n                        if not idxs[w]:\n                            continue\n                        word = words[w]\n                        sw = word.options['space_width']\n                        p = parts[w]\n                        for k in idxs[w]:\n                            # try to add single space at each space\n                            if line.w + sw > uww:\n                                done = True\n                                break\n                            line.w += sw\n                            word.lw += sw\n                            p[k] += space\n                        if done:\n                            break\n\n                # if not completely full, push last words to right edge\n                diff = int(uww - line.w)\n                if diff > 0:\n                    # find the last word that had a space\n                    for w in range(len(words) - 1, -1, -1):\n                        if not idxs[w]:\n                            continue\n                        break\n                    old_opts = self.options\n                    self.options = word.options\n                    word = words[w]\n                    # split that word into left/right and push right till uww\n                    l_text = empty.join(parts[w][:idxs[w][-1]])\n                    r_text = empty.join(parts[w][idxs[w][-1]:])\n                    left = LayoutWord(word.options,\n                        self.get_extents(l_text)[0], word.lh, l_text)\n                    right = LayoutWord(word.options,\n                        self.get_extents(r_text)[0], word.lh, r_text)\n                    left.lw = max(left.lw, word.lw + diff - right.lw)\n                    self.options = old_opts\n\n                    # now put words back together with right/left inserted\n                    for k in range(len(words)):\n                        if idxs[k]:\n                            words[k].text = empty.join(parts[k])\n                    words[w] = right\n                    words.insert(w, left)\n                else:\n                    for k in range(len(words)):\n                        if idxs[k]:\n                            words[k].text = empty.join(parts[k])\n                line.w = uww\n                w = max(w, uww)\n\n        self._internal_size = w, h\n        if uw:\n            w = uw\n        if uh:\n            h = uh\n        if h > 1 and w < 2:\n            w = 2\n        if w < 1:\n            w = 1\n        if h < 1:\n            h = 1\n        return int(w), int(h)\n\n    def _real_render(self):\n        lines = self._cached_lines\n        options = None\n        for line in lines:\n            if len(line.words):  # get opts from first line, first word\n                options = line.words[0].options\n                break\n        if not options:  # there was no text to render\n            self._render_begin()\n            data = self._render_end()\n            assert(data)\n            if data is not None and data.width > 1:\n                self.texture.blit_data(data)\n            return\n\n        old_opts = self.options\n        render_text = self._render_text\n        xpad, ypad = options['padding_x'], options['padding_y']\n        x, y = xpad, ypad   # pos in the texture\n        iw, ih = self._internal_size  # the real size of text, not texture\n        w, h = self.size\n        halign = options['halign']\n        valign = options['valign']\n        refs = self._refs\n        anchors = self._anchors\n        self._render_begin()\n\n        if valign == 'bottom':\n            y = h - ih + ypad\n        elif valign == 'middle':\n            y = int((h - ih) / 2 + ypad)\n\n        for layout_line in lines:  # for plain label each line has only one str\n            lw, lh = layout_line.w, layout_line.h\n            x = xpad\n            if halign[0] == 'c':  # center\n                x = int((w - lw) / 2.)\n            elif halign[0] == 'r':  # right\n                x = max(0, int(w - lw - xpad))\n            layout_line.x = x\n            layout_line.y = y\n            psp = pph = 0\n            for word in layout_line.words:\n                options = self.options = word.options\n                # the word height is not scaled by line_height, only lh was\n                wh = options['line_height'] * word.lh\n                # calculate sub/super script pos\n                if options['script'] == 'superscript':\n                    script_pos = max(0, psp if psp else self.get_descent())\n                    psp = script_pos\n                    pph = wh\n                elif options['script'] == 'subscript':\n                    script_pos = min(lh - wh, ((psp + pph) - wh)\n                                     if pph else (lh - wh))\n                    pph = wh\n                    psp = script_pos\n                else:\n                    script_pos = (lh - wh) / 1.25\n                    psp = pph = 0\n                if len(word.text):\n                    render_text(word.text, x, y + script_pos)\n\n                # should we record refs ?\n                ref = options['_ref']\n                if ref is not None:\n                    if not ref in refs:\n                        refs[ref] = []\n                    refs[ref].append((x, y, x + word.lw, y + wh))\n\n                # Should we record anchors?\n                anchor = options['_anchor']\n                if anchor is not None:\n                    if not anchor in anchors:\n                        anchors[anchor] = (x, y)\n                x += word.lw\n            y += lh\n\n        self.options = old_opts\n        # get data from provider\n        data = self._render_end()\n        assert(data)\n\n        # If the text is 1px width, usually, the data is black.\n        # Don't blit that kind of data, otherwise, you have a little black bar.\n        if data is not None and data.width > 1:\n            self.texture.blit_data(data)\n\n    def shorten_post(self, lines, w, h, margin=2):\n        ''' Shortens the text to a single line according to the label options.\n\n        This function operates on a text that has already been laid out because\n        for markup, parts of text can have different size and options.\n\n        If :attr:`text_size` [0] is None, the lines are returned unchanged.\n        Otherwise, the lines are converted to a single line fitting within the\n        constrained width, :attr:`text_size` [0].\n\n        :params:\n\n            `lines`: list of `LayoutLine` instances describing the text.\n            `w`: int, the width of the text in lines, including padding.\n            `h`: int, the height of the text in lines, including padding.\n            `margin` int, the additional space left on the sides. This is in\n            addition to :attr:`padding_x`.\n\n        :returns:\n            3-tuple of (xw, h, lines), where w, and h is similar to the input\n            and contains the resulting width / height of the text, including\n            padding. lines, is a list containing a single `LayoutLine`, which\n            contains the words for the line.\n        '''\n\n        def n(line, c):\n            ''' A function similar to text.find, except it's an iterator that\n            returns successive occurrences of string c in list line. line is\n            not a string, but a list of LayoutWord instances that we walk\n            from left to right returning the indices of c in the words as we\n            encounter them. Note that the options can be different among the\n            words.\n\n            :returns:\n                3-tuple: the index of the word in line, the index of the\n                occurrence in word, and the extents (width) of the combined\n                words until this occurrence, not including the occurrence char.\n                If no more are found it returns (-1, -1, total_w) where total_w\n                is the full width of all the words.\n            '''\n            total_w = 0\n            for w in range(len(line)):\n                word = line[w]\n                if not word.lw:\n                    continue\n                f = partial(word.text.find, c)\n                i = f()\n                while i != -1:\n                    self.options = word.options\n                    yield w, i, total_w + self.get_extents(word.text[:i])[0]\n                    i = f(i + 1)\n                self.options = word.options\n                total_w += self.get_extents(word.text)[0]\n            yield -1, -1, total_w  # this should never be reached, really\n\n        def p(line, c):\n            ''' Similar to the `n` function, except it returns occurrences of c\n            from right to left in the list, line, similar to rfind.\n            '''\n            total_w = 0\n            offset = 0 if len(c) else 1\n            for w in range(len(line) - 1, -1, -1):\n                word = line[w]\n                if not word.lw:\n                    continue\n                f = partial(word.text.rfind, c)\n                i = f()\n                while i != -1:\n                    self.options = word.options\n                    yield (w, i, total_w +\n                           self.get_extents(word.text[i + 1:])[0])\n                    if i:\n                        i = f(0, i - offset)\n                    else:\n                        if not c:\n                            self.options = word.options\n                            yield (w, -1, total_w +\n                                   self.get_extents(word.text)[0])\n                        break\n                self.options = word.options\n                total_w += self.get_extents(word.text)[0]\n            yield -1, -1, total_w  # this should never be reached, really\n\n        def n_restricted(line, uw, c):\n            ''' Similar to the function `n`, except it only returns the first\n            occurrence and it's not an iterator. Furthermore, if the first\n            occurrence doesn't fit within width uw, it returns the index of\n            whatever amount of text will still fit in uw.\n\n            :returns:\n                similar to the function `n`, except it's a 4-tuple, with the\n                last element a boolean, indicating if we had to clip the text\n                to fit in uw (True) or if the whole text until the first\n                occurrence fitted in uw (False).\n            '''\n            total_w = 0\n            if not len(line):\n                return 0, 0, 0\n            for w in range(len(line)):\n                word = line[w]\n                f = partial(word.text.find, c)\n                self.options = word.options\n                extents = self.get_cached_extents()\n                i = f()\n                if i != -1:\n                    ww = extents(word.text[:i])[0]\n\n                if i != -1 and total_w + ww <= uw:  # found and it fits\n                    return w, i, total_w + ww, False\n                elif i == -1:\n                    ww = extents(word.text)[0]\n                    if total_w + ww <= uw:  # wasn't found and all fits\n                        total_w += ww\n                        continue\n                    i = len(word.text)\n\n                # now just find whatever amount of the word does fit\n                e = 0\n                while e != i and total_w + extents(word.text[:e])[0] <= uw:\n                    e += 1\n                e = max(0, e - 1)\n                return w, e, total_w + extents(word.text[:e])[0], True\n\n            return -1, -1, total_w, False\n\n        def p_restricted(line, uw, c):\n            ''' Similar to `n_restricted`, except it returns the first\n            occurrence starting from the right, like `p`.\n            '''\n            total_w = 0\n            if not len(line):\n                return 0, 0, 0\n            for w in range(len(line) - 1, -1, -1):\n                word = line[w]\n                f = partial(word.text.rfind, c)\n                self.options = word.options\n                extents = self.get_cached_extents()\n                i = f()\n                if i != -1:\n                    ww = extents(word.text[i + 1:])[0]\n\n                if i != -1 and total_w + ww <= uw:  # found and it fits\n                    return w, i, total_w + ww, False\n                elif i == -1:\n                    ww = extents(word.text)[0]\n                    if total_w + ww <= uw:  # wasn't found and all fits\n                        total_w += ww\n                        continue\n\n                # now just find whatever amount of the word does fit\n                s = len(word.text) - 1\n                while s >= 0 and total_w + extents(word.text[s:])[0] <= uw:\n                    s -= 1\n                return w, s, total_w + extents(word.text[s + 1:])[0], True\n\n            return -1, -1, total_w, False\n\n        textwidth = self.get_cached_extents()\n        uw = self.text_size[0]\n        if uw is None:\n            return w, h, lines\n        old_opts = copy(self.options)\n        uw = max(0, int(uw - old_opts['padding_x'] * 2 - margin))\n        chr = type(self.text)\n        ssize = textwidth(' ')\n        c = old_opts['split_str']\n        line_height = old_opts['line_height']\n        xpad, ypad = old_opts['padding_x'], old_opts['padding_y']\n        dir = old_opts['shorten_from'][0]\n\n        # flatten lines into single line\n        line = []\n        last_w = 0\n        for l in range(len(lines)):\n            # concatenate (non-empty) inside lines with a space\n            this_line = lines[l]\n            if last_w and this_line.w and not this_line.line_wrap:\n                line.append(LayoutWord(old_opts, ssize[0], ssize[1], chr(' ')))\n            last_w = this_line.w or last_w\n            for word in this_line.words:\n                if word.lw:\n                    line.append(word)\n\n        # if that fits, just return the flattened line\n        lw = sum([word.lw for word in line])\n        if lw <= uw:\n            lh = max([word.lh for word in line] + [0]) * line_height\n            return lw + 2 * xpad, lh + 2 * ypad, [LayoutLine(0, 0,\n            lw, lh, 1, 0, line)]\n\n        # find the size of ellipsis that'll fit\n        elps_s = textwidth('...')\n        if elps_s[0] > uw:  # even ellipsis didn't fit...\n            s = textwidth('..')\n            if s[0] <= uw:\n                return (s[0] + 2 * xpad, s[1] * line_height + 2 * ypad,\n                    [LayoutLine(0, 0, s[0], s[1], 1, 0, [LayoutWord(old_opts,\n                    s[0], s[1], '..')])])\n            else:\n                s = textwidth('.')\n                return (s[0] + 2 * xpad, s[1] * line_height + 2 * ypad,\n                    [LayoutLine(0, 0, s[0], s[1], 1, 0, [LayoutWord(old_opts,\n                    s[0], s[1], '.')])])\n        elps = LayoutWord(old_opts, elps_s[0], elps_s[1], '...')\n        uw -= elps_s[0]\n\n        # now find the first left and right words that fit\n        w1, e1, l1, clipped1 = n_restricted(line, uw, c)\n        w2, s2, l2, clipped2 = p_restricted(line, uw, c)\n\n        if dir != 'l':  # center or right\n            line1 = None\n            if clipped1 or clipped2 or l1 + l2 > uw:\n                # if either was clipped or both don't fit, just take first\n                if len(c):\n                    self.options = old_opts\n                    old_opts['split_str'] = ''\n                    res = self.shorten_post(lines, w, h, margin)\n                    self.options['split_str'] = c\n                    return res\n                line1 = line[:w1]\n                last_word = line[w1]\n                last_text = last_word.text[:e1]\n                self.options = last_word.options\n                s = self.get_extents(last_text)\n                line1.append(LayoutWord(last_word.options, s[0], s[1],\n                                        last_text))\n            elif (w1, e1) == (-1, -1):  # this shouldn't occur\n                line1 = line\n            if line1:\n                line1.append(elps)\n                lw = sum([word.lw for word in line1])\n                lh = max([word.lh for word in line1]) * line_height\n                self.options = old_opts\n                return lw + 2 * xpad, lh + 2 * ypad, [LayoutLine(0, 0,\n                    lw, lh, 1, 0, line1)]\n\n            # now we know that both the first and last word fit, and that\n            # there's at least one instances of the split_str in the line\n            if (w1, e1) != (w2, s2):  # more than one split_str\n                if dir == 'r':\n                    f = n(line, c)  # iterator\n                    assert next(f)[:-1] == (w1, e1)  # first word should match\n                    ww1, ee1, l1 = next(f)\n                    while l2 + l1 <= uw:\n                        w1, e1 = ww1, ee1\n                        ww1, ee1, l1 = next(f)\n                        if (w1, e1) == (w2, s2):\n                            break\n                else:   # center\n                    f = n(line, c)  # iterator\n                    f_inv = p(line, c)  # iterator\n                    assert next(f)[:-1] == (w1, e1)\n                    assert next(f_inv)[:-1] == (w2, s2)\n                    while True:\n                        if l1 <= l2:\n                            ww1, ee1, l1 = next(f)  # hypothesize that next fit\n                            if l2 + l1 > uw:\n                                break\n                            w1, e1 = ww1, ee1\n                            if (w1, e1) == (w2, s2):\n                                break\n                        else:\n                            ww2, ss2, l2 = next(f_inv)\n                            if l2 + l1 > uw:\n                                break\n                            w2, s2 = ww2, ss2\n                            if (w1, e1) == (w2, s2):\n                                break\n        else:  # left\n            line1 = [elps]\n            if clipped1 or clipped2 or l1 + l2 > uw:\n                # if either was clipped or both don't fit, just take last\n                if len(c):\n                    self.options = old_opts\n                    old_opts['split_str'] = ''\n                    res = self.shorten_post(lines, w, h, margin)\n                    self.options['split_str'] = c\n                    return res\n                first_word = line[w2]\n                first_text = first_word.text[s2 + 1:]\n                self.options = first_word.options\n                s = self.get_extents(first_text)\n                line1.append(LayoutWord(first_word.options, s[0], s[1],\n                                        first_text))\n                line1.extend(line[w2 + 1:])\n            elif (w1, e1) == (-1, -1):  # this shouldn't occur\n                line1 = line\n            if len(line1) != 1:\n                lw = sum([word.lw for word in line1])\n                lh = max([word.lh for word in line1]) * line_height\n                self.options = old_opts\n                return lw + 2 * xpad, lh + 2 * ypad, [LayoutLine(0, 0,\n                    lw, lh, 1, 0, line1)]\n\n            # now we know that both the first and last word fit, and that\n            # there's at least one instances of the split_str in the line\n            if (w1, e1) != (w2, s2):  # more than one split_str\n                f_inv = p(line, c)  # iterator\n                assert next(f_inv)[:-1] == (w2, s2)  # last word should match\n                ww2, ss2, l2 = next(f_inv)\n                while l2 + l1 <= uw:\n                    w2, s2 = ww2, ss2\n                    ww2, ss2, l2 = next(f_inv)\n                    if (w1, e1) == (w2, s2):\n                        break\n\n        # now add back the left half\n        line1 = line[:w1]\n        last_word = line[w1]\n        last_text = last_word.text[:e1]\n        self.options = last_word.options\n        s = self.get_extents(last_text)\n        if len(last_text):\n            line1.append(LayoutWord(last_word.options, s[0], s[1], last_text))\n        line1.append(elps)\n\n        # now add back the right half\n        first_word = line[w2]\n        first_text = first_word.text[s2 + 1:]\n        self.options = first_word.options\n        s = self.get_extents(first_text)\n        if len(first_text):\n            line1.append(LayoutWord(first_word.options, s[0], s[1],\n                                    first_text))\n        line1.extend(line[w2 + 1:])\n\n        lw = sum([word.lw for word in line1])\n        lh = max([word.lh for word in line1]) * line_height\n        self.options = old_opts\n        return lw + 2 * xpad, lh + 2 * ypad, [LayoutLine(0, 0,\n            lw, lh, 1, 0, line1)]\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/text/text_layout.pxd",
    "content": "\n\ncdef class LayoutWord:\n    cdef public object text\n    cdef public int lw, lh\n    cdef public dict options\n\n\ncdef class LayoutLine:\n    cdef public int x, y, w, h\n    cdef public int line_wrap  # whether this line wraps from last line\n    cdef public int is_last_line  # in a paragraph\n    cdef public list words\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/text/text_pil.py",
    "content": "'''\nText PIL: Draw text with PIL\n'''\n\n__all__ = ('LabelPIL', )\n\ntry:\n    from PIL import Image, ImageFont, ImageDraw\nexcept:\n    raise\n\nfrom kivy.compat import text_type\nfrom kivy.core.text import LabelBase\nfrom kivy.core.image import ImageData\n\n# used for fetching extends before creature image surface\ndefault_font = ImageFont.load_default()\n\n\nclass LabelPIL(LabelBase):\n    _cache = {}\n\n    def _select_font(self):\n        fontsize = int(self.options['font_size'])\n        fontname = self.options['font_name_r']\n        try:\n            id = '%s.%s' % (text_type(fontname), text_type(fontsize))\n        except UnicodeDecodeError:\n            id = '%s.%s' % (fontname, fontsize)\n\n        if not id in self._cache:\n            font = ImageFont.truetype(fontname, fontsize)\n            self._cache[id] = font\n\n        return self._cache[id]\n\n    def get_extents(self, text):\n        font = self._select_font()\n        w, h = font.getsize(text)\n        return w, h\n\n    def get_cached_extents(self):\n        return self._select_font().getsize\n\n    def _render_begin(self):\n        # create a surface, context, font...\n        self._pil_im = Image.new('RGBA', self._size)\n        self._pil_draw = ImageDraw.Draw(self._pil_im)\n\n    def _render_text(self, text, x, y):\n        color = tuple([int(c * 255) for c in self.options['color']])\n        self._pil_draw.text((int(x), int(y)),\n                            text, font=self._select_font(), fill=color)\n\n    def _render_end(self):\n        data = ImageData(self._size[0], self._size[1],\n                         self._pil_im.mode.lower(), self._pil_im.tostring())\n\n        del self._pil_im\n        del self._pil_draw\n\n        return data\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/text/text_pygame.py",
    "content": "'''\nText Pygame: Draw text with pygame\n'''\n\n__all__ = ('LabelPygame', )\n\nfrom kivy.compat import PY2\nfrom kivy.core.text import LabelBase\nfrom kivy.core.image import ImageData\n\ntry:\n    import pygame\nexcept:\n    raise\n\npygame_cache = {}\npygame_font_handles = {}\npygame_cache_order = []\n\n# init pygame font\ntry:\n    pygame.ftfont.init()\nexcept:\n    pygame.font.init()\n\n\nclass LabelPygame(LabelBase):\n\n    def _get_font_id(self):\n        if PY2:\n            try:\n                return '|'.join([unicode(self.options[x]) for x in\n                                 ('font_size', 'font_name_r',\n                                  'bold', 'italic')])\n            except UnicodeDecodeError:\n                pass\n        return '|'.join([str(self.options[x]) for x in\n                         ('font_size', 'font_name_r', 'bold', 'italic')])\n\n    def _get_font(self):\n        fontid = self._get_font_id()\n        if fontid not in pygame_cache:\n            # try first the file if it's a filename\n            font_handle = fontobject = None\n            fontname = self.options['font_name_r']\n            ext = fontname.rsplit('.', 1)\n            if len(ext) == 2:\n                # try to open the font if it has an extension\n                font_handle = open(fontname, 'rb')\n                fontobject = pygame.font.Font(font_handle,\n                                              int(self.options['font_size']))\n\n            # fallback to search a system font\n            if fontobject is None:\n                # try to search the font\n                font = pygame.font.match_font(\n                    self.options['font_name_r'].replace(' ', ''),\n                    bold=self.options['bold'],\n                    italic=self.options['italic'])\n\n                # fontobject\n                fontobject = pygame.font.Font(font,\n                                              int(self.options['font_size']))\n            pygame_cache[fontid] = fontobject\n            pygame_font_handles[fontid] = font_handle\n            pygame_cache_order.append(fontid)\n\n        # to prevent too much file open, limit the number of opened fonts to 64\n        while len(pygame_cache_order) > 64:\n            popid = pygame_cache_order.pop(0)\n            del pygame_cache[popid]\n            font_handle = pygame_font_handles.pop(popid)\n            if font_handle is not None:\n                font_handle.close()\n\n        return pygame_cache[fontid]\n\n    def get_ascent(self):\n        return self._get_font().get_ascent()\n\n    def get_descent(self):\n        return self._get_font().get_descent()\n\n    def get_extents(self, text):\n        return self._get_font().size(text)\n\n    def get_cached_extents(self):\n        return self._get_font().size\n\n    def _render_begin(self):\n        self._pygame_surface = pygame.Surface(self._size, pygame.SRCALPHA, 32)\n        self._pygame_surface.fill((0, 0, 0, 0))\n\n    def _render_text(self, text, x, y):\n        font = self._get_font()\n        color = [c * 255 for c in self.options['color']]\n        color[0], color[2] = color[2], color[0]\n        try:\n            text = font.render(text, True, color)\n            self._pygame_surface.blit(text, (x, y), None,\n                                      pygame.BLEND_RGBA_ADD)\n        except pygame.error:\n            pass\n\n    def _render_end(self):\n        w, h = self._size\n        data = ImageData(w, h,\n                         'rgba', self._pygame_surface.get_buffer().raw)\n\n        del self._pygame_surface\n\n        return data\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/text/text_sdl2.py",
    "content": "'''\nSDL2 text provider\n==================\n\nBased on SDL2 + SDL2_ttf\n'''\n\n__all__ = ('LabelSDL2', )\n\nfrom kivy.compat import PY2\nfrom kivy.core.text import LabelBase\nfrom kivy.core.text._text_sdl2 import (_SurfaceContainer, _get_extents,\n                                       _get_fontdescent, _get_fontascent)\n\n\nclass LabelSDL2(LabelBase):\n\n    def _get_font_id(self):\n        if PY2:\n            try:\n                return '|'.join([unicode(self.options[x]) for x\n                    in ('font_size', 'font_name_r', 'bold', 'italic')])\n            except UnicodeDecodeError:\n                pass\n        return '|'.join([str(self.options[x]) for x\n            in ('font_size', 'font_name_r', 'bold', 'italic')])\n\n    def get_extents(self, text):\n        try:\n            if PY2:\n                text = text.encode('UTF-8')\n        except:\n            pass\n        return _get_extents(self, text)\n\n    def get_descent(self):\n        return _get_fontdescent(self)\n\n    def get_ascent(self):\n        return _get_fontascent(self)\n\n    def _render_begin(self):\n        self._surface = _SurfaceContainer(self._size[0], self._size[1])\n\n    def _render_text(self, text, x, y):\n        self._surface.render(self, text, x, y)\n\n    def _render_end(self):\n        return self._surface.get_data()\n\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/video/__init__.py",
    "content": "'''\nVideo\n=====\n\nCore class for reading video files and managing the\n:class:`kivy.graphics.texture.Texture` video.\n\n.. versionchanged:: 1.8.0\n    There is now 2 distinct Gstreamer implementation: one using Gi/Gst\n    working for both Python 2+3 with Gstreamer 1.0, and one using PyGST\n    working only for Python 2 + Gstreamer 0.10.\n    If you have issue with GStreamer, have a look at\n    :ref:`gstreamer-compatibility`\n\n.. note::\n\n    Recording is not supported.\n'''\n\n__all__ = ('VideoBase', 'Video')\n\nfrom kivy.clock import Clock\nfrom kivy.core import core_select_lib\nfrom kivy.event import EventDispatcher\nfrom kivy.logger import Logger\nfrom kivy.compat import PY2\n\n\nclass VideoBase(EventDispatcher):\n    '''VideoBase, a class used to implement a video reader.\n\n    :Parameters:\n        `filename` : str\n            Filename of the video. Can be a file or an URI.\n        `eos` : str, defaults to 'pause'\n            Action to take when EOS is hit. Can be one of 'pause', 'stop' or\n            'loop'.\n\n            .. versionchanged:: unknown\n                added 'pause'\n\n        `async` : bool, defaults to True\n            Load the video asynchronously (may be not supported by all\n            providers).\n        `autoplay` : bool, defaults to False\n            Auto play the video on init.\n\n    :Events:\n        `on_eos`\n            Fired when EOS is hit.\n        `on_load`\n            Fired when the video is loaded and the texture is available.\n        `on_frame`\n            Fired when a new frame is written to the texture.\n    '''\n\n    __slots__ = ('_wantplay', '_buffer', '_filename', '_texture',\n                 '_volume', 'eos', '_state', '_async', '_autoplay')\n\n    __events__ = ('on_eos', 'on_load', 'on_frame')\n\n    def __init__(self, **kwargs):\n        kwargs.setdefault('filename', None)\n        kwargs.setdefault('eos', 'stop')\n        kwargs.setdefault('async', True)\n        kwargs.setdefault('autoplay', False)\n\n        super(VideoBase, self).__init__()\n\n        self._wantplay = False\n        self._buffer = None\n        self._filename = None\n        self._texture = None\n        self._volume = 1.\n        self._state = ''\n\n        self._autoplay = kwargs.get('autoplay')\n        self._async = kwargs.get('async')\n        self.eos = kwargs.get('eos')\n        if self.eos == 'pause':\n            Logger.warning(\"'pause' is deprecated. Use 'stop' instead.\")\n            self.eos = 'stop'\n        self.filename = kwargs.get('filename')\n\n        Clock.schedule_interval(self._update, 1 / 30.)\n\n        if self._autoplay:\n            self.play()\n\n    def __del__(self):\n        self.unload()\n\n    def on_eos(self):\n        pass\n\n    def on_load(self):\n        pass\n\n    def on_frame(self):\n        pass\n\n    def _get_filename(self):\n        return self._filename\n\n    def _set_filename(self, filename):\n        if filename == self._filename:\n            return\n        self.unload()\n        self._filename = filename\n        if self._filename is None:\n            return\n        self.load()\n\n    filename = property(lambda self: self._get_filename(),\n                        lambda self, x: self._set_filename(x),\n                        doc='Get/set the filename/uri of the current video')\n\n    def _get_position(self):\n        return 0\n\n    def _set_position(self, pos):\n        self.seek(pos)\n\n    position = property(lambda self: self._get_position(),\n                        lambda self, x: self._set_position(x),\n                        doc='Get/set the position in the video (in seconds)')\n\n    def _get_volume(self):\n        return self._volume\n\n    def _set_volume(self, volume):\n        self._volume = volume\n\n    volume = property(lambda self: self._get_volume(),\n                      lambda self, x: self._set_volume(x),\n                      doc='Get/set the volume in the video (1.0 = 100%)')\n\n    def _get_duration(self):\n        return 0\n\n    duration = property(lambda self: self._get_duration(),\n                        doc='Get the video duration (in seconds)')\n\n    def _get_texture(self):\n        return self._texture\n\n    texture = property(lambda self: self._get_texture(),\n                       doc='Get the video texture')\n\n    def _get_state(self):\n        return self._state\n\n    state = property(lambda self: self._get_state(),\n                     doc='Get the video playing status')\n\n    def _do_eos(self, *args):\n        '''\n        .. versionchanged:: 1.4.0\n            Now dispatches the `on_eos` event.\n        '''\n        if self.eos == 'pause':\n            self.pause()\n        elif self.eos == 'stop':\n            self.stop()\n        elif self.eos == 'loop':\n            self.position = 0\n            self.play()\n\n        self.dispatch('on_eos')\n\n    def _update(self, dt):\n        '''Update the video content to texture.\n        '''\n        pass\n\n    def seek(self, percent):\n        '''Move on percent position'''\n        pass\n\n    def stop(self):\n        '''Stop the video playing'''\n        self._state = ''\n\n    def pause(self):\n        '''Pause the video\n\n        .. versionadded:: 1.4.0\n        '''\n        self._state = 'paused'\n\n    def play(self):\n        '''Play the video'''\n        self._state = 'playing'\n\n    def load(self):\n        '''Load the video from the current filename'''\n        pass\n\n    def unload(self):\n        '''Unload the actual video'''\n        self._state = ''\n\n\n# Load the appropriate provider\nvideo_providers = []\ntry:\n    from kivy.lib.gstplayer import GstPlayer  # NOQA\n    video_providers += [('gstplayer', 'video_gstplayer', 'VideoGstplayer')]\nexcept ImportError:\n    #video_providers += [('gi', 'video_gi', 'VideoGi')]\n    if PY2:\n        # if peoples do not have gi, fallback on pygst, only for python2\n        video_providers += [\n            ('pygst', 'video_pygst', 'VideoPyGst')]\nvideo_providers += [\n    ('ffmpeg', 'video_ffmpeg', 'VideoFFMpeg'),\n    ('ffpyplayer', 'video_ffpyplayer', 'VideoFFPy'),\n    ('pyglet', 'video_pyglet', 'VideoPyglet'),\n    ('null', 'video_null', 'VideoNull')]\n\n\nVideo = core_select_lib('video', video_providers)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/video/video_ffmpeg.py",
    "content": "'''\nFFmpeg video abstraction\n========================\n\n.. versionadded:: 1.0.8\n\nThis abstraction requires ffmpeg python extensions. We have made a special\nextension that is used for the android platform but can also be used on x86\nplatforms. The project is available at::\n\n    http://github.com/tito/ffmpeg-android\n\nThe extension is designed for implementing a video player.\nRefer to the documentation of the ffmpeg-android project for more information\nabout the requirements.\n'''\n\ntry:\n    import ffmpeg\nexcept:\n    raise\n\nfrom kivy.core.video import VideoBase\nfrom kivy.graphics.texture import Texture\n\n\nclass VideoFFMpeg(VideoBase):\n\n    def __init__(self, **kwargs):\n        self._do_load = False\n        self._player = None\n        super(VideoFFMpeg, self).__init__(**kwargs)\n\n    def unload(self):\n        if self._player:\n            self._player.stop()\n            self._player = None\n        self._state = ''\n        self._do_load = False\n\n    def load(self):\n        self.unload()\n\n    def play(self):\n        if self._player:\n            self.unload()\n        self._player = ffmpeg.FFVideo(self._filename)\n        self._do_load = True\n\n    def stop(self):\n        self.unload()\n\n    def seek(self, percent):\n        if self._player is None:\n            return\n        self._player.seek(percent)\n\n    def _do_eos(self):\n        self.unload()\n        self.dispatch('on_eos')\n        super(VideoFFMpeg, self)._do_eos()\n\n    def _update(self, dt):\n        if self._do_load:\n            self._player.open()\n            self._do_load = False\n            return\n\n        player = self._player\n        if player is None:\n            return\n        if player.is_open is False:\n            self._do_eos()\n            return\n\n        frame = player.get_next_frame()\n        if frame is None:\n            return\n\n        # first time we got a frame, we know that video is readed now.\n        if self._texture is None:\n            self._texture = Texture.create(size=(\n                player.get_width(), player.get_height()),\n                colorfmt='rgb')\n            self._texture.flip_vertical()\n            self.dispatch('on_load')\n\n        if self._texture:\n            self._texture.blit_buffer(frame)\n            self.dispatch('on_frame')\n\n    def _get_duration(self):\n        if self._player is None:\n            return 0\n        return self._player.get_duration()\n\n    def _get_position(self):\n        if self._player is None:\n            return 0\n        return self._player.get_position()\n\n    def _get_volume(self):\n        if self._player is None:\n            return 0\n        self._volume = self._player.get_volume()\n        return self._volume\n\n    def _set_volume(self, volume):\n        if self._player is None:\n            return\n        self._player.set_volume(volume)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/video/video_ffpyplayer.py",
    "content": "'''\nFFmpeg based video abstraction\n==============================\n\nTo use, you need to install ffpyplyaer and have a compiled ffmpeg shared\nlibrary.\n\n    https://github.com/matham/ffpyplayer\n\nThe docs there describe how to set this up. But briefly, first you need to\ncompile ffmpeg using the shared flags while disabling the static flags (you'll\nprobably have to set the fPIC flag, e.g. CFLAGS=-fPIC). Here's some\ninstructions: https://trac.ffmpeg.org/wiki/CompilationGuide. For Windows, you\ncan download compiled GPL binaries from http://ffmpeg.zeranoe.com/builds/.\nSimilarly, you should download SDL.\n\nNow, you should a ffmpeg and sdl directory. In each, you should have a include,\nbin, and lib directory, where e.g. for Windows, lib contains the .dll.a files,\nwhile bin contains the actual dlls. The include directory holds the headers.\nThe bin directory is only needed if the shared libraries are not already on\nthe path. In the environment define FFMPEG_ROOT and SDL_ROOT, each pointing to\nthe ffmpeg, and SDL directories, respectively. (If you're using SDL2,\nthe include directory will contain a directory called SDL2, which then holds\nthe headers).\n\nOnce defined, download the ffpyplayer git and run\n\n    python setup.py build_ext --inplace\n\nFinally, before running you need to ensure that ffpyplayer is in python's path.\n\n..Note::\n\n    When kivy exits by closing the window while the video is playing,\n    it appears that the __del__method of VideoFFPy\n    is not called. Because of this the VideoFFPy object is not\n    properly deleted when kivy exits. The consequence is that because\n    MediaPlayer creates internal threads which do not have their daemon\n    flag set, when the main threads exists it'll hang and wait for the other\n    MediaPlayer threads to exit. But since __del__ is not called to delete the\n    MediaPlayer object, those threads will remain alive hanging kivy. What this\n    means is that you have to be sure to delete the MediaPlayer object before\n    kivy exits by setting it to None.\n'''\n\n__all__ = ('VideoFFPy', )\n\ntry:\n    import ffpyplayer\n    from ffpyplayer.player import MediaPlayer\n    from ffpyplayer.tools import set_log_callback, loglevels, get_log_callback\nexcept:\n    raise\n\n\nfrom threading import Thread\nfrom kivy.clock import Clock, mainthread\nfrom kivy.logger import Logger\nfrom kivy.core.video import VideoBase\nfrom kivy.graphics import Rectangle, BindTexture\nfrom kivy.graphics.texture import Texture\nfrom kivy.graphics.fbo import Fbo\nfrom kivy.weakmethod import WeakMethod\nimport time\n\nLogger.info('VideoFFPy: Using ffpyplayer {}'.format(ffpyplayer.version))\n\n\nlogger_func = {'quiet': Logger.critical, 'panic': Logger.critical,\n               'fatal': Logger.critical, 'error': Logger.error,\n               'warning': Logger.warning, 'info': Logger.info,\n               'verbose': Logger.debug, 'debug': Logger.debug}\n\n\ndef _log_callback(message, level):\n    message = message.strip()\n    if message:\n        logger_func[level]('ffpyplayer: {}'.format(message))\n\nif not get_log_callback():\n    set_log_callback(_log_callback)\n\n\nclass VideoFFPy(VideoBase):\n\n    YUV_RGB_FS = \"\"\"\n    $HEADER$\n    uniform sampler2D tex_y;\n    uniform sampler2D tex_u;\n    uniform sampler2D tex_v;\n\n    void main(void) {\n        float y = texture2D(tex_y, tex_coord0).r;\n        float u = texture2D(tex_u, tex_coord0).r - 0.5;\n        float v = texture2D(tex_v, tex_coord0).r - 0.5;\n        float r = y +             1.402 * v;\n        float g = y - 0.344 * u - 0.714 * v;\n        float b = y + 1.772 * u;\n        gl_FragColor = vec4(r, g, b, 1.0);\n    }\n    \"\"\"\n\n    def __init__(self, **kwargs):\n        self._ffplayer = None\n        self._thread = None\n        self._next_frame = None\n        self._ffplayer_need_quit = False\n        self._callback_ref = WeakMethod(self._player_callback)\n        self._trigger = Clock.create_trigger(self._redraw)\n\n        super(VideoFFPy, self).__init__(**kwargs)\n\n    def __del__(self):\n        self.unload()\n        if self._log_callback_set:\n            set_log_callback(None)\n\n    def _player_callback(self, selector, value):\n        if self._ffplayer is None:\n            return\n        if selector == 'quit':\n            def close(*args):\n                self.unload()\n            Clock.schedule_once(close, 0)\n\n    def _get_position(self):\n        if self._ffplayer is not None:\n            return self._ffplayer.get_pts()\n        return 0\n\n    def _set_position(self, pos):\n        self.seek(pos)\n\n    def _get_volume(self):\n        if self._ffplayer is not None:\n            self._volume = self._ffplayer.get_volume()\n        return self._volume\n\n    def _set_volume(self, volume):\n        self._volume = volume\n        if self._ffplayer is not None:\n            self._ffplayer.set_volume(volume)\n\n    def _get_duration(self):\n        if self._ffplayer is None:\n            return 0\n        return self._ffplayer.get_metadata()['duration']\n\n    @mainthread\n    def _do_eos(self):\n        if self.eos == 'pause':\n            self.pause()\n        elif self.eos == 'stop':\n            self.stop()\n        elif self.eos == 'loop':\n            self.position = 0\n\n        self.dispatch('on_eos')\n\n    @mainthread\n    def _change_state(self, state):\n        self._state = state\n\n    def _redraw(self, *args):\n        if not self._ffplayer:\n            return\n        next_frame = self._next_frame\n        if not next_frame:\n            return\n\n        img, pts = next_frame\n        if img.get_size() != self._size or self._texture is None:\n            self._size = w, h = img.get_size()\n\n            if self._out_fmt == 'yuv420p':\n                w2 = int(w / 2)\n                h2 = int(h / 2)\n                self._tex_y = Texture.create(\n                    size=(w, h), colorfmt='luminance')\n                self._tex_u = Texture.create(\n                    size=(w2, h2), colorfmt='luminance')\n                self._tex_v = Texture.create(\n                    size=(w2, h2), colorfmt='luminance')\n                self._fbo = fbo = Fbo(size=self._size)\n                with fbo:\n                    BindTexture(texture=self._tex_u, index=1)\n                    BindTexture(texture=self._tex_v, index=2)\n                    Rectangle(size=fbo.size, texture=self._tex_y)\n                fbo.shader.fs = VideoFFPy.YUV_RGB_FS\n                fbo['tex_y'] = 0\n                fbo['tex_u'] = 1\n                fbo['tex_v'] = 2\n                self._texture = fbo.texture\n            else:\n                self._texture = Texture.create(size=self._size, colorfmt='rgba')\n\n            # XXX FIXME\n            #self.texture.add_reload_observer(self.reload_buffer)\n            self._texture.flip_vertical()\n            self.dispatch('on_load')\n\n        if self._texture:\n            if self._out_fmt == 'yuv420p':\n                dy, du, dv, _ = img.to_memoryview()\n                self._tex_y.blit_buffer(dy, colorfmt='luminance')\n                self._tex_u.blit_buffer(du, colorfmt='luminance')\n                self._tex_v.blit_buffer(dv, colorfmt='luminance')\n            else:\n                self._texture.blit_buffer(\n                    img.to_memoryview()[0], colorfmt='rgba')\n\n            self._fbo.ask_update()\n            self._fbo.draw()\n            self.dispatch('on_frame')\n\n    def _next_frame_run(self):\n        ffplayer = self._ffplayer\n        sleep = time.sleep\n        trigger = self._trigger\n        did_dispatch_eof = False\n\n        # fast path, if the source video is yuv420p, we'll use a glsl shader for\n        # buffer conversion to rgba\n        while not self._ffplayer_need_quit:\n            src_pix_fmt = ffplayer.get_metadata().get('src_pix_fmt')\n            if not src_pix_fmt:\n                sleep(0.005)\n                continue\n\n            if src_pix_fmt == 'yuv420p':\n                self._out_fmt = 'yuv420p'\n                ffplayer.set_output_pix_fmt(self._out_fmt)\n            self._ffplayer.toggle_pause()\n            break\n\n        if self._ffplayer_need_quit:\n            return\n\n        # wait until loaded or failed, shouldn't take long, but just to make\n        # sure metadata is available.\n        s = time.clock()\n        while not self._ffplayer_need_quit:\n            if ffplayer.get_metadata()['src_vid_size'] != (0, 0):\n                break\n            # XXX if will fail later then?\n            if time.clock() - s > 10.:\n                break\n            sleep(0.005)\n\n        if self._ffplayer_need_quit:\n            return\n\n        # we got all the informations, now, get the frames :)\n        self._change_state('playing')\n\n        while not self._ffplayer_need_quit:\n            t1 = time.time()\n            frame, val = ffplayer.get_frame()\n            t2 = time.time()\n            if val == 'eof':\n                sleep(0.2)\n                if not did_dispatch_eof:\n                    self._do_eos()\n                    did_dispatch_eof = True\n            elif val == 'paused':\n                did_dispatch_eof = False\n                sleep(0.2)\n            else:\n                did_dispatch_eof = False\n                if frame:\n                    self._next_frame = frame\n                    trigger()\n                else:\n                    val = val if val else (1 / 30.)\n                sleep(val)\n\n    def seek(self, percent):\n        if self._ffplayer is None:\n            return\n        self._ffplayer.seek(percent * self._ffplayer.get_metadata()\n                            ['duration'], relative=False)\n        self._next_frame = None\n\n    def stop(self):\n        self.unload()\n\n    def pause(self):\n        if self._ffplayer and self._state != 'paused':\n            self._ffplayer.toggle_pause()\n            self._state = 'paused'\n\n    def play(self):\n        if self._ffplayer and self._state == 'paused':\n            self._ffplayer.toggle_pause()\n            self._state = 'playing'\n            return\n\n        self.load()\n        self._out_fmt = 'rgba'\n        ff_opts = {\n            'paused': True,\n            'out_fmt': self._out_fmt\n        }\n        self._ffplayer = MediaPlayer(\n                self._filename, callback=self._callback_ref,\n                thread_lib='SDL',\n                loglevel='info', ff_opts=ff_opts)\n\n        self._thread = Thread(target=self._next_frame_run, name='Next frame')\n        self._thread.daemon = True\n        self._thread.start()\n\n    def load(self):\n        self.unload()\n\n    def unload(self):\n        Clock.unschedule(self._redraw)\n        self._ffplayer_need_quit = True\n        if self._thread:\n            self._thread.join()\n            self._thread = None\n        if self._ffplayer:\n            self._ffplayer = None\n        self._next_frame = None\n        self._size = (0, 0)\n        self._state = ''\n        self._ffplayer_need_quit = False\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/video/video_gi.py",
    "content": "'''\nVideo GI\n========\n\nImplementation of VideoBase with using pygi / gstreamer. Pygi is both\ncompatible with Python 2 and 3.\n'''\n\n#\n# Important notes: you must take care of glib event + python. If you connect()\n# directly an event to a python object method, the object will be ref, and will\n# be never unref.\n# To prevent memory leak, you must connect() to a func, and you might want to\n# pass the referenced object with weakref()\n#\n\nfrom gi.repository import Gst\nfrom functools import partial\nfrom os.path import realpath\nfrom threading import Lock\nfrom weakref import ref\nfrom kivy.compat import PY2\nfrom kivy.core.video import VideoBase\nfrom kivy.graphics.texture import Texture\nfrom kivy.logger import Logger\nfrom kivy.support import install_gobject_iteration\nfrom ctypes import Structure, c_void_p, c_int, string_at\nimport atexit\n\nif PY2:\n    from urllib import pathname2url\nelse:\n    from urllib.request import pathname2url\n\n# initialize the video/gi. if the older version is used, don't use video_gi.\nGst.init(None)\nversion = Gst.version()\nif version < (1, 0, 0, 0):\n    raise Exception('Cannot use video_gi, Gstreamer < 1.0 is not supported.')\nLogger.info('VideoGi: Using Gstreamer {}'.format(\n    '.'.join(['{}'.format(x) for x in Gst.version()])))\ninstall_gobject_iteration()\n\n\nclass _MapInfo(Structure):\n    _fields_ = [\n        ('memory', c_void_p),\n        ('flags', c_int),\n        ('data', c_void_p)]\n        # we don't care about the rest\n\n\ndef _gst_new_buffer(obj, appsink):\n    obj = obj()\n    if not obj:\n        return\n    with obj._buffer_lock:\n        obj._buffer = obj._appsink.emit('pull-sample')\n    return False\n\n\ndef _on_gst_message(bus, message):\n    Logger.trace('VideoGi: (bus) {}'.format(message))\n    # log all error messages\n    if message.type == Gst.MessageType.ERROR:\n        error, debug = list(map(str, message.parse_error()))\n        Logger.error('VideoGi: {}'.format(error))\n        Logger.debug('VideoGi: {}'.format(debug))\n\n\ndef _on_gst_eos(obj, *largs):\n    obj = obj()\n    if not obj:\n        return\n    obj._do_eos()\n\n\ndef _on_videogi_unref(obj):\n    if obj in VideoGi._instances:\n        VideoGi._instances.remove(obj)\n\n\nclass VideoGi(VideoBase):\n\n    _instances = []\n\n    def __init__(self, **kwargs):\n        self._buffer_lock = Lock()\n        self._buffer = None\n        self._texture = None\n        self._gst_init()\n        wk = ref(self, _on_videogi_unref)\n        VideoGi._instances.append(wk)\n        super(VideoGi, self).__init__(**kwargs)\n\n    def _gst_init(self):\n        # self._appsink will receive the buffers so we can upload them to GPU\n        self._appsink = Gst.ElementFactory.make('appsink', '')\n        self._appsink.props.caps = Gst.caps_from_string(\n            'video/x-raw,format=RGB')\n\n        self._appsink.props.async = True\n        self._appsink.props.drop = True\n        self._appsink.props.qos = True\n        self._appsink.props.emit_signals = True\n        self._appsink.connect('new-sample', partial(\n            _gst_new_buffer, ref(self)))\n\n        # playbin, takes care of all, loading, playing, etc.\n        self._playbin = Gst.ElementFactory.make('playbin', 'playbin')\n        self._playbin.props.video_sink = self._appsink\n\n        # gstreamer bus, to attach and listen to gst messages\n        self._bus = self._playbin.get_bus()\n        self._bus.add_signal_watch()\n        self._bus.connect('message', _on_gst_message)\n        self._bus.connect('message::eos', partial(\n            _on_gst_eos, ref(self)))\n\n    def _update_texture(self, sample):\n        # texture will be updated with newest buffer/frame\n\n        # read the data from the buffer memory\n        mapinfo = data = None\n        try:\n            buf = sample.get_buffer()\n            result, mapinfo = buf.map(Gst.MapFlags.READ)\n\n            # We cannot get the data out of mapinfo, using Gst 1.0.6 + Gi 3.8.0\n            # related bug report:\n            #     https://bugzilla.gnome.org/show_bug.cgi?id=678663\n            # ie: mapinfo.data is normally a char*, but here, we have an int\n            # So right now, we use ctypes instead to read the mapinfo ourself.\n            addr = mapinfo.__hash__()\n            c_mapinfo = _MapInfo.from_address(addr)\n\n            # now get the memory\n            data = string_at(c_mapinfo.data, mapinfo.size)\n        finally:\n            if mapinfo is not None:\n                buf.unmap(mapinfo)\n\n        # upload the data to the GPU\n        info = sample.get_caps().get_structure(0)\n        size = info.get_value('width'), info.get_value('height')\n\n        # texture is not allocated yet, create it first\n        if not self._texture:\n            self._texture = Texture.create(size=size, colorfmt='rgb')\n            self._texture.flip_vertical()\n            self.dispatch('on_load')\n\n        if self._texture:\n            self._texture.blit_buffer(data, size=size, colorfmt='rgb')\n\n    def _update(self, dt):\n        buf = None\n        with self._buffer_lock:\n            buf = self._buffer\n            self._buffer = None\n        if buf is not None:\n            self._update_texture(buf)\n            self.dispatch('on_frame')\n\n    def unload(self):\n        self._playbin.set_state(Gst.State.NULL)\n        self._buffer = None\n        self._texture = None\n\n    def load(self):\n        Logger.debug('VideoGi: Load <{}>'.format(self._filename))\n        self._playbin.set_state(Gst.State.NULL)\n        self._playbin.props.uri = self._get_uri()\n        self._playbin.set_state(Gst.State.READY)\n\n    def stop(self):\n        self._state = ''\n        self._playbin.set_state(Gst.State.PAUSED)\n\n    def pause(self):\n        self._state = 'paused'\n        self._playbin.set_state(Gst.State.PAUSED)\n\n    def play(self):\n        self._state = 'playing'\n        self._playbin.set_state(Gst.State.PLAYING)\n\n    def seek(self, percent):\n        seek_t = percent * self._get_duration() * 10e8\n        seek_format = Gst.Format.TIME\n        seek_flags = Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT\n        self._playbin.seek_simple(seek_format, seek_flags, seek_t)\n\n        #if pipeline is not playing, we need to pull pre-roll to update frame\n        if not self._state == 'playing':\n            with self._buffer_lock:\n                self._buffer = self._appsink.emit('pull-preroll')\n\n    def _get_uri(self):\n        uri = self.filename\n        if not uri:\n            return\n        if not '://' in uri:\n            uri = 'file:' + pathname2url(realpath(uri))\n        return uri\n\n    def _get_position(self):\n        try:\n            ret, value = self._appsink.query_position(Gst.Format.TIME)\n            if ret:\n                return value / float(Gst.SECOND)\n        except:\n            pass\n        return -1\n\n    def _get_duration(self):\n        try:\n            ret, value = self._playbin.query_duration(Gst.Format.TIME)\n            if ret:\n                return value / float(Gst.SECOND)\n        except:\n            pass\n        return -1\n\n    def _get_volume(self):\n        self._volume = self._playbin.props.volume\n        return self._volume\n\n    def _set_volume(self, volume):\n        self._playbin.props.volume = volume\n        self._volume = volume\n\n\n@atexit.register\ndef video_gi_clean():\n    # if we leave the python process with some video running, we can hit a\n    # segfault. This is forcing the stop/unload of all remaining videos before\n    # exiting the python process.\n    for weakvideo in VideoGi._instances:\n        video = weakvideo()\n        if video:\n            video.stop()\n            video.unload()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/video/video_gstplayer.py",
    "content": "'''\nVideo Gstplayer\n===============\n\n.. versionadded:: 1.8.0\n\nImplementation of a VideoBase with Kivy :class:`~kivy.lib.gstplayer.GstPlayer`\nThis player is the prefered player, using Gstreamer 1.0, working on both Python\n2 and 3.\n'''\n\nfrom kivy.lib.gstplayer import GstPlayer, get_gst_version\nfrom kivy.graphics.texture import Texture\nfrom kivy.core.video import VideoBase\nfrom kivy.logger import Logger\nfrom kivy.clock import Clock\nfrom kivy.compat import PY2\nfrom threading import Lock\nfrom functools import partial\nfrom os.path import realpath\nfrom weakref import ref\n\nif PY2:\n    from urllib import pathname2url\nelse:\n    from urllib.request import pathname2url\n\nLogger.info('VideoGstplayer: Using Gstreamer {}'.format(\n    '.'.join(map(str, get_gst_version()))))\n\n\ndef _on_gstplayer_buffer(video, width, height, data):\n    video = video()\n    # if we still receive the video but no more player, remove it.\n    if not video:\n        return\n    with video._buffer_lock:\n        video._buffer = (width, height, data)\n\n\ndef _on_gstplayer_message(mtype, message):\n    if mtype == 'error':\n        Logger.error('VideoGstplayer: {}'.format(message))\n    elif mtype == 'warning':\n        Logger.warning('VideoGstplayer: {}'.format(message))\n    elif mtype == 'info':\n        Logger.info('VideoGstplayer: {}'.format(message))\n\n\nclass VideoGstplayer(VideoBase):\n\n    def __init__(self, **kwargs):\n        self.player = None\n        self._buffer = None\n        self._buffer_lock = Lock()\n        super(VideoGstplayer, self).__init__(**kwargs)\n\n    def _on_gst_eos_sync(self):\n        Clock.schedule_once(self._do_eos, 0)\n\n    def load(self):\n        Logger.debug('VideoGstplayer: Load <{}>'.format(self._filename))\n        uri = self._get_uri()\n        wk_self = ref(self)\n        self.player_callback = partial(_on_gstplayer_buffer, wk_self)\n        self.player = GstPlayer(uri, self.player_callback,\n                                self._on_gst_eos_sync, _on_gstplayer_message)\n        self.player.load()\n\n    def unload(self):\n        if self.player:\n            self.player.unload()\n            self.player = None\n        with self._buffer_lock:\n            self._buffer = None\n        self._texture = None\n\n    def stop(self):\n        super(VideoGstplayer, self).stop()\n        self.player.stop()\n\n    def pause(self):\n        super(VideoGstplayer, self).pause()\n        self.player.pause()\n\n    def play(self):\n        super(VideoGstplayer, self).play()\n        self.player.set_volume(self.volume)\n        self.player.play()\n\n    def seek(self, percent):\n        self.player.seek(percent)\n\n    def _get_position(self):\n        return self.player.get_position()\n\n    def _get_duration(self):\n        return self.player.get_duration()\n\n    def _get_volume(self):\n        return self._volume\n\n    def _set_volume(self, value):\n        self._volume = value\n        if self.player:\n            self.player.set_volume(self._volume)\n\n    def _update(self, dt):\n        buf = None\n        with self._buffer_lock:\n            buf = self._buffer\n            self._buffer = None\n        if buf is not None:\n            self._update_texture(buf)\n            self.dispatch('on_frame')\n\n    def _update_texture(self, buf):\n        width, height, data = buf\n\n        # texture is not allocated yet, create it first\n        if not self._texture:\n            self._texture = Texture.create(size=(width, height),\n                                           colorfmt='rgb')\n            self._texture.flip_vertical()\n            self.dispatch('on_load')\n\n        if self._texture:\n            self._texture.blit_buffer(\n                data, size=(width, height), colorfmt='rgb')\n\n    def _get_uri(self):\n        uri = self.filename\n        if not uri:\n            return\n        if not '://' in uri:\n            uri = 'file:' + pathname2url(realpath(uri))\n        return uri\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/video/video_null.py",
    "content": "\n'''\nVideoNull: empty implementation of VideoBase for the no provider case\n'''\n\nfrom kivy.core.video import VideoBase\n\n\nclass VideoNull(VideoBase):\n    '''VideoBase implementation when there is no provider.\n    '''\n    pass\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/video/video_pyglet.py",
    "content": "\n'''\nVideoPyglet: implementation of VideoBase with Pyglet\n'''\n\nimport pyglet\n\nfrom kivy.core.video import VideoBase\n\n\n#have to set these before importing pyglet.gl\n#otherwise pyglet creates a seperate gl context and fails\n# on error checks becasue we use pygame window\npyglet.options['shadow_window'] = False\npyglet.options['debug_gl'] = False\nimport pyglet.gl\n\n\nclass FakePygletContext:\n    # another pyglet fix, because pyglet has a bugfix which is a bad hacked,\n    # it checks for context._workaround_unpack_row_length..but we're using\n    # the implicit context form pyglet or glut window\n    # this means we cant have a pyglet window provider though! if we do,\n    # this will break pyglet window context\n    _workaround_unpack_row_length = False\n\npyglet.gl.current_context = FakePygletContext()\n\n\nclass VideoPyglet(VideoBase):\n    '''VideoBase implementation using Pyglet\n    '''\n\n    def unload(self):\n        self.player = None\n        self._source = None\n        self._fbo = None\n\n    def load(self):\n        self.unload()  # make sure we unload an resources\n\n        #load media file and set size of video\n        self._source = source = pyglet.media.load(self._filename)\n        self._format = source.video_format\n        self.size = (self._format.width, self._format.height)\n\n        #load pyglet player and have it play teh video we loaded\n        self._player = None\n        self._player = pyglet.media.Player()\n        self._player.queue(source)\n        self.play()\n        self.stop()\n\n        # we have to keep track of tie ourselves..\n        # at least its the only way i can get pyglet player to restart,\n        # _player.time does not get reset when you do seek(0) for soe reason,\n        # and is read only\n        self.time = self._player.time\n\n    def _update(self, dt):\n        if self._source.duration - self.time < 0.1:  # we are at the end\n            self.seek(0)\n        if self.state == 'playing':\n            # keep track of time into video\n            self.time += dt\n            # required by pyglet video if not in pyglet window\n            self._player.dispatch_events(dt)\n        if self._player.get_texture():\n            # TODO: blit the pyglet texture to our own texture.\n            assert('TODO')\n\n    def stop(self):\n        self._player.pause()\n        super(VideoPyglet, self).stop()\n\n    def play(self):\n        self._player.play()\n        super(VideoPyglet, self).play()\n\n    def seek(self, percent):\n        t = self._source.duration * percent\n        self.time = t\n        self._player.seek(t)\n        self.stop()\n\n    def _get_position(self):\n        if self._player:\n            return self.time\n\n    def _get_duration(self):\n        if self._source:\n            return self._source.duration\n\n    def _get_volume(self):\n        if self._player:\n            return self._player.volume\n        return 0\n\n    def _set_volume(self, volume):\n        if self._player:\n            self._player.volume = volume\n            self.dispatch('on_frame')\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/video/video_pygst.py",
    "content": "'''\nVideo PyGst\n===========\n\nImplementation of a VideoBase using PyGST. This module is compatible only with\nPython 2.\n'''\n\n#\n# Important notes: you must take care of glib event + python. If you connect()\n# directly an event to a python object method, the object will be ref, and will\n# be never unref.\n# To prevent memory leak, you must connect() to a func, and you might want to\n# pass the referenced object with weakref()\n#\n\nimport pygst\n\nif not hasattr(pygst, '_gst_already_checked'):\n    found = False\n    for version in ('1.0', '0.10'):\n        try:\n            pygst.require(version)\n            found = True\n            break\n\n        except:\n            continue\n\n    if found:\n        pygst._gst_already_checked = True\n    else:\n        raise Exception('Unable to find a valid Gstreamer version to use')\n\nimport gst\nfrom functools import partial\nfrom os import path\nfrom threading import Lock\nfrom urllib import pathname2url\nfrom weakref import ref\nfrom kivy.core.video import VideoBase\nfrom kivy.graphics.texture import Texture\nfrom kivy.logger import Logger\nfrom kivy.support import install_gobject_iteration\n\n\ninstall_gobject_iteration()\n\n\ndef _gst_new_buffer(obj, appsink):\n    obj = obj()\n    if not obj:\n        return\n    with obj._buffer_lock:\n        obj._buffer = obj._appsink.emit('pull-buffer')\n\n\ndef _on_gst_message(bus, message):\n    Logger.trace('VideoPyGst: (bus) %s' % str(message))\n    # log all error messages\n    if message.type == gst.MESSAGE_ERROR:\n        error, debug = list(map(str, message.parse_error()))\n        Logger.error('VideoPyGst: %s' % error)\n        Logger.debug('VideoPyGst: %s' % debug)\n\n\ndef _on_gst_eos(obj, *largs):\n    obj = obj()\n    if not obj:\n        return\n    obj._do_eos()\n\n\nclass VideoPyGst(VideoBase):\n\n    def __init__(self, **kwargs):\n        self._buffer_lock = Lock()\n        self._buffer = None\n        self._texture = None\n        self._gst_init()\n        super(VideoPyGst, self).__init__(**kwargs)\n\n    def _gst_init(self):\n        # self._appsink will receive the buffers so we can upload them to GPU\n        self._appsink = gst.element_factory_make('appsink', '')\n        self._appsink.set_property('caps', gst.Caps(\n            'video/x-raw-rgb,red_mask=(int)0xff0000,'\n            'green_mask=(int)0x00ff00,blue_mask=(int)0x0000ff'))\n\n        self._appsink.set_property('async', True)\n        self._appsink.set_property('drop', True)\n        self._appsink.set_property('qos', True)\n        self._appsink.set_property('emit-signals', True)\n        self._appsink.connect('new-buffer', partial(\n            _gst_new_buffer, ref(self)))\n\n        # playbin, takes care of all, loading, playing, etc.\n        # XXX playbin2 have some issue when playing some video or streaming :/\n        self._playbin = gst.element_factory_make('playbin', 'playbin')\n        self._playbin.set_property('video-sink', self._appsink)\n\n        # gstreamer bus, to attach and listen to gst messages\n        self._bus = self._playbin.get_bus()\n        self._bus.add_signal_watch()\n        self._bus.connect('message', _on_gst_message)\n        self._bus.connect('message::eos', partial(\n            _on_gst_eos, ref(self)))\n\n    def _update_texture(self, buf):\n        # texture will be updated with newest buffer/frame\n        size = None\n        caps = buf.get_caps()\n        _s = caps.get_structure(0)\n        size = _s['width'], _s['height']\n        if not self._texture:\n            # texture is not allocated yet, so create it first\n            self._texture = Texture.create(size=size, colorfmt='rgb')\n            self._texture.flip_vertical()\n            self.dispatch('on_load')\n\n        # upload texture data to GPU\n        if self._texture:\n            self._texture.blit_buffer(buf.data, size=size, colorfmt='rgb')\n\n    def _update(self, dt):\n        buf = None\n        with self._buffer_lock:\n            buf = self._buffer\n            self._buffer = None\n        if buf is not None:\n            self._update_texture(buf)\n            self.dispatch('on_frame')\n\n    def unload(self):\n        self._playbin.set_state(gst.STATE_NULL)\n        self._buffer = None\n        self._texture = None\n\n    def load(self):\n        Logger.debug('VideoPyGst: Load <%s>' % self._filename)\n        self._playbin.set_state(gst.STATE_NULL)\n        self._playbin.set_property('uri', self._get_uri())\n        self._playbin.set_state(gst.STATE_READY)\n\n    def stop(self):\n        '''.. versionchanged:: 1.4.0'''\n        self._state = ''\n        self._playbin.set_state(gst.STATE_PAUSED)\n\n    def pause(self):\n        '''.. versionadded:: 1.4.0'''\n        self._state = 'paused'\n        self._playbin.set_state(gst.STATE_PAUSED)\n\n    def play(self):\n        self._state = 'playing'\n        self._playbin.set_state(gst.STATE_PLAYING)\n\n    def seek(self, percent):\n        seek_t = percent * self._get_duration() * 10e8\n        seek_format = gst.FORMAT_TIME\n        seek_flags = gst.SEEK_FLAG_FLUSH | gst.SEEK_FLAG_KEY_UNIT\n        self._playbin.seek_simple(seek_format, seek_flags, seek_t)\n\n        #if pipeline is not playing, we need to pull pre-roll to update frame\n        if not self._state == 'playing':\n            with self._buffer_lock:\n                self._buffer = self._appsink.emit('pull-preroll')\n\n    def _get_uri(self):\n        uri = self.filename\n        if not uri:\n            return\n        if not '://' in uri:\n            uri = 'file:' + pathname2url(path.realpath(uri))\n        return uri\n\n    def _get_position(self):\n        try:\n            value, fmt = self._appsink.query_position(gst.FORMAT_TIME)\n            return value / 10e8\n        except:\n            return -1\n\n    def _get_duration(self):\n        try:\n            return self._playbin.query_duration(gst.FORMAT_TIME)[0] / 10e8\n        except:\n            return -1\n\n    def _get_volume(self):\n        self._volume = self._playbin.get_property('volume')\n        return self._volume\n\n    def _set_volume(self, volume):\n        self._playbin.set_property('volume', volume)\n        self._volume = volume\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/window/__init__.py",
    "content": "# pylint: disable=W0611\n# coding: utf-8\n'''\nWindow\n======\n\nCore class for creating the default Kivy window. Kivy supports only one window\nper application: please don't try to create more than one.\n'''\n\n__all__ = ('Keyboard', 'WindowBase', 'Window')\n\nfrom os.path import join, exists\nfrom os import getcwd\n\nfrom kivy.core import core_select_lib\nfrom kivy.clock import Clock\nfrom kivy.config import Config\nfrom kivy.logger import Logger\nfrom kivy.base import EventLoop, stopTouchApp\nfrom kivy.modules import Modules\nfrom kivy.event import EventDispatcher\nfrom kivy.properties import ListProperty, ObjectProperty, AliasProperty, \\\n    NumericProperty, OptionProperty, StringProperty, BooleanProperty\nfrom kivy.utils import platform, reify\nfrom kivy.context import get_current_context\nfrom kivy.uix.behaviors import FocusBehavior\nfrom kivy.setupconfig import USE_SDL2\nfrom kivy.graphics.transformation import Matrix\n\n# late import\nVKeyboard = None\nandroid = None\n\n\nclass Keyboard(EventDispatcher):\n    '''Keyboard interface that is returned by\n    :meth:`WindowBase.request_keyboard`. When you request a keyboard,\n    you'll get an instance of this class. Whatever the keyboard input is\n    (system or virtual keyboard), you'll receive events through this\n    instance.\n\n    :Events:\n        `on_key_down`: keycode, text, modifiers\n            Fired when a new key is pressed down\n        `on_key_up`: keycode\n            Fired when a key is released (up)\n\n    Here is an example of how to request a Keyboard in accordance with the\n    current configuration:\n\n    .. include:: ../../examples/widgets/keyboardlistener.py\n        :literal:\n\n    '''\n\n    # Keycodes mapping, between str <-> int. Theses keycode are\n    # currently taken from pygame.key. But when a new provider will be\n    # used, it must do the translation to these keycodes too.\n    keycodes = {\n        # specials keys\n        'backspace': 8, 'tab': 9, 'enter': 13, 'rshift': 303, 'shift': 304,\n        'alt': 308, 'rctrl': 306, 'lctrl': 305,\n        'super': 309, 'alt-gr': 307, 'compose': 311, 'pipe': 310,\n        'capslock': 301, 'escape': 27, 'spacebar': 32, 'pageup': 280,\n        'pagedown': 281, 'end': 279, 'home': 278, 'left': 276, 'up':\n        273, 'right': 275, 'down': 274, 'insert': 277, 'delete': 127,\n        'numlock': 300, 'print': 144, 'screenlock': 145, 'pause': 19,\n\n        # a-z keys\n        'a': 97, 'b': 98, 'c': 99, 'd': 100, 'e': 101, 'f': 102, 'g': 103,\n        'h': 104, 'i': 105, 'j': 106, 'k': 107, 'l': 108, 'm': 109, 'n': 110,\n        'o': 111, 'p': 112, 'q': 113, 'r': 114, 's': 115, 't': 116, 'u': 117,\n        'v': 118, 'w': 119, 'x': 120, 'y': 121, 'z': 122,\n\n        # 0-9 keys\n        '0': 48, '1': 49, '2': 50, '3': 51, '4': 52,\n        '5': 53, '6': 54, '7': 55, '8': 56, '9': 57,\n\n        # numpad\n        'numpad0': 256, 'numpad1': 257, 'numpad2': 258, 'numpad3': 259,\n        'numpad4': 260, 'numpad5': 261, 'numpad6': 262, 'numpad7': 263,\n        'numpad8': 264, 'numpad9': 265, 'numpaddecimal': 266,\n        'numpaddivide': 267, 'numpadmul': 268, 'numpadsubstract': 269,\n        'numpadadd': 270, 'numpadenter': 271,\n\n        # F1-15\n        'f1': 282, 'f2': 283, 'f3': 284, 'f4': 285, 'f5': 286, 'f6': 287,\n        'f7': 288, 'f8': 289, 'f9': 290, 'f10': 291, 'f11': 292, 'f12': 293,\n        'f13': 294, 'f14': 295, 'f15': 296,\n\n        # other keys\n        '(': 40, ')': 41,\n        '[': 91, ']': 93,\n        '{': 123, '}': 125,\n        ':': 59, ';': 59,\n        '=': 61, '+': 43,\n        '-': 45, '_': 95,\n        '/': 47, '*': 42,\n        '?': 47,\n        '`': 96, '~': 126,\n        '´': 180, '¦': 166,\n        '\\\\': 92, '|': 124,\n        '\"': 34, \"'\": 39,\n        ',': 44, '.': 46,\n        '<': 60, '>': 62,\n        '@': 64, '!': 33,\n        '#': 35, '$': 36,\n        '%': 37, '^': 94,\n        '&': 38, '¬': 172,\n        '¨': 168, '…': 8230,\n        'ù': 249, 'à': 224,\n        'é': 233, 'è': 232,\n    }\n\n    __events__ = ('on_key_down', 'on_key_up', 'on_textinput')\n\n    def __init__(self, **kwargs):\n        super(Keyboard, self).__init__()\n\n        #: Window which the keyboard is attached too\n        self.window = kwargs.get('window', None)\n\n        #: Callback that will be called when the keyboard is released\n        self.callback = kwargs.get('callback', None)\n\n        #: Target that have requested the keyboard\n        self.target = kwargs.get('target', None)\n\n        #: VKeyboard widget, if allowed by the configuration\n        self.widget = kwargs.get('widget', None)\n\n    def on_key_down(self, keycode, text, modifiers):\n        pass\n\n    def on_key_up(self, keycode):\n        pass\n\n    def on_textinput(self, text):\n        pass\n\n    def release(self):\n        '''Call this method to release the current keyboard.\n        This will ensure that the keyboard is no longer attached to your\n        callback.'''\n        if self.window:\n            self.window.release_keyboard(self.target)\n\n    def _on_window_textinput(self, instance, text):\n        return self.dispatch('on_textinput', text)\n\n    def _on_window_key_down(self, instance, keycode, scancode, text,\n                            modifiers):\n        keycode = (keycode, self.keycode_to_string(keycode))\n        if text == '\\x04':\n            Window.trigger_keyboard_height()\n            return\n        return self.dispatch('on_key_down', keycode, text, modifiers)\n\n    def _on_window_key_up(self, instance, keycode, *largs):\n        keycode = (keycode, self.keycode_to_string(keycode))\n        return self.dispatch('on_key_up', keycode)\n\n    def _on_vkeyboard_key_down(self, instance, keycode, text, modifiers):\n        if keycode is None:\n            keycode = text.lower()\n        keycode = (self.string_to_keycode(keycode), keycode)\n        return self.dispatch('on_key_down', keycode, text, modifiers)\n\n    def _on_vkeyboard_key_up(self, instance, keycode, text, modifiers):\n        if keycode is None:\n            keycode = text\n        keycode = (self.string_to_keycode(keycode), keycode)\n        return self.dispatch('on_key_up', keycode)\n\n    def _on_vkeyboard_textinput(self, instance, text):\n        return self.dispatch('on_textinput', text)\n\n    def string_to_keycode(self, value):\n        '''Convert a string to a keycode number according to the\n        :attr:`Keyboard.keycodes`. If the value is not found in the\n        keycodes, it will return -1.\n        '''\n        return Keyboard.keycodes.get(value, -1)\n\n    def keycode_to_string(self, value):\n        '''Convert a keycode number to a string according to the\n        :attr:`Keyboard.keycodes`. If the value is not found in the\n        keycodes, it will return ''.\n        '''\n        keycodes = list(Keyboard.keycodes.values())\n        if value in keycodes:\n            return list(Keyboard.keycodes.keys())[keycodes.index(value)]\n        return ''\n\n\nclass WindowBase(EventDispatcher):\n    '''WindowBase is an abstract window widget for any window implementation.\n\n    :Parameters:\n        `borderless`: str, one of ('0', '1')\n            Set the window border state. Check the\n            :mod:`~kivy.config` documentation for a\n            more detailed explanation on the values.\n        `fullscreen`: str, one of ('0', '1', 'auto', 'fake')\n            Make the window fullscreen. Check the\n            :mod:`~kivy.config` documentation for a\n            more detailed explanation on the values.\n        `width`: int\n            Width of the window.\n        `height`: int\n            Height of the window.\n\n    :Events:\n        `on_motion`: etype, motionevent\n            Fired when a new :class:`~kivy.input.motionevent.MotionEvent` is\n            dispatched\n        `on_touch_down`:\n            Fired when a new touch event is initiated.\n        `on_touch_move`:\n            Fired when an existing touch event changes location.\n        `on_touch_up`:\n            Fired when an existing touch event is terminated.\n        `on_draw`:\n            Fired when the :class:`Window` is being drawn.\n        `on_flip`:\n            Fired when the :class:`Window` GL surface is being flipped.\n        `on_rotate`: rotation\n            Fired when the :class:`Window` is being rotated.\n        `on_close`:\n            Fired when the :class:`Window` is closed.\n        `on_request_close`:\n            Fired when the event loop wants to close the window, or if the\n            escape key is pressed and `exit_on_escape` is `True`. If a function\n            bound to this event returns `True`, the window will not be closed.\n            If the the event is triggered because of the keyboard escape key,\n            the keyword argument `source` is dispatched along with a value of\n            `keyboard` to the bound functions.\n\n            .. versionadded:: 1.9.0\n\n        `on_keyboard`: key, scancode, codepoint, modifier\n            Fired when the keyboard is used for input.\n\n            .. versionchanged:: 1.3.0\n                The *unicode* parameter has been deprecated in favor of\n                codepoint, and will be removed completely in future versions.\n\n        `on_key_down`: key, scancode, codepoint\n            Fired when a key pressed.\n\n            .. versionchanged:: 1.3.0\n                The *unicode* parameter has been deprecated in favor of\n                codepoint, and will be removed completely in future versions.\n\n        `on_key_up`: key, scancode, codepoint\n            Fired when a key is released.\n\n            .. versionchanged:: 1.3.0\n                The *unicode* parameter has be deprecated in favor of\n                codepoint, and will be removed completely in future versions.\n\n        `on_dropfile`: str\n            Fired when a file is dropped on the application.\n\n    '''\n\n    __instance = None\n    __initialized = False\n    _fake_fullscreen = False\n    _density = 1\n\n    # private properties\n    _size = ListProperty([0, 0])\n    _modifiers = ListProperty([])\n    _rotation = NumericProperty(0)\n    _clearcolor = ObjectProperty([0, 0, 0, 1])\n\n    children = ListProperty([])\n    '''List of the children of this window.\n\n    :attr:`children` is a :class:`~kivy.properties.ListProperty` instance and\n    defaults to an empty list.\n\n    Use :meth:`add_widget` and :meth:`remove_widget` to manipulate the list of\n    children. Don't manipulate the list directly unless you know what you are\n    doing.\n    '''\n\n    parent = ObjectProperty(None, allownone=True)\n    '''Parent of this window.\n\n    :attr:`parent` is a :class:`~kivy.properties.ObjectProperty` instance and\n    defaults to None. When created, the parent is set to the window itself.\n    You must take care of it if you are doing a recursive check.\n    '''\n\n    icon = StringProperty()\n\n    def _get_modifiers(self):\n        return self._modifiers\n\n    modifiers = AliasProperty(_get_modifiers, None)\n    '''List of keyboard modifiers currently active.\n    '''\n\n    def _get_size(self):\n        r = self._rotation\n        w, h = self._size\n        if self._density != 1:\n            w, h = self._win._get_gl_size()\n        if self.softinput_mode == 'resize':\n            h -= self.keyboard_height\n        if r in (0, 180):\n            return w, h\n        return h, w\n\n    def _set_size(self, size):\n        if self._size != size:\n            r = self._rotation\n            if r in (0, 180):\n                self._size = size\n            else:\n                self._size = size[1], size[0]\n\n            self.dispatch('on_resize', *size)\n            return True\n        else:\n            return False\n\n    size = AliasProperty(_get_size, _set_size, bind=('_size', ))\n    '''Get the rotated size of the window. If :attr:`rotation` is set, then the\n    size will change to reflect the rotation.\n    '''\n\n    def _get_clearcolor(self):\n        return self._clearcolor\n\n    def _set_clearcolor(self, value):\n        if value is not None:\n            if type(value) not in (list, tuple):\n                raise Exception('Clearcolor must be a list or tuple')\n            if len(value) != 4:\n                raise Exception('Clearcolor must contain 4 values')\n        self._clearcolor = value\n\n    clearcolor = AliasProperty(_get_clearcolor, _set_clearcolor,\n                               bind=('_clearcolor', ))\n    '''Color used to clear the window.\n\n    ::\n\n        from kivy.core.window import Window\n\n        # red background color\n        Window.clearcolor = (1, 0, 0, 1)\n\n        # don't clear background at all\n        Window.clearcolor = None\n\n    .. versionchanged:: 1.7.2\n        The clearcolor default value is now: (0, 0, 0, 1).\n\n    '''\n\n    # make some property read-only\n    def _get_width(self):\n        _size = self._size\n        if self._density != 1:\n            _size = self._win._get_gl_size()\n        r = self._rotation\n        if r == 0 or r == 180:\n            return _size[0]\n        return _size[1]\n\n    width = AliasProperty(_get_width, None, bind=('_rotation', '_size'))\n    '''Rotated window width.\n\n    :attr:`width` is a read-only :class:`~kivy.properties.AliasProperty`.\n    '''\n\n    def _get_height(self):\n        '''Rotated window height'''\n        r = self._rotation\n        _size = self._size\n        if self._density != 1:\n            _size = self._win._get_gl_size()\n        kb = self.keyboard_height if self.softinput_mode == 'resize' else 0\n        if r == 0 or r == 180:\n            return _size[1] - kb\n        return _size[0] - kb\n\n    height = AliasProperty(_get_height, None, bind=('_rotation', '_size'))\n    '''Rotated window height.\n\n    :attr:`height` is a read-only :class:`~kivy.properties.AliasProperty`.\n    '''\n\n    def _get_center(self):\n        return self.width / 2., self.height / 2.\n\n    center = AliasProperty(_get_center, None, bind=('width', 'height'))\n    '''Center of the rotated window.\n\n    :attr:`center` is a :class:`~kivy.properties.AliasProperty`.\n    '''\n\n    def _get_rotation(self):\n        return self._rotation\n\n    def _set_rotation(self, x):\n        x = int(x % 360)\n        if x == self._rotation:\n            return\n        if x not in (0, 90, 180, 270):\n            raise ValueError('can rotate only 0, 90, 180, 270 degrees')\n        self._rotation = x\n        if self.initialized is False:\n            return\n        self.dispatch('on_resize', *self.size)\n        self.dispatch('on_rotate', x)\n\n    rotation = AliasProperty(_get_rotation, _set_rotation,\n                             bind=('_rotation', ))\n    '''Get/set the window content rotation. Can be one of 0, 90, 180, 270\n    degrees.\n    '''\n\n    softinput_mode = OptionProperty('', options=('', 'pan', 'scale', 'resize'))\n    '''This specifies the behavior of window contents on display of soft\n    keyboard on mobile platform. Can be one of '', 'pan', 'scale', 'resize'.\n\n    When '' The main window is left as it is allowing the user to use\n    :attr:`keyboard_height` to manage the window contents the way they want.\n\n    when 'pan' The main window pans moving the bottom part of the window to be\n    always on top of the keyboard.\n\n    when 'resize' The window is resized and the contents scaled to fit the\n    remaining space.\n\n    ..versionadded::1.9.0\n\n    :attr:`softinput_mode` is a :class:`OptionProperty` defaults to None.\n\n    '''\n\n    _keyboard_changed = BooleanProperty(False)\n\n    def _upd_kbd_height(self, *kargs):\n        self._keyboard_changed = not self._keyboard_changed\n\n    def _get_ios_kheight(self):\n        return 0\n\n    def _get_android_kheight(self):\n        global android\n        if not android:\n            import android\n        return android.get_keyboard_height()\n\n    def _get_kheight(self):\n        if platform == 'android':\n            return self._get_android_kheight()\n        if platform == 'ios':\n            return self._get_ios_kheight()\n        return 0\n\n    keyboard_height = AliasProperty(_get_kheight, None,\n                                    bind=('_keyboard_changed',))\n    '''Rerturns the height of the softkeyboard/IME on mobile platforms.\n    Will return 0 if not on mobile platform or if IME is not active.\n\n    ..versionadded:: 1.9.0\n\n    :attr:`keyboard_height` is a read-only :class:`AliasProperty` defaults to 0.\n    '''\n\n    def _set_system_size(self, size):\n        self._size = size\n\n    def _get_system_size(self):\n        if self.softinput_mode == 'resize':\n            return self._size[0], self._size[1] - self.keyboard_height\n        return self._size\n\n    system_size = AliasProperty(\n        _get_system_size,\n        _set_system_size,\n        bind=('_size', ))\n    '''Real size of the window ignoring rotation.\n    '''\n\n    borderless = BooleanProperty(False)\n    '''When set to True, this property removes the window border/decoration.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`borderless` is a :class:`BooleanProperty`, defaults to False.\n    '''\n\n    fullscreen = OptionProperty(False, options=(True, False, 'auto', 'fake'))\n    '''This property sets the fullscreen mode of the window. Available options\n    are: True, False, 'auto', 'fake'. Check the :mod:`~kivy.config`\n    documentation for a more detailed explanation on the values.\n\n    .. versionadded:: 1.2.0\n\n    .. note::\n        The 'fake' option has been deprecated, use the :attr:`borderless`\n        property instead.\n    '''\n\n    mouse_pos = ObjectProperty([0, 0])\n    '''2d position of the mouse within the window.\n\n    .. versionadded:: 1.2.0\n    '''\n\n    @property\n    def __self__(self):\n        return self\n\n    top = NumericProperty(None, allownone=True)\n    left = NumericProperty(None, allownone=True)\n    position = OptionProperty('auto', options=['auto', 'custom'])\n    render_context = ObjectProperty(None)\n    canvas = ObjectProperty(None)\n    title = StringProperty('Kivy')\n\n    __events__ = (\n        'on_draw', 'on_flip', 'on_rotate', 'on_resize', 'on_close',\n        'on_motion', 'on_touch_down', 'on_touch_move', 'on_touch_up',\n        'on_mouse_down', 'on_mouse_move', 'on_mouse_up', 'on_keyboard',\n        'on_key_down', 'on_key_up', 'on_textinput', 'on_dropfile',\n        'on_request_close', 'on_joy_axis', 'on_joy_hat', 'on_joy_ball',\n        'on_joy_button_down', \"on_joy_button_up\")\n\n    def __new__(cls, **kwargs):\n        if cls.__instance is None:\n            cls.__instance = EventDispatcher.__new__(cls)\n        return cls.__instance\n\n    def __init__(self, **kwargs):\n\n        force = kwargs.pop('force', False)\n\n        # don't init window 2 times,\n        # except if force is specified\n        if WindowBase.__instance is not None and not force:\n            return\n\n        self.initialized = False\n        self._is_desktop = Config.getboolean('kivy', 'desktop')\n\n        # create a trigger for update/create the window when one of window\n        # property changes\n        self.trigger_create_window = Clock.create_trigger(\n            self.create_window, -1)\n\n        # Create a trigger for updating the keyboard height\n        self.trigger_keyboard_height = Clock.create_trigger(\n            self._upd_kbd_height, .5)\n\n        # set the default window parameter according to the configuration\n        if 'borderless' not in kwargs:\n            kwargs['borderless'] = Config.getboolean('graphics', 'borderless')\n        if 'fullscreen' not in kwargs:\n            fullscreen = Config.get('graphics', 'fullscreen')\n            if fullscreen not in ('auto', 'fake'):\n                fullscreen = fullscreen.lower() in ('true', '1', 'yes', 'yup')\n            kwargs['fullscreen'] = fullscreen\n        if 'width' not in kwargs:\n            kwargs['width'] = Config.getint('graphics', 'width')\n        if 'height' not in kwargs:\n            kwargs['height'] = Config.getint('graphics', 'height')\n        if 'rotation' not in kwargs:\n            kwargs['rotation'] = Config.getint('graphics', 'rotation')\n        if 'position' not in kwargs:\n            kwargs['position'] = Config.getdefault('graphics', 'position',\n                                                   'auto')\n        if 'top' in kwargs:\n            kwargs['position'] = 'custom'\n            kwargs['top'] = kwargs['top']\n        else:\n            kwargs['top'] = Config.getint('graphics', 'top')\n        if 'left' in kwargs:\n            kwargs['position'] = 'custom'\n            kwargs['left'] = kwargs['left']\n        else:\n            kwargs['left'] = Config.getint('graphics', 'left')\n        kwargs['_size'] = (kwargs.pop('width'), kwargs.pop('height'))\n\n        super(WindowBase, self).__init__(**kwargs)\n\n        # bind all the properties that need to recreate the window\n        self._bind_create_window()\n        self.bind(size=self.trigger_keyboard_height,\n                  rotation=self.trigger_keyboard_height)\n\n        self.bind(softinput_mode=lambda *dt: self.update_viewport(),\n                  keyboard_height=lambda *dt: self.update_viewport())\n\n        # init privates\n        self._system_keyboard = Keyboard(window=self)\n        self._keyboards = {'system': self._system_keyboard}\n        self._vkeyboard_cls = None\n\n        self.children = []\n        self.parent = self\n\n        # before creating the window\n        import kivy.core.gl  # NOQA\n\n        # configure the window\n        self.create_window()\n\n        # attach modules + listener event\n        EventLoop.set_window(self)\n        Modules.register_window(self)\n        EventLoop.add_event_listener(self)\n\n        # manage keyboard(s)\n        self.configure_keyboards()\n\n        # assign the default context of the widget creation\n        if not hasattr(self, '_context'):\n            self._context = get_current_context()\n\n        # mark as initialized\n        self.initialized = True\n\n    def _bind_create_window(self):\n        for prop in (\n                'fullscreen', 'borderless', 'position', 'top',\n                'left', '_size', 'system_size'):\n            self.bind(**{prop: self.trigger_create_window})\n\n    def _unbind_create_window(self):\n        for prop in (\n                'fullscreen', 'borderless', 'position', 'top',\n                'left', '_size', 'system_size'):\n            self.unbind(**{prop: self.trigger_create_window})\n\n    def toggle_fullscreen(self):\n        '''Toggle between fullscreen and windowed mode.\n\n        .. deprecated:: 1.9.0\n            Use :attr:`fullscreen` instead.\n        '''\n        pass\n\n    def maximize(self):\n        '''Maximizes the window. This method should be used on desktop\n        platforms only.\n\n        .. versionadded:: 1.9.0\n\n        .. note::\n            This feature works with the SDL2 window provider only.\n\n        .. warning::\n            This code is still experimental, and its API may be subject to\n            change in a future version.\n        '''\n        Logger.warning('Window: maximize() is not implemented in the current '\n                        'window provider.')\n\n    def minimize(self):\n        '''Minimizes the window. This method should be used on desktop\n        platforms only.\n\n        .. versionadded:: 1.9.0\n\n        .. note::\n            This feature works with the SDL2 window provider only.\n\n        .. warning::\n            This code is still experimental, and its API may be subject to\n            change in a future version.\n        '''\n        Logger.warning('Window: minimize() is not implemented in the current '\n                        'window provider.')\n\n    def restore(self):\n        '''Restores the size and position of a maximized or minimized window.\n        This method should be used on desktop platforms only.\n\n        .. versionadded:: 1.9.0\n\n        .. note::\n            This feature works with the SDL2 window provider only.\n\n        .. warning::\n            This code is still experimental, and its API may be subject to\n            change in a future version.\n        '''\n        Logger.warning('Window: restore() is not implemented in the current '\n                        'window provider.')\n\n    def hide(self):\n        '''Hides the window. This method should be used on desktop\n        platforms only.\n\n        .. versionadded:: 1.9.0\n\n        .. note::\n            This feature works with the SDL2 window provider only.\n\n        .. warning::\n            This code is still experimental, and its API may be subject to\n            change in a future version.\n        '''\n        Logger.warning('Window: hide() is not implemented in the current '\n                        'window provider.')\n\n    def show(self):\n        '''Shows the window. This method should be used on desktop\n        platforms only.\n\n        .. versionadded:: 1.9.0\n\n        .. note::\n            This feature works with the SDL2 window provider only.\n\n        .. warning::\n            This code is still experimental, and its API may be subject to\n            change in a future version.\n        '''\n        Logger.warning('Window: show() is not implemented in the current '\n                        'window provider.')\n\n    def close(self):\n        '''Close the window'''\n        pass\n\n    def create_window(self, *largs):\n        '''Will create the main window and configure it.\n\n        .. warning::\n            This method is called automatically at runtime. If you call it, it\n            will recreate a RenderContext and Canvas. This means you'll have a\n            new graphics tree, and the old one will be unusable.\n\n            This method exist to permit the creation of a new OpenGL context\n            AFTER closing the first one. (Like using runTouchApp() and\n            stopTouchApp()).\n\n            This method has only been tested in a unittest environment and\n            is not suitable for Applications.\n\n            Again, don't use this method unless you know exactly what you are\n            doing!\n        '''\n        # just to be sure, if the trigger is set, and if this method is\n        # manually called, unset the trigger\n        Clock.unschedule(self.create_window)\n\n        # ensure the window creation will not be called twice\n        if platform in ('android', 'ios'):\n            self._unbind_create_window()\n\n        if not self.initialized:\n            from kivy.core.gl import init_gl\n            init_gl()\n\n            # create the render context and canvas, only the first time.\n            from kivy.graphics import RenderContext, Canvas\n            self.render_context = RenderContext()\n            self.canvas = Canvas()\n            self.render_context.add(self.canvas)\n\n        else:\n            # if we get initialized more than once, then reload opengl state\n            # after the second time.\n            # XXX check how it's working on embed platform.\n            if platform == 'linux' or Window.__class__.__name__ == 'WindowSDL':\n                # on linux, it's safe for just sending a resize.\n                self.dispatch('on_resize', *self.system_size)\n\n            else:\n                # on other platform, window are recreated, we need to reload.\n                from kivy.graphics.context import get_context\n                get_context().reload()\n                Clock.schedule_once(lambda x: self.canvas.ask_update(), 0)\n                self.dispatch('on_resize', *self.system_size)\n\n        # ensure the gl viewport is correct\n        self.update_viewport()\n\n    def on_flip(self):\n        '''Flip between buffers (event)'''\n        self.flip()\n\n    def flip(self):\n        '''Flip between buffers'''\n        pass\n\n    def _update_childsize(self, instance, value):\n        self.update_childsize([instance])\n\n    def add_widget(self, widget, canvas=None):\n        '''Add a widget to a window'''\n        widget.parent = self\n        self.children.insert(0, widget)\n        canvas = self.canvas.before if canvas == 'before' else \\\n            self.canvas.after if canvas == 'after' else self.canvas\n        canvas.add(widget.canvas)\n        self.update_childsize([widget])\n        widget.bind(\n            pos_hint=self._update_childsize,\n            size_hint=self._update_childsize,\n            size=self._update_childsize,\n            pos=self._update_childsize)\n\n    def remove_widget(self, widget):\n        '''Remove a widget from a window\n        '''\n        if not widget in self.children:\n            return\n        self.children.remove(widget)\n        if widget.canvas in self.canvas.children:\n            self.canvas.remove(widget.canvas)\n        elif widget.canvas in self.canvas.after.children:\n            self.canvas.after.remove(widget.canvas)\n        elif widget.canvas in self.canvas.before.children:\n            self.canvas.before.remove(widget.canvas)\n        widget.parent = None\n        widget.unbind(\n            pos_hint=self._update_childsize,\n            size_hint=self._update_childsize,\n            size=self._update_childsize,\n            pos=self._update_childsize)\n\n    def clear(self):\n        '''Clear the window with the background color'''\n        # XXX FIXME use late binding\n        from kivy.graphics.opengl import glClearColor, glClear, \\\n            GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT\n        cc = self._clearcolor\n        if cc is not None:\n            glClearColor(*cc)\n            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |\n                    GL_STENCIL_BUFFER_BIT)\n\n    def set_title(self, title):\n        '''Set the window title.\n\n        .. versionadded:: 1.0.5\n        '''\n        self.title = title\n\n    def set_icon(self, filename):\n        '''Set the icon of the window.\n\n        .. versionadded:: 1.0.5\n        '''\n        self.icon = filename\n\n    def to_widget(self, x, y, initial=True, relative=False):\n        return (x, y)\n\n    def to_window(self, x, y, initial=True, relative=False):\n        return (x, y)\n\n    def _apply_transform(self, m):\n        return m\n\n    def get_window_matrix(self, x=0, y=0):\n        m = Matrix()\n        m.translate(x, y, 0)\n        return m\n\n    def get_root_window(self):\n        return self\n\n    def get_parent_window(self):\n        return self\n\n    def get_parent_layout(self):\n        return None\n\n    def on_draw(self):\n        self.clear()\n        self.render_context.draw()\n\n    def on_motion(self, etype, me):\n        '''Event called when a Motion Event is received.\n\n        :Parameters:\n            `etype`: str\n                One of 'begin', 'update', 'end'\n            `me`: :class:`~kivy.input.motionevent.MotionEvent`\n                The Motion Event currently dispatched.\n        '''\n        if me.is_touch:\n            w, h = self.system_size\n            if platform == 'ios':\n                w, h = self.size\n            me.scale_for_screen(w, h, rotation=self._rotation,\n                                smode=self.softinput_mode,\n                                kheight=self.keyboard_height)\n            if etype == 'begin':\n                self.dispatch('on_touch_down', me)\n            elif etype == 'update':\n                self.dispatch('on_touch_move', me)\n            elif etype == 'end':\n                self.dispatch('on_touch_up', me)\n                FocusBehavior._handle_post_on_touch_up(me)\n\n    def on_touch_down(self, touch):\n        '''Event called when a touch down event is initiated.\n\n        .. versionchanged:: 1.9.0\n            The touch `pos` is now transformed to window coordinates before\n            this method is called. Before, the touch `pos` coordinate would be\n            `(0, 0)` when this method was called.\n        '''\n        for w in self.children[:]:\n            if w.dispatch('on_touch_down', touch):\n                return True\n\n    def on_touch_move(self, touch):\n        '''Event called when a touch event moves (changes location).\n\n        .. versionchanged:: 1.9.0\n            The touch `pos` is now transformed to window coordinates before\n            this method is called. Before, the touch `pos` coordinate would be\n            `(0, 0)` when this method was called.\n        '''\n        for w in self.children[:]:\n            if w.dispatch('on_touch_move', touch):\n                return True\n\n    def on_touch_up(self, touch):\n        '''Event called when a touch event is released (terminated).\n\n        .. versionchanged:: 1.9.0\n            The touch `pos` is now transformed to window coordinates before\n            this method is called. Before, the touch `pos` coordinate would be\n            `(0, 0)` when this method was called.\n        '''\n        for w in self.children[:]:\n            if w.dispatch('on_touch_up', touch):\n                return True\n\n    def on_resize(self, width, height):\n        '''Event called when the window is resized.'''\n        self.update_viewport()\n\n    def update_viewport(self):\n        from kivy.graphics.opengl import glViewport\n        from kivy.graphics.transformation import Matrix\n        from math import radians\n\n        w, h = self.system_size\n        if self._density != 1:\n            w, h = self.size\n\n        smode = self.softinput_mode\n        kheight = self.keyboard_height\n\n        w2, h2 = w / 2., h / 2.\n        r = radians(self.rotation)\n\n        x, y = 0, 0\n        _h = h\n        if smode:\n            y = kheight\n        if smode == 'scale':\n            _h -= kheight\n\n        # prepare the viewport\n        glViewport(x, y, w, _h)\n\n        # do projection matrix\n        projection_mat = Matrix()\n        projection_mat.view_clip(0.0, w, 0.0, h, -1.0, 1.0, 0)\n        self.render_context['projection_mat'] = projection_mat\n\n        # do modelview matrix\n        modelview_mat = Matrix().translate(w2, h2, 0)\n        modelview_mat = modelview_mat.multiply(Matrix().rotate(r, 0, 0, 1))\n\n        w, h = self.size\n        w2, h2 = w / 2., h / 2.\n        modelview_mat = modelview_mat.multiply(Matrix().translate(-w2, -h2, 0))\n        self.render_context['modelview_mat'] = modelview_mat\n\n        # redraw canvas\n        self.canvas.ask_update()\n\n        # and update childs\n        self.update_childsize()\n\n    def update_childsize(self, childs=None):\n        width, height = self.size\n        if childs is None:\n            childs = self.children\n        for w in childs:\n            shw, shh = w.size_hint\n            if shw and shh:\n                w.size = shw * width, shh * height\n            elif shw:\n                w.width = shw * width\n            elif shh:\n                w.height = shh * height\n            for key, value in w.pos_hint.items():\n                if key == 'x':\n                    w.x = value * width\n                elif key == 'right':\n                    w.right = value * width\n                elif key == 'y':\n                    w.y = value * height\n                elif key == 'top':\n                    w.top = value * height\n                elif key == 'center_x':\n                    w.center_x = value * width\n                elif key == 'center_y':\n                    w.center_y = value * height\n\n    def screenshot(self, name='screenshot{:04d}.png'):\n        '''Save the actual displayed image in a file\n        '''\n        i = 0\n        path = None\n        if name != 'screenshot{:04d}.png':\n            _ext = name.split('.')[-1]\n            name = ''.join((name[:-(len(_ext) + 1)], '{:04d}.', _ext))\n        while True:\n            i += 1\n            path = join(getcwd(), name.format(i))\n            if not exists(path):\n                break\n        return path\n\n    def on_rotate(self, rotation):\n        '''Event called when the screen has been rotated.\n        '''\n        pass\n\n    def on_close(self, *largs):\n        '''Event called when the window is closed'''\n        Modules.unregister_window(self)\n        EventLoop.remove_event_listener(self)\n\n    def on_request_close(self, *largs, **kwargs):\n        '''Event called before we close the window. If a bound function returns\n        `True`, the window will not be closed. If the the event is triggered\n        because of the keyboard escape key, the keyword argument `source` is\n        dispatched along with a value of `keyboard` to the bound functions.\n\n        .. warning::\n            When the bound function returns True the window will not be closed,\n            so use with care because the user would not be able to close the\n            program, even if the red X is clicked.\n        '''\n        pass\n\n    def on_mouse_down(self, x, y, button, modifiers):\n        '''Event called when the mouse is used (pressed/released)'''\n        pass\n\n    def on_mouse_move(self, x, y, modifiers):\n        '''Event called when the mouse is moved with buttons pressed'''\n        pass\n\n    def on_mouse_up(self, x, y, button, modifiers):\n        '''Event called when the mouse is moved with buttons pressed'''\n        pass\n\n    def on_joy_axis(self, stickid, axisid, value):\n        '''Event called when a joystick has a stick or other axis moved\n\n        .. versionadded:: 1.9.0'''\n        pass\n\n    def on_joy_hat(self, stickid, hatid, value):\n        '''Event called when a joystick has a hat/dpad moved\n\n        .. versionadded:: 1.9.0'''\n        pass\n\n    def on_joy_ball(self, stickid, ballid, value):\n        '''Event called when a joystick has a ball moved\n\n        .. versionadded:: 1.9.0'''\n        pass\n\n    def on_joy_button_down(self, stickid, buttonid):\n        '''Event called when a joystick has a button pressed\n\n        .. versionadded:: 1.9.0'''\n        pass\n\n    def on_joy_button_up(self, stickid, buttonid):\n        '''Event called when a joystick has a button released\n\n        .. versionadded:: 1.9.0'''\n        pass\n\n    def on_keyboard(self, key, scancode=None, codepoint=None,\n                    modifier=None, **kwargs):\n        '''Event called when keyboard is used.\n\n        .. warning::\n            Some providers may omit `scancode`, `codepoint` and/or `modifier`!\n        '''\n        if 'unicode' in kwargs:\n            Logger.warning(\"The use of the unicode parameter is deprecated, \"\n                           \"and will be removed in future versions. Use \"\n                           \"codepoint instead, which has identical \"\n                           \"semantics.\")\n\n        # Quit if user presses ESC or the typical OSX shortcuts CMD+q or CMD+w\n        # TODO If just CMD+w is pressed, only the window should be closed.\n        is_osx = platform == 'darwin'\n        if WindowBase.on_keyboard.exit_on_escape:\n            if key == 27 or all([is_osx, key in [113, 119], modifier == 1024]):\n                if not self.dispatch('on_request_close', source='keyboard'):\n                    stopTouchApp()\n                    self.close()\n                    return True\n\n    if Config:\n        on_keyboard.exit_on_escape = Config.getboolean('kivy', 'exit_on_escape')\n\n        def __exit(section, name, value):\n            WindowBase.__dict__['on_keyboard'].exit_on_escape = \\\n                Config.getboolean('kivy', 'exit_on_escape')\n\n        Config.add_callback(__exit, 'kivy', 'exit_on_escape')\n\n    def on_key_down(self, key, scancode=None, codepoint=None,\n                    modifier=None, **kwargs):\n        '''Event called when a key is down (same arguments as on_keyboard)'''\n        if 'unicode' in kwargs:\n            Logger.warning(\"The use of the unicode parameter is deprecated, \"\n                           \"and will be removed in future versions. Use \"\n                           \"codepoint instead, which has identical \"\n                           \"semantics.\")\n\n    def on_key_up(self, key, scancode=None, codepoint=None,\n                  modifier=None, **kwargs):\n        '''Event called when a key is released (same arguments as on_keyboard)\n        '''\n        if 'unicode' in kwargs:\n            Logger.warning(\"The use of the unicode parameter is deprecated, \"\n                           \"and will be removed in future versions. Use \"\n                           \"codepoint instead, which has identical \"\n                           \"semantics.\")\n\n    def on_textinput(self, text):\n        '''Event called whem text: i.e. alpha numeric non control keys or set\n        of keys is entered. As it is not gaurenteed whether we get one\n        character or multiple ones, this event supports handling multiple\n        characters.\n\n        ..versionadded:: 1.9.0\n        '''\n        pass\n\n    def on_dropfile(self, filename):\n        '''Event called when a file is dropped on the application.\n\n        .. warning::\n\n            This event currently works with sdl2 window provider, on pygame\n            window provider and MacOSX with a patched version of pygame.\n            This event is left in place for further evolution\n            (ios, android etc.)\n\n        .. versionadded:: 1.2.0\n        '''\n        pass\n\n    @reify\n    def dpi(self):\n        '''Return the DPI of the screen. If the implementation doesn't support\n        any DPI lookup, it will just return 96.\n\n        .. warning::\n\n            This value is not cross-platform. Use\n            :attr:`kivy.base.EventLoop.dpi` instead.\n        '''\n        return 96.\n\n    def configure_keyboards(self):\n        # Configure how to provide keyboards (virtual or not)\n\n        # register system keyboard to listening keys from window\n        sk = self._system_keyboard\n        self.bind(\n            on_key_down=sk._on_window_key_down,\n            on_key_up=sk._on_window_key_up,\n            on_textinput=sk._on_window_textinput)\n\n        # use the device's real keyboard\n        self.use_syskeyboard = True\n\n        # use the device's real keyboard\n        self.allow_vkeyboard = False\n\n        # one single vkeyboard shared between all widgets\n        self.single_vkeyboard = True\n\n        # the single vkeyboard is always sitting at the same position\n        self.docked_vkeyboard = False\n\n        # now read the configuration\n        mode = Config.get('kivy', 'keyboard_mode')\n        if mode not in ('', 'system', 'dock', 'multi', 'systemanddock',\n                        'systemandmulti'):\n            Logger.critical('Window: unknown keyboard mode %r' % mode)\n\n        # adapt mode according to the configuration\n        if mode == 'system':\n            self.use_syskeyboard = True\n            self.allow_vkeyboard = False\n            self.single_vkeyboard = True\n            self.docked_vkeyboard = False\n        elif mode == 'dock':\n            self.use_syskeyboard = False\n            self.allow_vkeyboard = True\n            self.single_vkeyboard = True\n            self.docked_vkeyboard = True\n        elif mode == 'multi':\n            self.use_syskeyboard = False\n            self.allow_vkeyboard = True\n            self.single_vkeyboard = False\n            self.docked_vkeyboard = False\n        elif mode == 'systemanddock':\n            self.use_syskeyboard = True\n            self.allow_vkeyboard = True\n            self.single_vkeyboard = True\n            self.docked_vkeyboard = True\n        elif mode == 'systemandmulti':\n            self.use_syskeyboard = True\n            self.allow_vkeyboard = True\n            self.single_vkeyboard = False\n            self.docked_vkeyboard = False\n\n        Logger.info(\n            'Window: virtual keyboard %sallowed, %s, %s' % (\n                '' if self.allow_vkeyboard else 'not ',\n                'single mode' if self.single_vkeyboard else 'multiuser mode',\n                'docked' if self.docked_vkeyboard else 'not docked'))\n\n    def set_vkeyboard_class(self, cls):\n        '''.. versionadded:: 1.0.8\n\n        Set the VKeyboard class to use. If set to None, it will use the\n        :class:`kivy.uix.vkeyboard.VKeyboard`.\n        '''\n        self._vkeyboard_cls = cls\n\n    def release_all_keyboards(self):\n        '''.. versionadded:: 1.0.8\n\n        This will ensure that no virtual keyboard / system keyboard is\n        requested. All instances will be closed.\n        '''\n        for key in list(self._keyboards.keys())[:]:\n            keyboard = self._keyboards[key]\n            if keyboard:\n                keyboard.release()\n\n    def request_keyboard(self, callback, target, input_type='text'):\n        '''.. versionadded:: 1.0.4\n\n        Internal widget method to request the keyboard. This method is rarely\n        required by the end-user as it is handled automatically by the\n        :class:`~kivy.uix.textinput.TextInput`. We expose it in case you want\n        to handle the keyboard manually for unique input scenarios.\n\n        A widget can request the keyboard, indicating a callback to call\n        when the keyboard is released (or taken by another widget).\n\n        :Parameters:\n            `callback`: func\n                Callback that will be called when the keyboard is\n                closed. This can be because somebody else requested the\n                keyboard or the user closed it.\n            `target`: Widget\n                Attach the keyboard to the specified `target`. This should be\n                the widget that requested the keyboard. Ensure you have a\n                different target attached to each keyboard if you're working in\n                a multi user mode.\n\n                .. versionadded:: 1.0.8\n\n            `input_type`: string\n                Choose the type of soft keyboard to request. Can be one of\n                'text', 'number', 'url', 'mail', 'datetime', 'tel', 'address'.\n\n                .. note::\n\n                    `input_type` is currently only honored on mobile devices.\n\n                .. versionadded:: 1.8.0\n\n        :Return:\n            An instance of :class:`Keyboard` containing the callback, target,\n            and if the configuration allows it, a\n            :class:`~kivy.uix.vkeyboard.VKeyboard` instance attached as a\n            *.widget* property.\n\n        .. note::\n\n            The behavior of this function is heavily influenced by the current\n            `keyboard_mode`. Please see the Config's\n            :ref:`configuration tokens <configuration-tokens>` section for\n            more information.\n\n        '''\n\n        # release any previous keyboard attached.\n        self.release_keyboard(target)\n\n        # if we can use virtual vkeyboard, activate it.\n        if self.allow_vkeyboard:\n            keyboard = None\n\n            # late import\n            global VKeyboard\n            if VKeyboard is None and self._vkeyboard_cls is None:\n                from kivy.uix.vkeyboard import VKeyboard\n                self._vkeyboard_cls = VKeyboard\n\n            # if the keyboard doesn't exist, create it.\n            key = 'single' if self.single_vkeyboard else target\n            if key not in self._keyboards:\n                vkeyboard = self._vkeyboard_cls()\n                keyboard = Keyboard(widget=vkeyboard, window=self)\n                vkeyboard.bind(\n                    on_key_down=keyboard._on_vkeyboard_key_down,\n                    on_key_up=keyboard._on_vkeyboard_key_up,\n                    on_textinput=keyboard._on_vkeyboard_textinput)\n                self._keyboards[key] = keyboard\n            else:\n                keyboard = self._keyboards[key]\n\n            # configure vkeyboard\n            keyboard.target = keyboard.widget.target = target\n            keyboard.callback = keyboard.widget.callback = callback\n\n            # add to the window\n            self.add_widget(keyboard.widget)\n\n            # only after add, do dock mode\n            keyboard.widget.docked = self.docked_vkeyboard\n            keyboard.widget.setup_mode()\n\n        else:\n            # system keyboard, just register the callback.\n            keyboard = self._system_keyboard\n            keyboard.callback = callback\n            keyboard.target = target\n\n        # use system (hardware) keyboard according to flag\n        if self.allow_vkeyboard and self.use_syskeyboard:\n            self.unbind(\n                on_key_down=keyboard._on_window_key_down,\n                on_key_up=keyboard._on_window_key_up,\n                on_textinput=keyboard._on_window_textinput)\n            self.bind(\n                on_key_down=keyboard._on_window_key_down,\n                on_key_up=keyboard._on_window_key_up,\n                on_textinput=keyboard._on_window_textinput)\n\n        return keyboard\n\n    def release_keyboard(self, target=None):\n        '''.. versionadded:: 1.0.4\n\n        Internal method for the widget to release the real-keyboard. Check\n        :meth:`request_keyboard` to understand how it works.\n        '''\n        if self.allow_vkeyboard:\n            key = 'single' if self.single_vkeyboard else target\n            if key not in self._keyboards:\n                return\n            keyboard = self._keyboards[key]\n            callback = keyboard.callback\n            if callback:\n                keyboard.callback = None\n                callback()\n            keyboard.target = None\n            self.remove_widget(keyboard.widget)\n            if key != 'single' and key in self._keyboards:\n                del self._keyboards[key]\n        elif self._system_keyboard.callback:\n            # this way will prevent possible recursion.\n            callback = self._system_keyboard.callback\n            self._system_keyboard.callback = None\n            callback()\n            return True\n\n#: Instance of a :class:`WindowBase` implementation\nwindow_impl = []\nif platform == 'linux':\n    window_impl += [('egl_rpi', 'window_egl_rpi', 'WindowEglRpi')]\nif USE_SDL2:\n    window_impl += [('sdl2', 'window_sdl2', 'WindowSDL')]\nelse:\n    window_impl += [\n        ('pygame', 'window_pygame', 'WindowPygame')]\nif platform == 'linux':\n    window_impl += [('x11', 'window_x11', 'WindowX11')]\nWindow = core_select_lib('window', window_impl, True)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/window/window_egl_rpi.py",
    "content": "'''\nEGL Rpi Window: EGL Window provider, specialized for the Pi\n\nInspired by: rpi_vid_core + JF002 rpi kivy  repo\n'''\n\n__all__ = ('WindowEglRpi', )\n\nfrom kivy.logger import Logger\nfrom kivy.core.window import WindowBase\nfrom kivy.base import EventLoop\nfrom kivy.lib.vidcore_lite import bcm, egl\n\n\nclass WindowEglRpi(WindowBase):\n\n    def create_window(self):\n        bcm.host_init()\n\n        w, h = bcm.graphics_get_display_size(0)\n        Logger.debug('Window: Actual display size: {}x{}'.format(\n            w, h))\n        self._size = w, h\n        self._create_window(w, h)\n        self._create_egl_context(self.win, 0)\n        super(WindowEglRpi, self).create_window()\n\n    def _create_window(self, w, h):\n        dst = bcm.Rect(0, 0, w, h)\n        src = bcm.Rect(0, 0, w << 16, h << 16)\n        display = egl.bcm_display_open(0)\n        update = egl.bcm_update_start(0)\n        element = egl.bcm_element_add(update, display, 0, dst, src)\n        self.win = egl.NativeWindow(element, w, h)\n        egl.bcm_update_submit_sync(update)\n\n    def _create_egl_context(self, win, flags):\n        api = egl._constants.EGL_OPENGL_ES_API\n        c = egl._constants\n\n        attribs = [\n            c.EGL_RED_SIZE, 8,\n            c.EGL_GREEN_SIZE, 8,\n            c.EGL_BLUE_SIZE, 8,\n            c.EGL_ALPHA_SIZE, 8,\n            c.EGL_DEPTH_SIZE, 16,\n            c.EGL_STENCIL_SIZE, 8,\n            c.EGL_SURFACE_TYPE, c.EGL_WINDOW_BIT,\n            c.EGL_NONE]\n\n        attribs_context = [c.EGL_CONTEXT_CLIENT_VERSION, 2, c.EGL_NONE]\n\n        display = egl.GetDisplay(c.EGL_DEFAULT_DISPLAY)\n        egl.Initialise(display)\n        egl.BindAPI(c.EGL_OPENGL_ES_API)\n        egl.GetConfigs(display)\n        config = egl.ChooseConfig(display, attribs, 1)[0]\n        surface = egl.CreateWindowSurface(display, config, win)\n        context = egl.CreateContext(display, config, None, attribs_context)\n        egl.MakeCurrent(display, surface, surface, context)\n\n        self.egl_info = (display, surface, context)\n        egl.MakeCurrent(display, surface, surface, context)\n\n    def close(self):\n        egl.Terminate(self.egl_info[0])\n\n    def flip(self):\n        egl.SwapBuffers(self.egl_info[0], self.egl_info[1])\n\n    def _mainloop(self):\n        EventLoop.idle()\n\n    def mainloop(self):\n        while not EventLoop.quit and EventLoop.status == 'started':\n            try:\n                self._mainloop()\n            except BaseException as inst:\n                raise\n                '''\n                # use exception manager first\n                r = ExceptionManager.handle_exception(inst)\n                if r == ExceptionManager.RAISE:\n                    #stopTouchApp()\n                    raise\n                else:\n                    pass\n                '''\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/window/window_pygame.py",
    "content": "'''\nWindow Pygame: windowing provider based on Pygame\n'''\n\n__all__ = ('WindowPygame', )\n\n# fail early if possible\nimport pygame\n\nfrom kivy.compat import PY2\nfrom kivy.core.window import WindowBase\nfrom kivy.core import CoreCriticalException\nfrom os import environ\nfrom os.path import exists, join\nfrom kivy.config import Config\nfrom kivy import kivy_data_dir\nfrom kivy.base import ExceptionManager\nfrom kivy.logger import Logger\nfrom kivy.base import stopTouchApp, EventLoop\nfrom kivy.utils import platform, deprecated\nfrom kivy.resources import resource_find\nfrom kivy.clock import Clock\n\ntry:\n    android = None\n    if platform == 'android':\n        import android\nexcept ImportError:\n    pass\n\n# late binding\nglReadPixels = GL_RGBA = GL_UNSIGNED_BYTE = None\n\n\nclass WindowPygame(WindowBase):\n\n    def create_window(self, *largs):\n        # ensure the mouse is still not up after window creation, otherwise, we\n        # have some weird bugs\n        self.dispatch('on_mouse_up', 0, 0, 'all', [])\n\n        # force display to show (available only for fullscreen)\n        displayidx = Config.getint('graphics', 'display')\n        if not 'SDL_VIDEO_FULLSCREEN_HEAD' in environ and displayidx != -1:\n            environ['SDL_VIDEO_FULLSCREEN_HEAD'] = '%d' % displayidx\n\n        # init some opengl, same as before.\n        self.flags = pygame.HWSURFACE | pygame.OPENGL | pygame.DOUBLEBUF\n\n        # right now, activate resizable window only on linux.\n        # on window / macosx, the opengl context is lost, and we need to\n        # reconstruct everything. Check #168 for a state of the work.\n        if platform in ('linux', 'macosx', 'win') and \\\n                Config.getboolean('graphics', 'resizable'):\n            self.flags |= pygame.RESIZABLE\n\n        try:\n            pygame.display.init()\n        except pygame.error as e:\n            raise CoreCriticalException(e.message)\n\n        multisamples = Config.getint('graphics', 'multisamples')\n\n        if multisamples > 0:\n            pygame.display.gl_set_attribute(pygame.GL_MULTISAMPLEBUFFERS, 1)\n            pygame.display.gl_set_attribute(pygame.GL_MULTISAMPLESAMPLES,\n                                            multisamples)\n        pygame.display.gl_set_attribute(pygame.GL_DEPTH_SIZE, 16)\n        pygame.display.gl_set_attribute(pygame.GL_STENCIL_SIZE, 1)\n        pygame.display.set_caption(self.title)\n\n        if self.position == 'auto':\n            self._pos = None\n        elif self.position == 'custom':\n            self._pos = self.left, self.top\n        else:\n            raise ValueError('position token in configuration accept only '\n                             '\"auto\" or \"custom\"')\n\n        if self._fake_fullscreen:\n            if not self.borderless:\n                self.fullscreen = self._fake_fullscreen = False\n            elif not self.fullscreen or self.fullscreen == 'auto':\n                self.borderless = self._fake_fullscreen = False\n\n        if self.fullscreen == 'fake':\n            self.borderless = self._fake_fullscreen = True\n            Logger.warning(\"The 'fake' fullscreen option has been \"\n                            \"deprecated, use Window.borderless or the \"\n                            \"borderless Config option instead.\")\n\n        if self.fullscreen == 'fake' or self.borderless:\n            Logger.debug('WinPygame: Set window to borderless mode.')\n\n            self.flags |= pygame.NOFRAME\n            # If no position set in borderless mode, we always need\n            # to set the position. So use 0, 0.\n            if self._pos is None:\n                self._pos = (0, 0)\n            environ['SDL_VIDEO_WINDOW_POS'] = '%d,%d' % self._pos\n\n        elif self.fullscreen in ('auto', True):\n            Logger.debug('WinPygame: Set window to fullscreen mode')\n            self.flags |= pygame.FULLSCREEN\n\n        elif self._pos is not None:\n            environ['SDL_VIDEO_WINDOW_POS'] = '%d,%d' % self._pos\n\n        # never stay with a None pos, application using w.center will be fired.\n        self._pos = (0, 0)\n\n        # prepare keyboard\n        repeat_delay = int(Config.get('kivy', 'keyboard_repeat_delay'))\n        repeat_rate = float(Config.get('kivy', 'keyboard_repeat_rate'))\n        pygame.key.set_repeat(repeat_delay, int(1000. / repeat_rate))\n\n        # set window icon before calling set_mode\n        try:\n            filename_icon = self.icon or Config.get('kivy', 'window_icon')\n            if filename_icon == '':\n                logo_size = 32\n                if platform == 'macosx':\n                    logo_size = 512\n                elif platform == 'win':\n                    logo_size = 64\n                filename_icon = 'kivy-icon-{}.png'.format(logo_size)\n                filename_icon = resource_find(\n                        join(kivy_data_dir, 'logo', filename_icon))\n            self.set_icon(filename_icon)\n        except:\n            Logger.exception('Window: cannot set icon')\n\n        # try to use mode with multisamples\n        try:\n            self._pygame_set_mode()\n        except pygame.error as e:\n            if multisamples:\n                Logger.warning('WinPygame: Video: failed (multisamples=%d)' %\n                               multisamples)\n                Logger.warning('WinPygame: trying without antialiasing')\n                pygame.display.gl_set_attribute(\n                    pygame.GL_MULTISAMPLEBUFFERS, 0)\n                pygame.display.gl_set_attribute(\n                    pygame.GL_MULTISAMPLESAMPLES, 0)\n                multisamples = 0\n                try:\n                    self._pygame_set_mode()\n                except pygame.error as e:\n                    raise CoreCriticalException(e.message)\n            else:\n                raise CoreCriticalException(e.message)\n\n        info = pygame.display.Info()\n        self._size = (info.current_w, info.current_h)\n        #self.dispatch('on_resize', *self._size)\n\n        # in order to debug futur issue with pygame/display, let's show\n        # more debug output.\n        Logger.debug('Window: Display driver ' + pygame.display.get_driver())\n        Logger.debug('Window: Actual window size: %dx%d',\n                     info.current_w, info.current_h)\n        if platform != 'android':\n            # unsupported platform, such as android that doesn't support\n            # gl_get_attribute.\n            Logger.debug(\n                'Window: Actual color bits r%d g%d b%d a%d',\n                pygame.display.gl_get_attribute(pygame.GL_RED_SIZE),\n                pygame.display.gl_get_attribute(pygame.GL_GREEN_SIZE),\n                pygame.display.gl_get_attribute(pygame.GL_BLUE_SIZE),\n                pygame.display.gl_get_attribute(pygame.GL_ALPHA_SIZE))\n            Logger.debug(\n                'Window: Actual depth bits: %d',\n                pygame.display.gl_get_attribute(pygame.GL_DEPTH_SIZE))\n            Logger.debug(\n                'Window: Actual stencil bits: %d',\n                pygame.display.gl_get_attribute(pygame.GL_STENCIL_SIZE))\n            Logger.debug(\n                'Window: Actual multisampling samples: %d',\n                pygame.display.gl_get_attribute(pygame.GL_MULTISAMPLESAMPLES))\n        super(WindowPygame, self).create_window()\n\n        # set mouse visibility\n        pygame.mouse.set_visible(\n            Config.getboolean('graphics', 'show_cursor'))\n\n        # if we are on android platform, automaticly create hooks\n        if android:\n            from kivy.support import install_android\n            install_android()\n\n    def close(self):\n        pygame.display.quit()\n        self.dispatch('on_close')\n\n    def on_title(self, instance, value):\n        if self.initialized:\n            pygame.display.set_caption(self.title)\n\n    def set_icon(self, filename):\n        if not exists(filename):\n            return False\n        try:\n            if platform == 'win':\n                try:\n                    if self._set_icon_win(filename):\n                        return True\n                except:\n                    # fallback on standard loading then.\n                    pass\n\n            # for all others platform, or if the ico is not available, use the\n            # default way to set it.\n            self._set_icon_standard(filename)\n            super(WindowPygame, self).set_icon(filename)\n        except:\n            Logger.exception('WinPygame: unable to set icon')\n\n    def _set_icon_standard(self, filename):\n        if PY2:\n            try:\n                im = pygame.image.load(filename)\n            except UnicodeEncodeError:\n                im = pygame.image.load(filename.encode('utf8'))\n        else:\n            im = pygame.image.load(filename)\n        if im is None:\n            raise Exception('Unable to load window icon (not found)')\n        pygame.display.set_icon(im)\n\n    def _set_icon_win(self, filename):\n        # ensure the window ico is ended by ico\n        if not filename.endswith('.ico'):\n            filename = '{}.ico'.format(filename.rsplit('.', 1)[0])\n        if not exists(filename):\n            return False\n\n        import win32api\n        import win32gui\n        import win32con\n        hwnd = pygame.display.get_wm_info()['window']\n        icon_big = win32gui.LoadImage(\n            None, filename, win32con.IMAGE_ICON,\n            48, 48, win32con.LR_LOADFROMFILE)\n        icon_small = win32gui.LoadImage(\n            None, filename, win32con.IMAGE_ICON,\n            16, 16, win32con.LR_LOADFROMFILE)\n        win32api.SendMessage(\n            hwnd, win32con.WM_SETICON, win32con.ICON_SMALL, icon_small)\n        win32api.SendMessage(\n            hwnd, win32con.WM_SETICON, win32con.ICON_BIG, icon_big)\n        return True\n\n    def screenshot(self, *largs, **kwargs):\n        global glReadPixels, GL_RGBA, GL_UNSIGNED_BYTE\n        filename = super(WindowPygame, self).screenshot(*largs, **kwargs)\n        if filename is None:\n            return None\n        if glReadPixels is None:\n            from kivy.graphics.opengl import (glReadPixels, GL_RGBA,\n                                              GL_UNSIGNED_BYTE)\n        width, height = self.system_size\n        data = glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE)\n        if PY2:\n            data = str(buffer(data))\n        else:\n            data = bytes(bytearray(data))\n        surface = pygame.image.fromstring(data, (width, height), 'RGBA', True)\n        pygame.image.save(surface, filename)\n        Logger.debug('Window: Screenshot saved at <%s>' % filename)\n        return filename\n\n    def flip(self):\n        pygame.display.flip()\n        super(WindowPygame, self).flip()\n\n    @deprecated\n    def toggle_fullscreen(self):\n        if self.flags & pygame.FULLSCREEN:\n            self.flags &= ~pygame.FULLSCREEN\n        else:\n            self.flags |= pygame.FULLSCREEN\n        self._pygame_set_mode()\n\n    def _mainloop(self):\n        EventLoop.idle()\n\n        for event in pygame.event.get():\n\n            # kill application (SIG_TERM)\n            if event.type == pygame.QUIT:\n                if self.dispatch('on_request_close'):\n                    continue\n                EventLoop.quit = True\n                self.close()\n\n            # mouse move\n            elif event.type == pygame.MOUSEMOTION:\n                x, y = event.pos\n                self.mouse_pos = x, self.system_size[1] - y\n                # don't dispatch motion if no button are pressed\n                if event.buttons == (0, 0, 0):\n                    continue\n                self._mouse_x = x\n                self._mouse_y = y\n                self._mouse_meta = self.modifiers\n                self.dispatch('on_mouse_move', x, y, self.modifiers)\n\n            # mouse action\n            elif event.type in (pygame.MOUSEBUTTONDOWN,\n                                pygame.MOUSEBUTTONUP):\n                self._pygame_update_modifiers()\n                x, y = event.pos\n                btn = 'left'\n                if event.button == 3:\n                    btn = 'right'\n                elif event.button == 2:\n                    btn = 'middle'\n                elif event.button == 4:\n                    btn = 'scrolldown'\n                elif event.button == 5:\n                    btn = 'scrollup'\n                elif event.button == 6:\n                    btn = 'scrollright'\n                elif event.button == 7:\n                    btn = 'scrollleft'\n                eventname = 'on_mouse_down'\n                if event.type == pygame.MOUSEBUTTONUP:\n                    eventname = 'on_mouse_up'\n                self._mouse_x = x\n                self._mouse_y = y\n                self._mouse_meta = self.modifiers\n                self._mouse_btn = btn\n                self._mouse_down = eventname == 'on_mouse_down'\n                self.dispatch(eventname, x, y, btn, self.modifiers)\n\n            # joystick action\n            elif event.type == pygame.JOYAXISMOTION:\n                self.dispatch('on_joy_axis', event.joy, event.axis, event.value)\n\n            elif event.type == pygame.JOYHATMOTION:\n                self.dispatch('on_joy_hat', event.joy, event.hat, event.value)\n\n            elif event.type == pygame.JOYBALLMOTION:\n                self.dispatch('on_joy_ball', event.joy, event.ballid,\n                            event.rel[0], event.rel[1])\n\n            elif event.type == pygame.JOYBUTTONDOWN:\n                self.dispatch('on_joy_button_down', event.joy, event.button)\n\n            elif event.type == pygame.JOYBUTTONUP:\n                self.dispatch('on_joy_button_up', event.joy, event.button)\n\n            # keyboard action\n            elif event.type in (pygame.KEYDOWN, pygame.KEYUP):\n                self._pygame_update_modifiers(event.mod)\n                # atm, don't handle keyup\n                if event.type == pygame.KEYUP:\n                    self.dispatch('on_key_up', event.key,\n                                  event.scancode)\n                    continue\n\n                # don't dispatch more key if down event is accepted\n                if self.dispatch('on_key_down', event.key,\n                                 event.scancode, event.unicode,\n                                 self.modifiers):\n                    continue\n                self.dispatch('on_keyboard', event.key,\n                              event.scancode, event.unicode,\n                              self.modifiers)\n\n            # video resize\n            elif event.type == pygame.VIDEORESIZE:\n                self._size = event.size\n                self.update_viewport()\n\n            elif event.type == pygame.VIDEOEXPOSE:\n                self.canvas.ask_update()\n\n            # ignored event\n            elif event.type == pygame.ACTIVEEVENT:\n                pass\n\n            # drop file (pygame patch needed)\n            elif event.type == pygame.USEREVENT and \\\n                    hasattr(pygame, 'USEREVENT_DROPFILE') and \\\n                    event.code == pygame.USEREVENT_DROPFILE:\n                self.dispatch('on_dropfile', event.filename)\n\n            '''\n            # unhandled event !\n            else:\n                Logger.debug('WinPygame: Unhandled event %s' % str(event))\n            '''\n\n    def mainloop(self):\n        while not EventLoop.quit and EventLoop.status == 'started':\n            try:\n                self._mainloop()\n                if not pygame.display.get_active():\n                    pygame.time.wait(100)\n            except BaseException as inst:\n                # use exception manager first\n                r = ExceptionManager.handle_exception(inst)\n                if r == ExceptionManager.RAISE:\n                    stopTouchApp()\n                    raise\n                else:\n                    pass\n\n    #\n    # Pygame wrapper\n    #\n    def _pygame_set_mode(self, size=None):\n        if size is None:\n            size = self.size\n        if self.fullscreen == 'auto':\n            pygame.display.set_mode((0, 0), self.flags)\n        else:\n            pygame.display.set_mode(size, self.flags)\n\n    def _pygame_update_modifiers(self, mods=None):\n        # Available mod, from dir(pygame)\n        # 'KMOD_ALT', 'KMOD_CAPS', 'KMOD_CTRL', 'KMOD_LALT',\n        # 'KMOD_LCTRL', 'KMOD_LMETA', 'KMOD_LSHIFT', 'KMOD_META',\n        # 'KMOD_MODE', 'KMOD_NONE'\n        if mods is None:\n            mods = pygame.key.get_mods()\n        self._modifiers = []\n        if mods & (pygame.KMOD_SHIFT | pygame.KMOD_LSHIFT):\n            self._modifiers.append('shift')\n        if mods & (pygame.KMOD_ALT | pygame.KMOD_LALT):\n            self._modifiers.append('alt')\n        if mods & (pygame.KMOD_CTRL | pygame.KMOD_LCTRL):\n            self._modifiers.append('ctrl')\n        if mods & (pygame.KMOD_META | pygame.KMOD_LMETA):\n            self._modifiers.append('meta')\n\n    def request_keyboard(self, callback, target, input_type='text'):\n        keyboard = super(WindowPygame, self).request_keyboard(\n            callback, target, input_type)\n        if android and not self.allow_vkeyboard:\n            android.show_keyboard(target, input_type)\n        return keyboard\n\n    def release_keyboard(self, *largs):\n        super(WindowPygame, self).release_keyboard(*largs)\n        if android:\n            android.hide_keyboard()\n        return True\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/core/window/window_sdl2.py",
    "content": "# found a way to include it more easily.\n'''\nSDL2 Window\n===========\n\nWindowing provider directly based on our own wrapped version of SDL.\n\nTODO:\n    - fix keys\n    - support scrolling\n    - clean code\n    - manage correctly all sdl events\n\n'''\n\n__all__ = ('WindowSDL2', )\n\nfrom os.path import join\nfrom kivy import kivy_data_dir\nfrom kivy.logger import Logger\nfrom kivy import metrics\nfrom kivy.base import EventLoop, ExceptionManager, stopTouchApp\nfrom kivy.clock import Clock\nfrom kivy.config import Config\nfrom kivy.core.window import WindowBase\nfrom kivy.core.window._window_sdl2 import _WindowSDL2Storage\nfrom kivy.input.provider import MotionEventProvider\nfrom kivy.input.motionevent import MotionEvent\nfrom kivy.resources import resource_find\nfrom kivy.utils import platform, deprecated\nfrom kivy.compat import unichr\nfrom collections import deque\n\nKMOD_LCTRL = 64\nKMOD_RCTRL = 128\nKMOD_RSHIFT = 2\nKMOD_LSHIFT = 1\nKMOD_RALT = 512\nKMOD_LALT = 256\nKMOD_LMETA = 1024\nKMOD_RMETA = 2048\n\nSDLK_SHIFTL = 1073742049\nSDLK_SHIFTR = 1073742053\nSDLK_LCTRL = 1073742048\nSDLK_RCTRL = 1073742052\nSDLK_LALT = 1073742050\nSDLK_RALT = 1073742054\nSDLK_LEFT = 1073741904\nSDLK_RIGHT = 1073741903\nSDLK_UP = 1073741906\nSDLK_DOWN = 1073741905\nSDLK_HOME = 1073741898\nSDLK_END = 1073741901\nSDLK_PAGEUP = 1073741899\nSDLK_PAGEDOWN = 1073741902\nSDLK_SUPER = 1073742051\nSDLK_CAPS = 1073741881\nSDLK_INSERT = 1073741897\nSDLK_KEYPADNUM = 1073741907\nSDLK_F1 = 1073741882\nSDLK_F2 = 1073741883\nSDLK_F3 = 1073741884\nSDLK_F4 = 1073741885\nSDLK_F5 = 1073741886\nSDLK_F6 = 1073741887\nSDLK_F7 = 1073741888\nSDLK_F8 = 1073741889\nSDLK_F9 = 1073741890\nSDLK_F10 = 1073741891\nSDLK_F11 = 1073741892\nSDLK_F12 = 1073741893\nSDLK_F13 = 1073741894\nSDLK_F14 = 1073741895\nSDLK_F15 = 1073741896\n\n\nclass SDL2MotionEvent(MotionEvent):\n    def depack(self, args):\n        self.is_touch = True\n        self.profile = ('pos', )\n        self.sx, self.sy = args\n        win = EventLoop.window\n        super(SDL2MotionEvent, self).depack(args)\n\n\nclass SDL2MotionEventProvider(MotionEventProvider):\n    win = None\n    q = deque()\n    touchmap = {}\n\n    def update(self, dispatch_fn):\n        touchmap = self.touchmap\n        while True:\n            try:\n                value = self.q.pop()\n            except IndexError:\n                return\n\n            action, fid, x, y = value\n            y = 1 - y\n            if fid not in touchmap:\n                touchmap[fid] = me = SDL2MotionEvent('sdl', fid, (x, y))\n            else:\n                me = touchmap[fid]\n                me.move((x, y))\n            if action == 'fingerdown':\n                dispatch_fn('begin', me)\n            elif action == 'fingerup':\n                me.update_time_end()\n                dispatch_fn('end', me)\n                del touchmap[fid]\n            else:\n                dispatch_fn('update', me)\n\n\nclass WindowSDL(WindowBase):\n\n    def __init__(self, **kwargs):\n        self._win = _WindowSDL2Storage()\n        super(WindowSDL, self).__init__()\n        self._mouse_x = self._mouse_y = -1\n        self._meta_keys = (KMOD_LCTRL, KMOD_RCTRL, KMOD_RSHIFT,\n            KMOD_LSHIFT, KMOD_RALT, KMOD_LALT, KMOD_LMETA,\n            KMOD_RMETA)\n        self.command_keys = {\n                    27: 'escape',\n                    9: 'tab',\n                    8: 'backspace',\n                    13: 'enter',\n                    127: 'del',\n                    271: 'enter',\n                    273: 'up',\n                    274: 'down',\n                    275: 'right',\n                    276: 'left',\n                    278: 'home',\n                    279: 'end',\n                    280: 'pgup',\n                    281: 'pgdown'}\n        self._mouse_buttons_down = set()\n\n    def create_window(self, *largs):\n\n        if self._fake_fullscreen:\n            if not self.borderless:\n                self.fullscreen = self._fake_fullscreen = False\n            elif not self.fullscreen or self.fullscreen == 'auto':\n                self.borderless = self._fake_fullscreen = False\n\n        if self.fullscreen == 'fake':\n            self.borderless = self._fake_fullscreen = True\n            Logger.warning(\"The 'fake' fullscreen option has been \"\n                            \"deprecated, use Window.borderless or the \"\n                            \"borderless Config option instead.\")\n\n        if not self.initialized:\n\n            if self.position == 'auto':\n                pos = None, None\n            elif self.position == 'custom':\n                pos = self.left, self.top\n\n            # setup !\n            w, h = self.system_size\n            resizable = Config.getboolean('graphics', 'resizable')\n            state = (Config.get('graphics', 'window_state')\n                     if self._is_desktop else None)\n            self.system_size = _size = self._win.setup_window(\n                pos[0], pos[1], w, h, self.borderless,\n                self.fullscreen, resizable, state)\n\n            # calculate density\n            sz = self._win._get_gl_size()[0]\n            self._density = density = sz / _size[0]\n            if self._is_desktop and self.size[0] != _size[0]:\n                self.dpi = density * 96.\n\n            # never stay with a None pos, application using w.center\n            # will be fired.\n            self._pos = (0, 0)\n        else:\n            w, h = self.system_size\n            self._win.resize_window(w, h)\n            self._win.set_border_state(self.borderless)\n            self._win.set_fullscreen_mode(self.fullscreen)\n\n        super(WindowSDL, self).create_window()\n\n        if self.initialized:\n            return\n\n        # auto add input provider\n        Logger.info('Window: auto add sdl2 input provider')\n        from kivy.base import EventLoop\n        SDL2MotionEventProvider.win = self\n        EventLoop.add_input_provider(SDL2MotionEventProvider('sdl', ''))\n\n        # set window icon before calling set_mode\n        try:\n            filename_icon = self.icon or Config.get('kivy', 'window_icon')\n            if filename_icon == '':\n                logo_size = 32\n                if platform == 'macosx':\n                    logo_size = 512\n                elif platform == 'win':\n                    logo_size = 64\n                filename_icon = 'kivy-icon-{}.png'.format(logo_size)\n                filename_icon = resource_find(\n                        join(kivy_data_dir, 'logo', filename_icon))\n            self.set_icon(filename_icon)\n        except:\n            Logger.exception('Window: cannot set icon')\n\n    def close(self):\n        self._win.teardown_window()\n        self.dispatch('on_close')\n\n    def maximize(self):\n        if self._is_desktop:\n            self._win.maximize_window()\n        else:\n            Logger.warning('Window: maximize() is used only on desktop OSes.')\n\n    def minimize(self):\n        if self._is_desktop:\n            self._win.minimize_window()\n        else:\n            Logger.warning('Window: minimize() is used only on desktop OSes.')\n\n    def restore(self):\n        if self._is_desktop:\n            self._win.restore_window()\n        else:\n            Logger.warning('Window: restore() is used only on desktop OSes.')\n\n    def hide(self):\n        if self._is_desktop:\n            self._win.hide_window()\n        else:\n            Logger.warning('Window: hide() is used only on desktop OSes.')\n\n    def show(self):\n        if self._is_desktop:\n            self._win.show_window()\n        else:\n            Logger.warning('Window: show() is used only on desktop OSes.')\n\n    @deprecated\n    def toggle_fullscreen(self):\n        if self.fullscreen in (True, 'auto'):\n            self.fullscreen = False\n        else:\n            self.fullscreen = 'auto'\n\n    def set_title(self, title):\n        self._win.set_window_title(title)\n\n    def set_icon(self, filename):\n        self._win.set_window_icon(str(filename))\n\n    def screenshot(self, *largs, **kwargs):\n        filename = super(WindowSDL, self).screenshot(*largs, **kwargs)\n        if filename is None:\n            return\n\n        from kivy.graphics.opengl import glReadPixels, GL_RGB, GL_UNSIGNED_BYTE\n        width, height = self.size\n        data = glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE)\n        self._win.save_bytes_in_png(filename, data, width, height)\n        Logger.debug('Window: Screenshot saved at <%s>' % filename)\n        return filename\n\n    def flip(self):\n        self._win.flip()\n        super(WindowSDL, self).flip()\n\n    def _fix_mouse_pos(self, x, y):\n        density = self._density\n        y -= 1\n        if self._is_desktop and self.size[0] != self._size[0]:\n            x, y = x * density, (y * density) - self.system_size[1]\n            #y = self.system_size[1] - y\n            self.mouse_pos = x, y\n        else:\n            self.mouse_pos = x, self.system_size[1] - y\n        return x, y\n\n    def _mainloop(self):\n        EventLoop.idle()\n\n        while True:\n            event = self._win.poll()\n            if event is False:\n                break\n            if event is None:\n                continue\n\n            action, args = event[0], event[1:]\n            if action == 'quit':\n                EventLoop.quit = True\n                self.close()\n                break\n\n            elif action in ('fingermotion', 'fingerdown', 'fingerup'):\n                # for finger, pass the raw event to SDL motion event provider\n                # XXX this is problematic. On OSX, it generates touches with 0,\n                # 0 coordinates, at the same times as mouse. But it works.\n                # We have a conflict of using either the mouse or the finger.\n                # Right now, we have no mechanism that we could use to know\n                # which is the preferred one for the application.\n                if platform == \"ios\":\n                    SDL2MotionEventProvider.q.appendleft(event)\n                pass\n\n            elif action == 'mousemotion':\n                x, y = args\n                x, y = self._fix_mouse_pos(x, y)\n                self._mouse_x = x\n                self._mouse_y = y\n                # don't dispatch motion if no button are pressed\n                if len(self._mouse_buttons_down) == 0:\n                    continue\n                self._mouse_meta = self.modifiers\n                self.dispatch('on_mouse_move', x, y, self.modifiers)\n\n            elif action in ('mousebuttondown', 'mousebuttonup'):\n                x, y, button = args\n                x, y = self._fix_mouse_pos(x, y)\n                btn = 'left'\n                if button == 3:\n                    btn = 'right'\n                elif button == 2:\n                    btn = 'middle'\n                eventname = 'on_mouse_down'\n                self._mouse_buttons_down.add(button)\n                if action == 'mousebuttonup':\n                    eventname = 'on_mouse_up'\n                    self._mouse_buttons_down.remove(button)\n                self._mouse_x = x\n                self._mouse_y = y\n                self.dispatch(eventname, x, y, btn, self.modifiers)\n            elif action.startswith('mousewheel'):\n                self._update_modifiers()\n                x, y, button = args\n                btn = 'scrolldown'\n                if action.endswith('up'):\n                    btn = 'scrollup'\n                elif action.endswith('right'):\n                    btn = 'scrollright'\n                elif action.endswith('left'):\n                    btn = 'scrollleft'\n\n                self._mouse_meta = self.modifiers\n                self._mouse_btn = btn\n                #times = x if y == 0 else y\n                #times = min(abs(times), 100)\n                #for k in range(times):\n                self._mouse_down = True\n                self.dispatch('on_mouse_down',\n                    self._mouse_x, self._mouse_y, btn, self.modifiers)\n                self._mouse_down = False\n                self.dispatch('on_mouse_up',\n                    self._mouse_x, self._mouse_y, btn, self.modifiers)\n\n            elif action == 'dropfile':\n                dropfile = args\n                self.dispatch('on_dropfile', dropfile[0])\n            # video resize\n            elif action == 'windowresized':\n                self._size = self._win.window_size\n                # don't use trigger here, we want to delay the resize event\n                cb = self._do_resize\n                Clock.unschedule(cb)\n                Clock.schedule_once(cb, .1)\n\n            elif action == 'windowresized':\n                self.canvas.ask_update()\n\n            elif action == 'windowrestored':\n                self.canvas.ask_update()\n\n            elif action == 'windowexposed':\n                self.canvas.ask_update()\n\n            elif action == 'windowminimized':\n                if Config.getboolean('kivy', 'pause_on_minimize'):\n                    self.do_pause()\n\n            elif action == 'joyaxismotion':\n                stickid, axisid, value = args\n                self.dispatch('on_joy_axis', stickid, axisid, value)\n            elif action == 'joyhatmotion':\n                stickid, hatid, value = args\n                self.dispatch('on_joy_hat', stickid, hatid, value)\n            elif action == 'joyballmotion':\n                stickid, ballid, xrel, yrel = args\n                self.dispatch('on_joy_ball', stickid, ballid, xrel, yrel)\n            elif action == 'joybuttondown':\n                stickid, buttonid = args\n                self.dispatch('on_joy_button_down', stickid, buttonid)\n            elif action == 'joybuttonup':\n                stickid, buttonid = args\n                self.dispatch('on_joy_button_up', stickid, buttonid)\n\n            elif action in ('keydown', 'keyup'):\n                mod, key, scancode, kstr = args\n\n                key_swap = {\n                    SDLK_LEFT: 276, SDLK_RIGHT: 275, SDLK_UP: 273,\n                    SDLK_DOWN: 274, SDLK_HOME: 278, SDLK_END: 279,\n                    SDLK_PAGEDOWN: 281, SDLK_PAGEUP: 280, SDLK_SHIFTR: 303,\n                    SDLK_SHIFTL: 304, SDLK_SUPER: 309, SDLK_LCTRL: 305,\n                    SDLK_RCTRL: 306, SDLK_LALT: 308, SDLK_RALT: 307,\n                    SDLK_CAPS: 301, SDLK_INSERT: 277, SDLK_F1: 282,\n                    SDLK_F2: 283, SDLK_F3: 284, SDLK_F4: 285, SDLK_F5: 286,\n                    SDLK_F6: 287, SDLK_F7: 288, SDLK_F8: 289, SDLK_F9: 290,\n                    SDLK_F10: 291, SDLK_F11: 292, SDLK_F12: 293, SDLK_F13: 294,\n                    SDLK_F14: 295, SDLK_F15: 296, SDLK_KEYPADNUM: 300}\n\n                if platform == 'ios':\n                    # XXX ios keyboard suck, when backspace is hit, the delete\n                    # keycode is sent. fix it.\n                    key_swap[127] = 8  # back\n\n                try:\n                    key = key_swap[key]\n                except KeyError:\n                    pass\n\n                if action == 'keydown':\n                    self._update_modifiers(mod, key)\n                else:\n                    self._update_modifiers(mod)  # ignore the key, it\n                                                 # has been released\n\n                # if mod in self._meta_keys:\n                if (key not in self._modifiers and\n                    key not in self.command_keys.keys()):\n                    try:\n                        kstr = unichr(key)\n                    except ValueError:\n                        pass\n                #if 'shift' in self._modifiers and key\\\n                #        not in self.command_keys.keys():\n                #    return\n\n                if action == 'keyup':\n                    self.dispatch('on_key_up', key, scancode)\n                    continue\n\n                # don't dispatch more key if down event is accepted\n                if self.dispatch('on_key_down', key,\n                                 scancode, kstr,\n                                 self.modifiers):\n                    continue\n                self.dispatch('on_keyboard', key,\n                              scancode, kstr,\n                              self.modifiers)\n\n            elif action == 'textinput':\n                text = args[0]\n                self.dispatch('on_textinput', text)\n                # XXX on IOS, keydown/up don't send unicode anymore.\n                # With latest sdl, the text is sent over textinput\n                # Right now, redo keydown/up, but we need to seperate both call\n                # too. (and adapt on_key_* API.)\n                #self.dispatch()\n                #self.dispatch('on_key_down', key, None, args[0],\n                #              self.modifiers)\n                #self.dispatch('on_keyboard', None, None, args[0],\n                #              self.modifiers)\n                #self.dispatch('on_key_up', key, None, args[0],\n                #              self.modifiers)\n\n            # unhandled event !\n            else:\n                Logger.trace('WindowSDL: Unhandled event %s' % str(event))\n\n    def _do_resize(self, dt):\n        Logger.debug('Window: Resize window to %s' % str(self.size))\n        self._win.resize_window(*self._size)\n        self.dispatch('on_resize', *self.size)\n\n    def do_pause(self):\n        # should go to app pause mode.\n        from kivy.app import App\n        from kivy.base import stopTouchApp\n        app = App.get_running_app()\n        if not app:\n            Logger.info('WindowSDL: No running App found, exit.')\n            stopTouchApp()\n            return\n\n        if not app.dispatch('on_pause'):\n            Logger.info('WindowSDL: App doesn\\'t support pause mode, stop.')\n            stopTouchApp()\n            return\n\n        # XXX FIXME wait for sdl resume\n        while True:\n            event = self._win.poll()\n            if event is False:\n                continue\n            if event is None:\n                continue\n\n            action, args = event[0], event[1:]\n            if action == 'quit':\n                EventLoop.quit = True\n                self.close()\n                break\n            elif action == 'windowrestored':\n                break\n\n        app.dispatch('on_resume')\n\n    def mainloop(self):\n        # don't known why, but pygame required a resize event\n        # for opengl, before mainloop... window reinit ?\n        #self.dispatch('on_resize', *self.size)\n\n        while not EventLoop.quit and EventLoop.status == 'started':\n            try:\n                self._mainloop()\n            except BaseException as inst:\n                # use exception manager first\n                r = ExceptionManager.handle_exception(inst)\n                if r == ExceptionManager.RAISE:\n                    stopTouchApp()\n                    raise\n                else:\n                    pass\n\n    #\n    # Pygame wrapper\n    #\n    def _update_modifiers(self, mods=None, key=None):\n        # Available mod, from dir(pygame)\n        # 'KMOD_ALT', 'KMOD_CAPS', 'KMOD_CTRL', 'KMOD_LALT',\n        # 'KMOD_LCTRL', 'KMOD_LMETA', 'KMOD_LSHIFT', 'KMOD_META',\n        # 'KMOD_MODE', 'KMOD_NONE'\n        if mods is None and key is None:\n            return\n        modifiers = set()\n\n        if mods is not None:\n            if mods & (KMOD_RSHIFT | KMOD_LSHIFT):\n                modifiers.add('shift')\n            if mods & (KMOD_RALT | KMOD_LALT):\n                modifiers.add('alt')\n            if mods & (KMOD_RCTRL | KMOD_LCTRL):\n                modifiers.add('ctrl')\n            if mods & (KMOD_RMETA | KMOD_LMETA):\n                modifiers.add('meta')\n\n        if key is not None:\n            if key in (KMOD_RSHIFT, KMOD_LSHIFT):\n                modifiers.add('shift')\n            if key in (KMOD_RALT, KMOD_LALT):\n                modifiers.add('alt')\n            if key in (KMOD_RCTRL, KMOD_LCTRL):\n                modifiers.add('ctrl')\n            if key in (KMOD_RMETA, KMOD_LMETA):\n                modifiers.add('meta')\n\n        self._modifiers = list(modifiers)\n        return\n\n    def request_keyboard(self, callback, target, input_type='text'):\n        self._sdl_keyboard = super(WindowSDL, self).\\\n            request_keyboard(callback, target, input_type)\n        self._win.show_keyboard()\n        Clock.schedule_interval(self._check_keyboard_shown, 1 / 5.)\n        return self._sdl_keyboard\n\n    def release_keyboard(self, *largs):\n        super(WindowSDL, self).release_keyboard(*largs)\n        self._win.hide_keyboard()\n        self._sdl_keyboard = None\n        return True\n\n    def _check_keyboard_shown(self, dt):\n        if self._sdl_keyboard is None:\n            return False\n        if not self._win.is_keyboard_shown():\n            self._sdl_keyboard.release()\n\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/data/glsl/default.fs",
    "content": "$HEADER$\nvoid main (void){\n    gl_FragColor = frag_color * texture2D(texture0, tex_coord0);\n}\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/data/glsl/default.vs",
    "content": "$HEADER$\nvoid main (void) {\n  frag_color = color * vec4(1.0, 1.0, 1.0, opacity);\n  tex_coord0 = vTexCoords0;\n  gl_Position = projection_mat * modelview_mat * vec4(vPosition.xy, 0.0, 1.0);\n}\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/data/glsl/header.fs",
    "content": "#ifdef GL_ES\n    precision highp float;\n#endif\n\n/* Outputs from the vertex shader */\nvarying vec4 frag_color;\nvarying vec2 tex_coord0;\n\n/* uniform texture samplers */\nuniform sampler2D texture0;\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/data/glsl/header.vs",
    "content": "#ifdef GL_ES\n    precision highp float;\n#endif\n\n/* Outputs to the fragment shader */\nvarying vec4 frag_color;\nvarying vec2 tex_coord0;\n\n/* vertex attributes */\nattribute vec2     vPosition;\nattribute vec2     vTexCoords0;\n\n/* uniform variables */\nuniform mat4       modelview_mat;\nuniform mat4       projection_mat;\nuniform vec4       color;\nuniform float      opacity;\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/data/images/defaulttheme.atlas",
    "content": "{\"defaulttheme-0.png\": {\"progressbar_background\": [391, 227, 24, 24], \"tab_btn_disabled\": [264, 137, 32, 32], \"tab_btn_pressed\": [366, 137, 32, 32], \"image-missing\": [152, 171, 48, 48], \"splitter_h\": [174, 123, 32, 7], \"splitter_down\": [501, 253, 7, 32], \"splitter_disabled_down\": [503, 291, 7, 32], \"vkeyboard_key_down\": [468, 137, 32, 32], \"vkeyboard_disabled_key_down\": [400, 137, 32, 32], \"selector_right\": [248, 223, 55, 62], \"player-background\": [2, 287, 103, 103], \"selector_middle\": [191, 223, 55, 62], \"spinner\": [235, 82, 29, 37], \"tab_btn_disabled_pressed\": [298, 137, 32, 32], \"switch-button_disabled\": [277, 291, 43, 32], \"textinput_disabled_active\": [372, 326, 64, 64], \"splitter_grip\": [36, 50, 12, 26], \"vkeyboard_key_normal\": [2, 44, 32, 32], \"button_disabled\": [80, 82, 29, 37], \"media-playback-stop\": [302, 171, 48, 48], \"splitter\": [501, 87, 7, 32], \"splitter_down_h\": [140, 123, 32, 7], \"sliderh_background_disabled\": [72, 132, 41, 37], \"modalview-background\": [464, 456, 45, 54], \"button\": [142, 82, 29, 37], \"splitter_disabled\": [502, 137, 7, 32], \"checkbox_radio_disabled_on\": [433, 87, 32, 32], \"slider_cursor\": [402, 171, 48, 48], \"vkeyboard_disabled_background\": [68, 221, 64, 64], \"checkbox_disabled_on\": [297, 87, 32, 32], \"sliderv_background_disabled\": [2, 78, 37, 41], \"button_disabled_pressed\": [111, 82, 29, 37], \"audio-volume-muted\": [102, 171, 48, 48], \"close\": [417, 231, 20, 20], \"action_group_disabled\": [452, 171, 33, 48], \"vkeyboard_background\": [2, 221, 64, 64], \"checkbox_off\": [331, 87, 32, 32], \"tab_disabled\": [305, 253, 96, 32], \"sliderh_background\": [115, 132, 41, 37], \"switch-button\": [322, 291, 43, 32], \"tree_closed\": [439, 231, 20, 20], \"bubble_btn_pressed\": [435, 291, 32, 32], \"selector_left\": [134, 223, 55, 62], \"filechooser_file\": [174, 326, 64, 64], \"checkbox_radio_disabled_off\": [399, 87, 32, 32], \"checkbox_radio_on\": [196, 137, 32, 32], \"checkbox_on\": [365, 87, 32, 32], \"button_pressed\": [173, 82, 29, 37], \"audio-volume-high\": [464, 406, 48, 48], \"audio-volume-low\": [2, 171, 48, 48], \"progressbar\": [305, 227, 32, 24], \"previous_normal\": [487, 187, 19, 32], \"separator\": [504, 342, 5, 48], \"filechooser_folder\": [240, 326, 64, 64], \"checkbox_radio_off\": [467, 87, 32, 32], \"textinput_active\": [306, 326, 64, 64], \"textinput\": [438, 326, 64, 64], \"player-play-overlay\": [122, 395, 117, 115], \"media-playback-pause\": [202, 171, 48, 48], \"sliderv_background\": [41, 78, 37, 41], \"ring\": [354, 402, 108, 108], \"bubble_arrow\": [487, 175, 16, 10], \"slider_cursor_disabled\": [352, 171, 48, 48], \"checkbox_disabled_off\": [469, 291, 32, 32], \"action_group_down\": [2, 121, 33, 48], \"spinner_disabled\": [204, 82, 29, 37], \"splitter_disabled_h\": [106, 123, 32, 7], \"bubble\": [107, 325, 65, 65], \"media-playback-start\": [252, 171, 48, 48], \"vkeyboard_disabled_key_normal\": [434, 137, 32, 32], \"overflow\": [230, 137, 32, 32], \"tree_opened\": [461, 231, 20, 20], \"action_item\": [339, 227, 24, 24], \"bubble_btn\": [401, 291, 32, 32], \"audio-volume-medium\": [52, 171, 48, 48], \"action_group\": [37, 121, 33, 48], \"spinner_pressed\": [266, 82, 29, 37], \"filechooser_selected\": [2, 392, 118, 118], \"tab\": [403, 253, 96, 32], \"action_bar\": [158, 133, 36, 36], \"action_view\": [365, 227, 24, 24], \"tab_btn\": [332, 137, 32, 32], \"switch-background\": [192, 291, 83, 32], \"splitter_disabled_down_h\": [72, 123, 32, 7], \"action_item_down\": [367, 291, 32, 32], \"switch-background_disabled\": [107, 291, 83, 32], \"textinput_disabled\": [241, 399, 111, 111], \"splitter_grip_h\": [483, 239, 26, 12]}}"
  },
  {
    "path": "tickeys/kivy_32/kivy/data/keyboards/azerty.json",
    "content": "{\n    \"title\" : \"Azerty\",\n    \"description\" : \"A French keyboard without international keys\",\n    \"cols\" : 15,\n\t\"rows\": 5,\n    \"normal_1\" : [\n        [\"@\", \"@\", \"`\", 1],    [\"&\", \"&\", \"1\", 1],    [\"\\u00e9\", \"\\u00e9\", \"2\", 1],\n        [\"'\", \"'\", \"3\", 1],    [\"\\\"\", \"\\\"\", \"4\", 1],  [\"[\", \"[\", \"5\", 1],\n        [\"-\", \"-\", \"6\", 1],    [\"\\u00e8\", \"\\u00e8\", \"7\", 1],    [\"_\", \"_\", \"8\", 1],\n        [\"\\u00e7\", \"\\u00e7\", \"9\", 1],    [\"\\u00e0\", \"\\u00e0\", \"0\", 1],    [\"]\", \"]\", \"+\", 1],\n        [\"=\", \"=\", \"=\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"normal_2\" : [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"a\", \"a\", \"a\", 1],    [\"z\", \"z\", \"z\", 1],\n        [\"e\", \"e\", \"e\", 1],    [\"r\", \"r\", \"r\", 1],    [\"t\", \"t\", \"t\", 1],\n        [\"y\", \"y\", \"y\", 1],    [\"u\", \"u\", \"u\", 1],    [\"i\", \"i\", \"i\", 1],\n        [\"o\", \"o\", \"o\", 1],    [\"p\", \"p\", \"p\", 1],    [\"^\", \"^\", \"^\", 1],\n        [\"$\", \"$\", \"}\", 1],    [\"\\u23ce\", null, \"enter\", 1.5]\n    ],\n    \"normal_3\" : [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"q\", \"q\", \"q\", 1],    [\"s\", \"s\", \"s\", 1],\n        [\"d\", \"d\", \"d\", 1],    [\"f\", \"f\", \"f\", 1],    [\"g\", \"g\", \"g\", 1],\n        [\"h\", \"h\", \"h\", 1],    [\"j\", \"j\", \"j\", 1],    [\"k\", \"k\", \"k\", 1],\n        [\"l\", \"l\", \"l\", 1],    [\"m\", \"m\", \"m\", 1],    [\"\\u00f9\", \"\\u00f9\", \"%\", 1],\n        [\"*\", \"*\", \"*\", 1],    [\"\\u23ce\", null, \"enter\", 1.2]\n    ],\n    \"normal_4\" : [\n        [\"\\u21e7\", null, \"shift\", 1.5],  [\"<\", \"<\", null, 1],    [\"w\", \"w\", null, 1],\n        [\"x\", \"x\", null, 1],\n        [\"c\", \"c\", null, 1],    [\"v\", \"v\", null, 1],    [\"b\", \"b\", null, 1],\n        [\"n\", \"n\", null, 1],    [\",\", \",\", null, 1],    [\";\", \";\", null, 1],\n        [\":\", \":\", null, 1],    [\"!\", \"!\", null, 1],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"normal_5\" : [\n        [\" \", \" \", \"spacebar\", 12], [\"\\u2b12\", null, \"layout\", 1.5], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ],\n    \"shift_1\" : [\n        [\"|\", \"|\", \"|\", 1],    [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],\n        [\"3\", \"3\", \"3\", 1],    [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],\n        [\"6\", \"6\", \"6\", 1],    [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],\n        [\"9\", \"9\", \"9\", 1],    [\"0\", \"0\", \"0\", 1],    [\"#\", \"#\", \"#\", 1],\n        [\"+\", \"+\", \"+\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"shift_2\" : [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"A\", \"A\", \"a\", 1],    [\"Z\", \"Z\", null, 1],\n        [\"E\", \"E\", \"e\", 1],    [\"R\", \"R\", \"r\", 1],    [\"T\", \"T\", \"t\", 1],\n        [\"Y\", \"Y\", \"y\", 1],    [\"U\", \"U\", \"u\", 1],    [\"I\", \"I\", \"i\", 1],\n        [\"O\", \"O\", \"o\", 1],    [\"P\", \"P\", \"p\", 1],    [\"[\", \"[\", \"[\", 1],\n        [\"]\", \"]\", \"]\", 1],    [\"\\u23ce\", null, \"enter\", 1.5]\n    ],\n    \"shift_3\" : [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"Q\", \"Q\", \"q\", 1],    [\"S\", \"S\", \"s\", 1],\n        [\"D\", \"D\", \"d\", 1],    [\"F\", \"F\", \"f\", 1],    [\"G\", \"G\", \"g\", 1],\n        [\"H\", \"H\", \"h\", 1],    [\"J\", \"J\", \"j\", 1],    [\"K\", \"K\", \"k\", 1],\n        [\"L\", \"L\", \"l\", 1],    [\"M\", \"M\", \"m\", 1],    [\"%\", \"%\", \"%\", 1],\n        [\"\\u00b5\", \"\\u00b5\", \"*\", 1],    [\"\\u23ce\", null, \"enter\", 1.2]\n    ],\n    \"shift_4\" : [\n        [\"\\u21e7\", null, \"shift\", 1.5],  [\">\", \">\", \">\", 1],    [\"W\", \"W\", \"w\", 1],\n        [\"X\", \"X\", \"x\", 1],    [\"C\", \"C\", \"c\", 1],    [\"V\", \"V\", \"v\", 1],\n        [\"B\", \"B\", \"b\", 1],    [\"N\", \"N\", \"n\", 1],    [\"?\", \"?\", \"?\", 1],\n        [\".\", \".\", \".\", 1],    [\"/\", \"/\", \"/\", 1],    [\"\\u00a7\", \"\\u00a7\", \"!\", 1],\n        [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"shift_5\" : [\n        [\" \", \" \", \"spacebar\", 12], [\"\\u2b12\", null, \"layout\", 1.5], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ]\n}\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/data/keyboards/de_CH.json",
    "content": "{\n    \"title\": \"de_CH\",\n    \"description\": \"A Swiss German keyboard, touch optimized (no shift+caps lock)\",\n\t\"cols\": 15,\n    \"rows\": 5,\n    \"normal_1\": [\n        [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],    [\"3\", \"3\", \"3\", 1],\n        [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],    [\"6\", \"6\", \"6\", 1],\n        [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],    [\"9\", \"9\", \"9\", 1],\n        [\"0\", \"0\", \"0\", 1],    [\"@\", \"@\", \"@\", 1],    [\"?\", \"?\", \"?\", 1],\n        [\"!\", \"!\", \"!\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"normal_2\" : [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"q\", \"q\", \"q\", 1],    [\"w\", \"w\", \"w\", 1],\n        [\"e\", \"e\", \"e\", 1],    [\"r\", \"r\", \"r\", 1],    [\"t\", \"t\", \"t\", 1],\n        [\"z\", \"z\", \"z\", 1],    [\"u\", \"u\", \"u\", 1],    [\"i\", \"i\", \"i\", 1],\n        [\"o\", \"o\", \"o\", 1],    [\"p\", \"p\", \"p\", 1],    [\"ü\", \"ü\", \"ü\", 1],\n        [\":\", \":\", \":\", 1],    [\"$\", \"$\", \"$\", 1.5]\n    ],\n    \"normal_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"a\", \"a\", \"a\", 1],    [\"s\", \"s\", \"s\", 1],\n        [\"d\", \"d\", \"d\", 1],    [\"f\", \"f\", \"f\", 1],    [\"g\", \"g\", \"g\", 1],\n        [\"h\", \"h\", \"h\", 1],    [\"j\", \"j\", \"j\", 1],    [\"k\", \"k\", \"k\", 1],\n        [\"l\", \"l\", \"l\", 1],    [\"ö\", \"ö\", \"ö\", 1],    [\"ä\", \"ä\", \"ä\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"normal_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"y\", \"y\", \"y\", 1],    [\"x\", \"x\", \"x\", 1],\n        [\"c\", \"c\", \"c\", 1],    [\"v\", \"v\", \"v\", 1],    [\"b\", \"b\", \"b\", 1],\n        [\"n\", \"n\", \"n\", 1],    [\"m\", \"m\", \"m\", 1],    [\",\", \",\", \",\", 1],\n        [\".\", \".\", \".\", 1],    [\"-\", \"-\", \"-\", 1],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"normal_5\": [\n        [\"#+=\", null, \"special\", 2.5], [\" \", \" \", \"spacebar\", 11], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ],\n\n    \"shift_1\": [\n        [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],    [\"3\", \"3\", \"3\", 1],\n        [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],    [\"6\", \"6\", \"6\", 1],\n        [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],    [\"9\", \"9\", \"9\", 1],\n        [\"0\", \"0\", \"0\", 1],    [\"@\", \"@\", \"@\", 1],    [\"?\", \"?\", \"?\", 1],\n        [\"!\", \"!\", \"!\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"shift_2\": [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"Q\", \"Q\", null, 1],    [\"W\", \"W\", null, 1],\n        [\"E\", \"E\", \"e\", 1],    [\"R\", \"R\", \"r\", 1],    [\"T\", \"T\", \"t\", 1],\n        [\"Z\", \"Z\", \"z\", 1],    [\"U\", \"U\", \"u\", 1],    [\"I\", \"I\", \"i\", 1],\n        [\"O\", \"O\", \"o\", 1],    [\"P\", \"P\", \"p\", 1],    [\"Ü\", \"Ü\", \"Ü\", 1],\n        [\":\", \":\", \":\", 1],    [\"/\", \"/\", \"/\", 1.5]\n    ],\n    \"shift_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"A\", \"A\", \"a\", 1],    [\"S\", \"S\", \"s\", 1],\n        [\"D\", \"D\", \"d\", 1],    [\"F\", \"F\", \"f\", 1],    [\"G\", \"G\", \"g\", 1],\n        [\"H\", \"H\", \"h\", 1],    [\"J\", \"J\", \"j\", 1],    [\"K\", \"K\", \"k\", 1],\n        [\"L\", \"L\", \"l\", 1],    [\"Ö\", \"Ö\", \"Ö\", 1],    [\"Ä\", \"Ä\", \"Ä\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"shift_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"Y\", \"Y\", \"y\", 1],  [\"X\", \"X\", \"x\", 1],\n        [\"C\", \"C\", \"c\", 1],    [\"V\", \"V\", \"v\", 1],    [\"B\", \"B\", \"b\", 1],\n        [\"N\", \"N\", \"n\", 1],    [\"M\", \"M\", \"m\", 1],    [\";\", \";\", \";\", 1],\n        [\":\", \":\", \":\", 1],    [\"_\", \"_\", \"_\", 1],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"shift_5\": [\n        [\"#+=\", null, \"special\", 2.5], [\" \", \" \", \"spacebar\", 11], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ],\n\n    \"special_1\": [\n        [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],    [\"3\", \"3\", \"3\", 1],\n        [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],    [\"6\", \"6\", \"6\", 1],\n        [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],    [\"9\", \"9\", \"9\", 1],\n        [\"0\", \"0\", \"0\", 1],    [\"@\", \"@\", \"@\", 1],    [\"?\", \"?\", \"?\", 1],\n        [\"!\", \"!\", \"!\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"special_2\": [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"(\", \"(\", \"(\", 1],    [\")\", \")\", \")\", 1],\n        [\"{\", \"{\", \"{\", 1],    [\"}\", \"}\", \"}\", 1],    [\"[\", \"[\", \"[\", 1],\n        [\"]\", \"]\", \"]\", 1],    [\"€\", \"€\", \"€\", 1],    [\"$\", \"$\", \"$\", 1],\n        [\"£\", \"£\", \"£\", 1],    [\"¥\", \"¥\", \"¥\", 1],    [\"è\", \"è\", \"è\", 1],\n        [\"•\", \"•\", \"•\", 1],    [\"|\", \"|\", \"|\", 1.5]\n    ],\n    \"special_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"“\", \"“\", \"“\", 1],    [\"`\", \"`\", \"`\", 1],\n        [\"«\", \"«\", \"«\", 1],    [\"»\", \"»\", \"»\", 1],    [\"#\", \"#\", \"#\", 1],\n        [\"%\", \"%\", \"%\", 1],    [\"^\", \"^\", \"^\", 1],    [\"°\", \"°\", \"°\", 1],\n        [\"&\", \"&\", \"&\", 1],    [\"é\", \"é\", \"é\", 1],    [\"à\", \"à\", \"à\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"special_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"+\", \"+\", \"+\", 1],  [\"=\", \"=\", \"=\", 1],\n        [\"<\", \"<\", \"<\", 1],    [\">\", \">\", \">\", 1],    [\"*\", \"*\", \"*\", 1],\n        [\"È\", \"È\", \"È\", 1],    [\"É\", \"É\", \"É\", 1],    [\"À\", \"À\", \"À\", 1],\n        [\":\", \":\", \":\", 1],    [\"_\", \"_\", \"_\", 1],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"special_5\": [\n        [\"#+=\", null, \"special\", 2.5], [\" \", \" \", \"spacebar\", 11], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ]\n}\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/data/keyboards/en_US.json",
    "content": "{\n    \"title\": \"en_US\",\n    \"description\": \"A US Keyboard, touch optimized (no shift+caps lock)\",\n\t\"cols\": 15,\n    \"rows\": 5,\n    \"normal_1\": [\n        [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],    [\"3\", \"3\", \"3\", 1],\n        [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],    [\"6\", \"6\", \"6\", 1],\n        [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],    [\"9\", \"9\", \"9\", 1],\n        [\"0\", \"0\", \"0\", 1],    [\"@\", \"@\", \"@\", 1],    [\"?\", \"?\", \"?\", 1],\n        [\"!\", \"!\", \"!\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"normal_2\" : [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"q\", \"q\", \"q\", 1],    [\"w\", \"w\", \"w\", 1],\n        [\"e\", \"e\", \"e\", 1],    [\"r\", \"r\", \"r\", 1],    [\"t\", \"t\", \"t\", 1],\n        [\"y\", \"y\", \"y\", 1],    [\"u\", \"u\", \"u\", 1],    [\"i\", \"i\", \"i\", 1],\n        [\"o\", \"o\", \"o\", 1],    [\"p\", \"p\", \"p\", 1],    [\"[\", \"[\", \"[\", 1],\n        [\"]\", \"]\", \"]\", 1],    [\"\\\\\", \"\\\\\", \"\\\\\", 1.5]\n    ],\n    \"normal_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"a\", \"a\", \"a\", 1],    [\"s\", \"s\", \"s\", 1],\n        [\"d\", \"d\", \"d\", 1],    [\"f\", \"f\", \"f\", 1],    [\"g\", \"g\", \"g\", 1],\n        [\"h\", \"h\", \"h\", 1],    [\"j\", \"j\", \"j\", 1],    [\"k\", \"k\", \"k\", 1],\n        [\"l\", \"l\", \"l\", 1],    [\";\", \";\", \";\", 1],    [\"'\", \"'\", \"'\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"normal_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"z\", \"z\", \"z\", 1],    [\"x\", \"x\", \"x\", 1],\n        [\"c\", \"c\", \"c\", 1],    [\"v\", \"v\", \"v\", 1],    [\"b\", \"b\", \"b\", 1],\n        [\"n\", \"n\", \"n\", 1],    [\"m\", \"m\", \"m\", 1],    [\",\", \",\", \",\", 1],\n        [\".\", \".\", \".\", 1],    [\"/\", \"/\", \"/\", 1],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"normal_5\": [\n        [\"#+=\", null, \"special\", 2.5], [\" \", \" \", \"spacebar\", 11], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ],\n\n    \"shift_1\": [\n        [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],    [\"3\", \"3\", \"3\", 1],\n        [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],    [\"6\", \"6\", \"6\", 1],\n        [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],    [\"9\", \"9\", \"9\", 1],\n        [\"0\", \"0\", \"0\", 1],    [\"@\", \"@\", \"@\", 1],    [\"?\", \"?\", \"?\", 1],\n        [\"!\", \"!\", \"!\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"shift_2\": [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"Q\", \"Q\", null, 1],    [\"W\", \"W\", null, 1],\n        [\"E\", \"E\", \"e\", 1],    [\"R\", \"R\", \"r\", 1],    [\"T\", \"T\", \"t\", 1],\n        [\"Y\", \"Y\", \"y\", 1],    [\"U\", \"U\", \"u\", 1],    [\"I\", \"I\", \"i\", 1],\n        [\"O\", \"O\", \"o\", 1],    [\"P\", \"P\", \"p\", 1],    [\"{\", \"{\", \"{\", 1],\n        [\"}\", \"}\", \"}\", 1],    [\"|\", \"|\", \"|\", 1.5]\n    ],\n    \"shift_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"A\", \"A\", \"a\", 1],    [\"S\", \"S\", \"s\", 1],\n        [\"D\", \"D\", \"d\", 1],    [\"F\", \"F\", \"f\", 1],    [\"G\", \"G\", \"g\", 1],\n        [\"H\", \"H\", \"h\", 1],    [\"J\", \"J\", \"j\", 1],    [\"K\", \"K\", \"k\", 1],\n        [\"L\", \"L\", \"l\", 1],    [\":\", \":\", \":\", 1],    [\"\\\"\", \"\\\"\", \"\\\"\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"shift_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"Z\", \"Z\", \"z\", 1],  [\"X\", \"X\", \"x\", 1],\n        [\"C\", \"C\", \"c\", 1],    [\"V\", \"V\", \"v\", 1],    [\"B\", \"B\", \"b\", 1],\n        [\"N\", \"N\", \"n\", 1],    [\"M\", \"M\", \"m\", 1],    [\"<\", \"<\", \"<\", 1],\n        [\">\", \">\", \">\", 1],    [\"?\", \"?\", \"?\", 1],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"shift_5\": [\n        [\"#+=\", null, \"special\", 2.5], [\" \", \" \", \"spacebar\", 11], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ],\n\n    \"special_1\": [\n        [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],    [\"3\", \"3\", \"3\", 1],\n        [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],    [\"6\", \"6\", \"6\", 1],\n        [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],    [\"9\", \"9\", \"9\", 1],\n        [\"0\", \"0\", \"0\", 1],    [\"@\", \"@\", \"@\", 1],    [\"?\", \"?\", \"?\", 1],\n        [\"!\", \"!\", \"!\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"special_2\": [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"(\", \"(\", \"(\", 1],    [\")\", \")\", \")\", 1],\n        [\"{\", \"{\", \"{\", 1],    [\"}\", \"}\", \"}\", 1],    [\"[\", \"[\", \"[\", 1],\n        [\"]\", \"]\", \"]\", 1],    [\"€\", \"€\", \"€\", 1],    [\"$\", \"$\", \"$\", 1],\n        [\"£\", \"£\", \"£\", 1],    [\"¥\", \"¥\", \"¥\", 1],    [\"˘\", \"˘\", \"˘\", 1],\n        [\"•\", \"•\", \"•\", 1],    [\"|\", \"|\", \"|\", 1.5]\n    ],\n    \"special_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"“\", \"“\", \"“\", 1],    [\"`\", \"`\", \"`\", 1],\n        [\"«\", \"«\", \"«\", 1],    [\"»\", \"»\", \"»\", 1],    [\"#\", \"#\", \"#\", 1],\n        [\"%\", \"%\", \"%\", 1],    [\"^\", \"^\", \"^\", 1],    [\"°\", \"°\", \"°\", 1],\n        [\"&\", \"&\", \"&\", 1],    [\"ÿ\", \"ÿ\", \"ÿ\", 1],    [\"Æ\", \"Æ\", \"Æ\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"special_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"+\", \"+\", \"+\", 1],  [\"=\", \"=\", \"=\", 1],\n        [\"<\", \"<\", \"<\", 1],    [\">\", \">\", \">\", 1],    [\"*\", \"*\", \"*\", 1],\n        [\"Ù\", \"Ù\", \"Ù\", 1],    [\"~\", \"~\", \"~\", 1],    [\"À\", \"À\", \"À\", 1],\n        [\":\", \":\", \":\", 1],    [\"_\", \"_\", \"_\", 1],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"special_5\": [\n        [\"#+=\", null, \"special\", 2.5], [\" \", \" \", \"spacebar\", 11], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ]\n}\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/data/keyboards/fr_CH.json",
    "content": "{\n    \"title\": \"fr_CH\",\n    \"description\": \"A Swiss French keyboard, touch optimized (no shift+caps lock)\",\n\t\"cols\": 15,\n    \"rows\": 5,\n    \"normal_1\": [\n        [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],    [\"3\", \"3\", \"3\", 1],\n        [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],    [\"6\", \"6\", \"6\", 1],\n        [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],    [\"9\", \"9\", \"9\", 1],\n        [\"0\", \"0\", \"0\", 1],    [\"@\", \"@\", \"@\", 1],    [\"?\", \"?\", \"?\", 1],\n        [\"!\", \"!\", \"!\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"normal_2\" : [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"q\", \"q\", \"q\", 1],    [\"w\", \"w\", \"w\", 1],\n        [\"e\", \"e\", \"e\", 1],    [\"r\", \"r\", \"r\", 1],    [\"t\", \"t\", \"t\", 1],\n        [\"z\", \"z\", \"z\", 1],    [\"u\", \"u\", \"u\", 1],    [\"i\", \"i\", \"i\", 1],\n        [\"o\", \"o\", \"o\", 1],    [\"p\", \"p\", \"p\", 1],    [\"è\", \"è\", \"è\", 1],\n        [\":\", \":\", \":\", 1],    [\"$\", \"$\", \"$\", 1.5]\n    ],\n    \"normal_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"a\", \"a\", \"a\", 1],    [\"s\", \"s\", \"s\", 1],\n        [\"d\", \"d\", \"d\", 1],    [\"f\", \"f\", \"f\", 1],    [\"g\", \"g\", \"g\", 1],\n        [\"h\", \"h\", \"h\", 1],    [\"j\", \"j\", \"j\", 1],    [\"k\", \"k\", \"k\", 1],\n        [\"l\", \"l\", \"l\", 1],    [\"é\", \"é\", \"é\", 1],    [\"à\", \"à\", \"à\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"normal_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"y\", \"y\", \"y\", 1],    [\"x\", \"x\", \"x\", 1],\n        [\"c\", \"c\", \"c\", 1],    [\"v\", \"v\", \"v\", 1],    [\"b\", \"b\", \"b\", 1],\n        [\"n\", \"n\", \"n\", 1],    [\"m\", \"m\", \"m\", 1],    [\",\", \",\", \",\", 1],\n        [\".\", \".\", \".\", 1],    [\"-\", \"-\", \"-\", 1],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"normal_5\": [\n        [\"#+=\", null, \"special\", 2.5], [\" \", \" \", \"spacebar\", 11], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ],\n\n    \"shift_1\": [\n        [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],    [\"3\", \"3\", \"3\", 1],\n        [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],    [\"6\", \"6\", \"6\", 1],\n        [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],    [\"9\", \"9\", \"9\", 1],\n        [\"0\", \"0\", \"0\", 1],    [\"@\", \"@\", \"@\", 1],    [\"?\", \"?\", \"?\", 1],\n        [\"!\", \"!\", \"!\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"shift_2\": [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"Q\", \"Q\", null, 1],    [\"W\", \"W\", null, 1],\n        [\"E\", \"E\", \"e\", 1],    [\"R\", \"R\", \"r\", 1],    [\"T\", \"T\", \"t\", 1],\n        [\"Z\", \"Z\", \"z\", 1],    [\"U\", \"U\", \"u\", 1],    [\"I\", \"I\", \"i\", 1],\n        [\"O\", \"O\", \"o\", 1],    [\"P\", \"P\", \"p\", 1],    [\"È\", \"È\", \"È\", 1],\n        [\":\", \":\", \":\", 1],    [\"/\", \"/\", \"/\", 1.5]\n    ],\n    \"shift_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"A\", \"A\", \"a\", 1],    [\"S\", \"S\", \"s\", 1],\n        [\"D\", \"D\", \"d\", 1],    [\"F\", \"F\", \"f\", 1],    [\"G\", \"G\", \"g\", 1],\n        [\"H\", \"H\", \"h\", 1],    [\"J\", \"J\", \"j\", 1],    [\"K\", \"K\", \"k\", 1],\n        [\"L\", \"L\", \"l\", 1],    [\"É\", \"É\", \"É\", 1],    [\"À\", \"À\", \"À\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"shift_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"Y\", \"Y\", \"y\", 1],  [\"X\", \"X\", \"x\", 1],\n        [\"C\", \"C\", \"c\", 1],    [\"V\", \"V\", \"v\", 1],    [\"B\", \"B\", \"b\", 1],\n        [\"N\", \"N\", \"n\", 1],    [\"M\", \"M\", \"m\", 1],    [\";\", \";\", \";\", 1],\n        [\":\", \":\", \":\", 1],    [\"_\", \"_\", \"_\", 1],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"shift_5\": [\n        [\"#+=\", null, \"special\", 2.5], [\" \", \" \", \"spacebar\", 11], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ],\n\n    \"special_1\": [\n        [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],    [\"3\", \"3\", \"3\", 1],\n        [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],    [\"6\", \"6\", \"6\", 1],\n        [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],    [\"9\", \"9\", \"9\", 1],\n        [\"0\", \"0\", \"0\", 1],    [\"@\", \"@\", \"@\", 1],    [\"?\", \"?\", \"?\", 1],\n        [\"!\", \"!\", \"!\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"special_2\": [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"(\", \"(\", \"(\", 1],    [\")\", \")\", \")\", 1],\n        [\"{\", \"{\", \"{\", 1],    [\"}\", \"}\", \"}\", 1],    [\"[\", \"[\", \"[\", 1],\n        [\"]\", \"]\", \"]\", 1],    [\"€\", \"€\", \"€\", 1],    [\"$\", \"$\", \"$\", 1],\n        [\"£\", \"£\", \"£\", 1],    [\"¥\", \"¥\", \"¥\", 1],    [\"ü\", \"ü\", \"ü\", 1],\n        [\"•\", \"•\", \"•\", 1],    [\"|\", \"|\", \"|\", 1.5]\n    ],\n    \"special_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"“\", \"“\", \"“\", 1],    [\"`\", \"`\", \"`\", 1],\n        [\"«\", \"«\", \"«\", 1],    [\"»\", \"»\", \"»\", 1],    [\"#\", \"#\", \"#\", 1],\n        [\"%\", \"%\", \"%\", 1],    [\"^\", \"^\", \"^\", 1],    [\"°\", \"°\", \"°\", 1],\n        [\"&\", \"&\", \"&\", 1],    [\"ö\", \"ö\", \"ö\", 1],    [\"ä\", \"ä\", \"ä\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"special_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"+\", \"+\", \"+\", 1],  [\"=\", \"=\", \"=\", 1],\n        [\"<\", \"<\", \"<\", 1],    [\">\", \">\", \">\", 1],    [\"*\", \"*\", \"*\", 1],\n        [\"Ö\", \"Ö\", \"Ö\", 1],    [\"Ä\", \"Ä\", \"Ä\", 1],    [\"Ü\", \"Ü\", \"Ü\", 1],\n        [\":\", \":\", \":\", 1],    [\"_\", \"_\", \"_\", 1],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"special_5\": [\n        [\"#+=\", null, \"special\", 2.5], [\" \", \" \", \"spacebar\", 11], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ]\n}\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/data/keyboards/qwerty.json",
    "content": "{\n    \"title\": \"Qwerty\",\n    \"description\": \"A classical US Keyboard\",\n\t\"cols\": 15,\n    \"rows\": 5,\n    \"normal_1\": [\n        [\"`\", \"`\", \"`\", 1],    [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],\n        [\"3\", \"3\", \"3\", 1],    [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],\n        [\"6\", \"6\", \"6\", 1],    [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],\n        [\"9\", \"9\", \"9\", 1],    [\"0\", \"0\", \"0\", 1],    [\"-\", \"-\", \"-\", 1],\n        [\"=\", \"=\", \"=\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"normal_2\" : [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"q\", \"q\", \"q\", 1],    [\"w\", \"w\", \"w\", 1],\n        [\"e\", \"e\", \"e\", 1],    [\"r\", \"r\", \"r\", 1],    [\"t\", \"t\", \"t\", 1],\n        [\"y\", \"y\", \"y\", 1],    [\"u\", \"u\", \"u\", 1],    [\"i\", \"i\", \"i\", 1],\n        [\"o\", \"o\", \"o\", 1],    [\"p\", \"p\", \"p\", 1],    [\"[\", \"[\", \"[\", 1],\n        [\"]\", \"]\", \"j\", 1],    [\"\\\\\", \"\\\\\", \"\\\\\", 1]\n    ],\n    \"normal_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"a\", \"a\", \"a\", 1],    [\"s\", \"s\", \"s\", 1],\n        [\"d\", \"d\", \"d\", 1],    [\"f\", \"f\", \"f\", 1],    [\"g\", \"g\", \"g\", 1],\n        [\"h\", \"h\", \"h\", 1],    [\"j\", \"j\", \"j\", 1],    [\"k\", \"k\", \"k\", 1],\n        [\"l\", \"l\", \"l\", 1],    [\":\", \":\", \":\", 1],    [\"'\", \"'\", \"'\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"normal_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"z\", \"z\", null, 1],    [\"x\", \"x\", \"x\", 1],\n        [\"c\", \"c\", \"c\", 1],    [\"v\", \"v\", \"v\", 1],    [\"b\", \"b\", \"b\", 1],\n        [\"n\", \"n\", \"n\", 1],    [\"m\", \"m\", \"m\", 1],    [\",\", \",\", \",\", 1],\n        [\".\", \".\", \".\", 1],    [\"/\", \"/\", \"/\", 1],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"normal_5\": [\n        [\" \", \" \", \"spacebar\", 12], [\"\\u2b12\", null, \"layout\", 1.5], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ],\n    \"shift_1\": [\n        [\"~\", \"~\", \"~\", 1],    [\"!\", \"!\", \"!\", 1],    [\"@\", \"@\", \"@\", 1],\n        [\"#\", \"#\", \"#\", 1],    [\"$\", \"$\", \"$\", 1],    [\"%\", \"%\", \"%\", 1],\n        [\"^\", \"^\", null, 1],   [\"&\", \"&\", \"&\", 1],    [\"*\", \"*\", \"*\", 1],\n        [\"(\", \"(\", \"(\", 1],    [\")\", \")\", \")\", 1],    [\"_\", \"_\", \"_\", 1],\n        [\"+\", \"+\", \"+\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"shift_2\": [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"Q\", \"Q\", null, 1],    [\"W\", \"W\", null, 1],\n        [\"E\", \"E\", \"e\", 1],    [\"R\", \"R\", \"r\", 1],    [\"T\", \"T\", \"t\", 1],\n        [\"Y\", \"Y\", \"y\", 1],    [\"U\", \"U\", \"u\", 1],    [\"I\", \"I\", \"i\", 1],\n        [\"O\", \"O\", \"o\", 1],    [\"P\", \"P\", \"p\", 1],    [\"{\", \"{\", \"{\", 1],\n        [\"}\", \"}\", \"}\", 1],    [\"|\", \"|\", \"|\", 1.5]\n    ],\n    \"shift_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"A\", \"A\", \"a\", 1],    [\"S\", \"S\", \"s\", 1],\n        [\"D\", \"D\", \"d\", 1],    [\"F\", \"F\", \"f\", 1],    [\"G\", \"G\", \"g\", 1],\n        [\"H\", \"H\", \"h\", 1],    [\"J\", \"J\", \"j\", 1],    [\"K\", \"K\", \"k\", 1],\n        [\"L\", \"L\", \"l\", 1],    [\";\", \";\", \";\", 1],    [\"\\\"\", \"\\\"\", \"\\\"\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"shift_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"Z\", \"Z\", \"z\", 1],    [\"X\", \"X\", \"x\", 1],\n        [\"C\", \"C\", \"c\", 1],    [\"V\", \"V\", \"v\", 1],    [\"B\", \"B\", \"b\", 1],\n        [\"N\", \"N\", \"n\", 1],    [\"M\", \"M\", \"m\", 1],    [\"<\", \"<\", \"<\", 1],\n        [\">\", \">\", \">\", 1],    [\"?\", \"?\", \"?\", 1.5],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"shift_5\": [\n        [\" \", \" \", \"spacebar\", 12], [\"\\u2b12\", null, \"layout\", 1.5], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ]\n}\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/data/keyboards/qwertz.json",
    "content": "{\n    \"title\": \"Qwerty\",\n    \"description\": \"A german Keyboard\",\n\t\"cols\": 15,\n    \"rows\": 5,\n    \"normal_1\": [\n        [\"!\", \"!\", \"!\", 1],    [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],\n        [\"3\", \"3\", \"3\", 1],    [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],\n        [\"6\", \"6\", \"6\", 1],    [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],\n        [\"9\", \"9\", \"9\", 1],    [\"0\", \"0\", \"0\", 1],    [\"ß\", \"ß\", \"ß\", 1],\n        [\"?\", \"?\", \"?\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"normal_2\" : [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"q\", \"q\", \"q\", 1],    [\"w\", \"w\", \"w\", 1],\n        [\"e\", \"e\", \"e\", 1],    [\"r\", \"r\", \"r\", 1],    [\"t\", \"t\", \"t\", 1],\n        [\"z\", \"z\", \"z\", 1],    [\"u\", \"u\", \"u\", 1],    [\"i\", \"i\", \"i\", 1],\n        [\"o\", \"o\", \"o\", 1],    [\"p\", \"p\", \"p\", 1],    [\"ü\", \"ü\", \"ü\", 1],\n        [\":\", \":\", \":\", 1],    [\"/\", \"/\", \"/\", 1]\n    ],\n    \"normal_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"a\", \"a\", \"a\", 1],    [\"s\", \"s\", \"s\", 1],\n        [\"d\", \"d\", \"d\", 1],    [\"f\", \"f\", \"f\", 1],    [\"g\", \"g\", \"g\", 1],\n        [\"h\", \"h\", \"h\", 1],    [\"j\", \"j\", \"j\", 1],    [\"k\", \"k\", \"k\", 1],\n        [\"l\", \"l\", \"l\", 1],    [\"ö\", \"ö\", \"ö\", 1],    [\"ä\", \"ä\", \"ä\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"normal_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"y\", \"y\", null, 1],    [\"x\", \"x\", \"x\", 1],\n        [\"c\", \"c\", \"c\", 1],    [\"v\", \"v\", \"v\", 1],    [\"b\", \"b\", \"b\", 1],\n        [\"n\", \"n\", \"n\", 1],    [\"m\", \"m\", \"m\", 1],    [\",\", \",\", \",\", 1],\n        [\".\", \".\", \".\", 1],    [\"-\", \"-\", \"-\", 1],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"normal_5\": [\n        [\" \", \" \", \"spacebar\", 12], [\"\\u2b12\", null, \"layout\", 1.5], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ],\n    \"shift_1\": [\n        [\"\\\"\", \"\\\"\", \"\\\"\", 1],    [\"+\", \"+\", \"+\", 1],    [\"@\", \"@\", \"@\", 1],\n        [\"#\", \"#\", \"#\", 1],    [\"$\", \"$\", \"$\", 1],    [\"€\", \"€\", \"€\", 1],\n        [\"%\", \"%\", \"%\", 1],   [\"&\", \"&\", \"&\", 1],    [\"*\", \"*\", \"*\", 1],\n        [\"(\", \"(\", \"(\", 1],    [\")\", \")\", \")\", 1],    [\"<\", \"<\", \"<\", 1],\n        [\">\", \">\", \">\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n    ],\n    \"shift_2\": [\n        [\"\\u21B9\", \"\\t\", \"tab\", 1.5],  [\"Q\", \"Q\", null, 1],    [\"W\", \"W\", null, 1],\n        [\"E\", \"E\", \"e\", 1],    [\"R\", \"R\", \"r\", 1],    [\"T\", \"T\", \"t\", 1],\n        [\"Z\", \"Z\", \"z\", 1],    [\"U\", \"U\", \"u\", 1],    [\"I\", \"I\", \"i\", 1],\n        [\"O\", \"O\", \"o\", 1],    [\"P\", \"P\", \"p\", 1],    [\"{\", \"{\", \"{\", 1],\n        [\"}\", \"}\", \"}\", 1],    [\"|\", \"|\", \"|\", 1.5]\n    ],\n    \"shift_3\": [\n        [\"\\u21ea\", null, \"capslock\", 1.8],  [\"A\", \"A\", \"a\", 1],    [\"S\", \"S\", \"s\", 1],\n        [\"D\", \"D\", \"d\", 1],    [\"F\", \"F\", \"f\", 1],    [\"G\", \"G\", \"g\", 1],\n        [\"H\", \"H\", \"h\", 1],    [\"J\", \"J\", \"j\", 1],    [\"K\", \"K\", \"k\", 1],\n        [\"L\", \"L\", \"l\", 1],    [\"=\", \"=\", \"=\", 1],    [\"°\", \"°\", \"°\", 1],\n        [\"\\u23ce\", null, \"enter\", 2.2]\n    ],\n    \"shift_4\": [\n        [\"\\u21e7\", null, \"shift\", 2.5],  [\"Y\", \"Y\", \"y\", 1],    [\"X\", \"X\", \"x\", 1],\n        [\"C\", \"C\", \"c\", 1],    [\"V\", \"V\", \"v\", 1],    [\"B\", \"B\", \"b\", 1],\n        [\"N\", \"N\", \"n\", 1],    [\"M\", \"M\", \"m\", 1],    [\";\", \";\", \";\", 1],\n        [\":\", \":\", \":\", 1],    [\"_\", \"_\", \"_\", 1.5],    [\"\\u21e7\", null, \"shift\", 2.5]\n    ],\n    \"shift_5\": [\n        [\" \", \" \", \"spacebar\", 12], [\"\\u2b12\", null, \"layout\", 1.5], [\"\\u2a2f\", null, \"escape\", 1.5]\n    ]\n}\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/data/settings_kivy.json",
    "content": "[\n\t{\n\t\t\"type\": \"title\",\n\t\t\"title\": \"Windows\"\n\t},\n\t{\n\t\t\"type\": \"bool\",\n\t\t\"title\": \"Fullscreen\",\n\t\t\"desc\": \"Set the window in windowed or fullscreen\",\n\t\t\"section\": \"graphics\",\n\t\t\"key\": \"fullscreen\",\n\t\t\"values\": [\"0\", \"auto\"]\n\t},\n\t{\n\t\t\"type\": \"numeric\",\n\t\t\"title\": \"FPS Limit\",\n\t\t\"desc\": \"Maximum FPS limit if set, 0 for unlimited\",\n\t\t\"section\": \"graphics\",\n\t\t\"key\": \"maxfps\"\n\t},\n\t{\n\t\t\"type\": \"bool\",\n\t\t\"title\": \"Mouse cursor\",\n\t\t\"desc\": \"Show/hide the mouse cursor on the window\",\n\t\t\"section\": \"graphics\",\n\t\t\"key\": \"show_cursor\"\n\t},\n    {\n        \"type\": \"options\",\n        \"title\": \"Rotation\",\n        \"desc\": \"Rotation of the window\",\n        \"section\": \"graphics\",\n        \"key\": \"rotation\",\n        \"options\": [\"0\", \"90\", \"180\", \"270\"]\n    },\n\n\t{\n\t\t\"type\": \"title\",\n\t\t\"title\": \"Logging\"\n\t},\n\t{\n\t\t\"type\": \"bool\",\n\t\t\"title\": \"File logging\",\n\t\t\"desc\": \"If activated, the logging will be stored in a file\",\n\t\t\"section\": \"kivy\",\n\t\t\"key\": \"log_enable\"\n\t},\n\t{\n\t\t\"type\": \"options\",\n\t\t\"title\": \"Log level\",\n\t\t\"desc\": \"Level of logging information\",\n\t\t\"section\": \"kivy\",\n\t\t\"key\": \"log_level\",\n\t\t\"options\": [\"trace\", \"debug\", \"info\", \"warning\", \"error\", \"critical\"]\n\t},\n\n\t{\n\t\t\"type\": \"title\",\n\t\t\"title\": \"Keyboard\"\n\t},\n\t{\n\t\t\"type\": \"options\",\n\t\t\"title\": \"Keyboard mode\",\n\t\t\"desc\": \"Activate the usage of Kivy Virtual Keyboard\",\n\t\t\"section\": \"kivy\",\n\t\t\"key\": \"keyboard_mode\",\n\t\t\"options\": [\"system\", \"dock\", \"multi\", \"systemanddock\", \"systemandmulti\"]\n\t},\n\t{\n\t\t\"type\": \"options\",\n\t\t\"title\": \"Keyboard layout\",\n\t\t\"desc\": \"Select a layout for virtual keyboard\",\n\t\t\"section\": \"kivy\",\n\t\t\"key\": \"keyboard_layout\",\n\t\t\"options\": [\"qwerty\", \"azerty\", \"qwertz\", \"de_CH\", \"fr_CH\", \"en_US\"]\n\t},\n\n\t{\n\t\t\"type\": \"title\",\n\t\t\"title\": \"Input post-processing\"\n\t},\n\t{\n\t\t\"type\": \"numeric\",\n\t\t\"title\": \"Double tap distance\",\n\t\t\"desc\": \"Radius in pixels within a double tap is detected\",\n\t\t\"section\": \"postproc\",\n\t\t\"key\": \"double_tap_distance\"\n\t},\n\t{\n\t\t\"type\": \"numeric\",\n\t\t\"title\": \"Double tap time\",\n\t\t\"desc\": \"Time in milliseconds during a double tap is allowed\",\n\t\t\"section\": \"postproc\",\n\t\t\"key\": \"double_tap_time\"\n\t},\n\t{\n\t\t\"type\": \"numeric\",\n\t\t\"title\": \"Retain distance\",\n\t\t\"desc\": \"Maximum distance to retain the touch\",\n\t\t\"section\": \"postproc\",\n\t\t\"key\": \"retain_distance\"\n\t},\n\t{\n\t\t\"type\": \"numeric\",\n\t\t\"title\": \"Retain time\",\n\t\t\"desc\": \"Time in milliseconds during the touch will be retain\",\n\t\t\"section\": \"postproc\",\n\t\t\"key\": \"retain_distance\"\n\t},\n\t{\n\t\t\"type\": \"numeric\",\n\t\t\"title\": \"Jitter distance\",\n\t\t\"desc\": \"Radius in pixels within the touch moves will be ignored\",\n\t\t\"section\": \"postproc\",\n\t\t\"key\": \"jitter_distance\"\n\t}\n]\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/data/style.kv",
    "content": "#:kivy 1.0\n\n<Label>:\n    canvas:\n        Color:\n            rgba: self.disabled_color if self.disabled else (self.color if not self.markup else (1, 1, 1, 1))\n        Rectangle:\n            texture: self.texture\n            size: self.texture_size\n            pos: int(self.center_x - self.texture_size[0] / 2.), int(self.center_y - self.texture_size[1] / 2.)\n\n<-Button,-ToggleButton>:\n    state_image: self.background_normal if self.state == 'normal' else self.background_down\n    disabled_image: self.background_disabled_normal if self.state == 'normal' else self.background_disabled_down\n    canvas:\n        Color:\n            rgba: self.background_color\n        BorderImage:\n            border: self.border\n            pos: self.pos\n            size: self.size\n            source: self.disabled_image if self.disabled else self.state_image\n        Color:\n            rgba: self.disabled_color if self.disabled else self.color\n        Rectangle:\n            texture: self.texture\n            size: self.texture_size\n            pos: int(self.center_x - self.texture_size[0] / 2.), int(self.center_y - self.texture_size[1] / 2.)\n\n<BubbleContent>\n    opacity: .7 if self.disabled else 1\n    rows: 1\n    canvas:\n        Color:\n            rgba: self.parent.background_color if self.parent else (1, 1, 1, 1)\n        BorderImage:\n            border: self.parent.border if self.parent else (16, 16, 16, 16)\n            texture: root.parent._bk_img.texture if root.parent else None\n            size: self.size\n            pos: self.pos\n\n<BubbleButton>:\n    background_normal: 'atlas://data/images/defaulttheme/bubble_btn'\n    background_down: 'atlas://data/images/defaulttheme/bubble_btn_pressed'\n    background_disabled_normal: 'atlas://data/images/defaulttheme/bubble_btn'\n    background_disabled_down: 'atlas://data/images/defaulttheme/bubble_btn_pressed'\n    border: (0, 0, 0, 0)\n\n<Slider>:\n    canvas:\n        Color:\n            rgb: 1, 1, 1\n        BorderImage:\n            border: (0, 18, 0, 18) if self.orientation == 'horizontal' else (18, 0, 18, 0)\n            pos: (self.x + self.padding, self.center_y - sp(18)) if self.orientation == 'horizontal' else (self.center_x - 18, self.y + self.padding)\n            size: (self.width - self.padding * 2, sp(36)) if self.orientation == 'horizontal' else (sp(36), self.height - self.padding * 2)\n            source: 'atlas://data/images/defaulttheme/slider{}_background{}'.format(self.orientation[0], '_disabled' if self.disabled else '')\n        Rectangle:\n            pos: (self.value_pos[0] - sp(16), self.center_y - sp(17)) if self.orientation == 'horizontal' else (self.center_x - (16), self.value_pos[1] - sp(16))\n            size: (sp(32), sp(32))\n            source: 'atlas://data/images/defaulttheme/slider_cursor{}'.format('_disabled' if self.disabled else '')\n\n<ProgressBar>:\n    canvas:\n        Color:\n            rgb: 1, 1, 1\n        BorderImage:\n            border: (12, 12, 12, 12)\n            pos: self.x, self.center_y - 12\n            size: self.width, 24\n            source: 'atlas://data/images/defaulttheme/progressbar_background'\n        BorderImage:\n            border: [int(min(self.width * (self.value / float(self.max)) if self.max else 0, 12))] * 4\n            pos: self.x, self.center_y - 12\n            size: self.width * (self.value / float(self.max)) if self.max else 0, 24\n            source: 'atlas://data/images/defaulttheme/progressbar'\n\n<SplitterStrip>:\n    border: self.parent.border if self.parent else (3, 3, 3, 3)\n    horizontal: '_h' if self.parent and self.parent.sizable_from[0] in  ('t', 'b') else ''\n    background_normal: 'atlas://data/images/defaulttheme/splitter{}{}'.format('_disabled' if self.disabled else '', self.horizontal)\n    background_down: 'atlas://data/images/defaulttheme/splitter_down{}{}'.format('_disabled' if self.disabled else '', self.horizontal)\n    Image:\n        pos: root.pos\n        size: root.size\n        allow_stretch: True\n        source: 'atlas://data/images/defaulttheme/splitter_grip' + root.horizontal\n\n<Scatter>:\n    canvas.before:\n        PushMatrix\n        MatrixInstruction:\n            matrix: self.transform\n    canvas.after:\n        PopMatrix\n\n\n<RelativeLayout>:\n    canvas.before:\n        PushMatrix\n        Translate:\n            xy: self.pos\n    canvas.after:\n        PopMatrix\n\n<Image,AsyncImage>:\n    canvas:\n        Color:\n            rgba: self.color\n        Rectangle:\n            texture: self.texture\n            size: self.norm_image_size\n            pos: self.center_x - self.norm_image_size[0] / 2., self.center_y - self.norm_image_size[1] / 2.\n\n<EffectWidget>:\n    canvas.before:\n        Translate:\n            xy: -self.x, -self.y\n    canvas:\n        Color:\n            rgba: 1, 1, 1, 1\n        Rectangle:\n            texture: self.texture\n            pos: self.pos\n            size: self.size\n\n<TabbedPanelContent>\n    rows: 1\n    padding: 3\n    canvas:\n        Color:\n            rgba: self.parent.background_color if self.parent else (1, 1, 1, 1)\n        BorderImage:\n            border: self.parent.border if self.parent else (16, 16, 16, 16)\n            source: (root.parent.background_disabled_image if self.disabled else root.parent.background_image) if root.parent else None\n            size: self.size\n            pos: self.pos\n\n<TabbedPanelStrip>\n    rows: 1\n\n<StripLayout>\n    padding: '2dp', '2dp', '2dp', '2dp'\n    canvas.before:\n        BorderImage:\n            pos: self.pos\n            size: self.size\n            border: root.border\n            source: root.background_image\n\n<TabbedPanelHeader>:\n    halign: 'center'\n    valign: 'middle'\n    background_normal: 'atlas://data/images/defaulttheme/tab_btn'\n    background_disabled_normal: 'atlas://data/images/defaulttheme/tab_btn_disabled'\n    background_down: 'atlas://data/images/defaulttheme/tab_btn_pressed'\n    background_disabled_down: 'atlas://data/images/defaulttheme/tab_btn_pressed'\n    border: (8, 8, 8, 8)\n    font_size: '15sp'\n\n<Selector>\n    allow_stretch: True\n\n<TextInput>:\n    canvas.before:\n        Color:\n            rgba: self.background_color\n        BorderImage:\n            border: self.border\n            pos: self.pos\n            size: self.size\n            source: (self.background_disabled_active if self.disabled else self.background_active) if self.focus else (self.background_disabled_normal if self.disabled else self.background_normal)\n        Color:\n            rgba: (self.cursor_color if self.focus and not self.cursor_blink else (0, 0, 0, 0))\n        Rectangle:\n            pos: [int(x) for x in self.cursor_pos]\n            size: 1, -self.line_height\n        Color:\n            rgba: self.disabled_foreground_color if self.disabled else (self.hint_text_color if not self.text and not self.focus else self.foreground_color)\n\n<TextInputCutCopyPaste>:\n    but_cut: cut.__self__\n    but_copy: copy.__self__\n    but_paste: paste.__self__\n    but_selectall: selectall.__self__\n\n    size_hint: None, None\n    size: '150sp', '50sp'\n    BubbleButton:\n        id: cut\n        text: 'Cut'\n        on_release: root.do('cut')\n    BubbleButton:\n        id: copy\n        text: 'Copy'\n        on_release: root.do('copy')\n    BubbleButton:\n        id: paste\n        text: 'Paste'\n        on_release: root.do('paste')\n    BubbleButton:\n        id: selectall\n        text: 'Select All'\n        on_release: root.do('selectall')\n\n<CodeInput>:\n    font_name: 'data/fonts/DroidSansMono.ttf'\n\n\n<TreeViewNode>:\n    canvas.before:\n        Color:\n            rgba: self.color_selected if self.is_selected else self.odd_color if self.odd else self.even_color\n        Rectangle:\n            pos: [self.parent.x, self.y] if self.parent else [0, 0]\n            size: [self.parent.width, self.height] if self.parent else [1, 1]\n        Color:\n            rgba: 1, 1, 1, int(not self.is_leaf)\n        Rectangle:\n            source: 'atlas://data/images/defaulttheme/tree_%s' % ('opened' if self.is_open else 'closed')\n            size: 16, 16\n            pos: self.x - 20, self.center_y - 8\n    canvas.after:\n        Color:\n            rgba: .5, .5, .5, .2\n        Line:\n            points: [self.parent.x, self.y, self.parent.right, self.y] if self.parent else []\n\n\n<TreeViewLabel>:\n    width: self.texture_size[0]\n    height: max(self.texture_size[1] + dp(10), dp(24))\n    text_size: self.width, None\n\n\n<StencilView>:\n    canvas.before:\n        StencilPush\n        Rectangle:\n            pos: self.pos\n            size: self.size\n        StencilUse\n\n    canvas.after:\n        StencilUnUse\n        Rectangle:\n            pos: self.pos\n            size: self.size\n        StencilPop\n\n\n<FileChooserListLayout>:\n    on_entry_added: treeview.add_node(args[1])\n    on_entries_cleared: treeview.root.nodes = []\n    on_subentry_to_entry: not args[2].locked and treeview.add_node(args[1], args[2])\n    on_remove_subentry: args[2].nodes = []\n    BoxLayout:\n        pos: root.pos\n        size: root.size\n        size_hint: None, None\n        orientation: 'vertical'\n        BoxLayout:\n            size_hint_y: None\n            height: 30\n            orientation: 'horizontal'\n            Widget:\n                # Just for spacing\n                width: 10\n                size_hint_x: None\n            Label:\n                text: 'Name'\n                text_size: self.size\n                halign: 'left'\n                bold: True\n            Label:\n                text: 'Size'\n                text_size: self.size\n                size_hint_x: None\n                halign: 'right'\n                bold: True\n            Widget:\n                # Just for spacing\n                width: 10\n                size_hint_x: None\n        ScrollView:\n            id: scrollview\n            do_scroll_x: False\n            Scatter:\n                do_rotation: False\n                do_scale: False\n                do_translation: False\n                size: treeview.size\n                size_hint_y: None\n                TreeView:\n                    id: treeview\n                    hide_root: True\n                    size_hint_y: None\n                    width: scrollview.width\n                    height: self.minimum_height\n                    on_node_expand: root.controller.entry_subselect(args[1])\n                    on_node_collapse: root.controller.close_subselection(args[1])\n\n<FileChooserListView>:\n    layout: layout\n    FileChooserListLayout:\n        id: layout\n        controller: root\n        pos: root.pos\n\n[FileListEntry@FloatLayout+TreeViewNode]:\n    locked: False\n    entries: []\n    path: ctx.path\n    # FIXME: is_selected is actually a read_only treeview property. In this\n    # case, however, we're doing this because treeview only has single-selection\n    # hardcoded in it. The fix to this would be to update treeview to allow\n    # multiple selection.\n    is_selected: self.path in ctx.controller().selection\n\n    orientation: 'horizontal'\n    size_hint_y: None\n    height: '48dp' if dp(1) > 1 else '24dp'\n    # Don't allow expansion of the ../ node\n    is_leaf: not ctx.isdir or ctx.name.endswith('..' + ctx.sep) or self.locked\n    on_touch_down: self.collide_point(*args[1].pos) and ctx.controller().entry_touched(self, args[1])\n    on_touch_up: self.collide_point(*args[1].pos) and ctx.controller().entry_released(self, args[1])\n    BoxLayout:\n        pos: root.pos\n        Label:\n            id: filename\n            text_size: self.width, None\n            halign: 'left'\n            shorten: True\n            text: ctx.name\n        Label:\n            text_size: self.width, None\n            size_hint_x: None\n            halign: 'right'\n            text: '{}'.format(ctx.get_nice_size())\n\n\n<FileChooserIconLayout>:\n    on_entry_added: stacklayout.add_widget(args[1])\n    on_entries_cleared: stacklayout.clear_widgets()\n    ScrollView:\n        id: scrollview\n        pos: root.pos\n        size: root.size\n        size_hint: None, None\n        do_scroll_x: False\n        Scatter:\n            do_rotation: False\n            do_scale: False\n            do_translation: False\n            size_hint_y: None\n            height: stacklayout.height\n            StackLayout:\n                id: stacklayout\n                width: scrollview.width\n                size_hint_y: None\n                height: self.minimum_height\n                spacing: '10dp'\n                padding: '10dp'\n\n<FileChooserIconView>:\n    layout: layout\n    FileChooserIconLayout:\n        id: layout\n        controller: root\n        pos: root.pos\n\n[FileIconEntry@Widget]:\n    locked: False\n    path: ctx.path\n    selected: self.path in ctx.controller().selection\n    size_hint: None, None\n\n    on_touch_down: self.collide_point(*args[1].pos) and ctx.controller().entry_touched(self, args[1])\n    on_touch_up: self.collide_point(*args[1].pos) and ctx.controller().entry_released(self, args[1])\n    size: '100dp', '100dp'\n\n    canvas:\n        Color:\n            rgba: 1, 1, 1, 1 if self.selected else 0\n        BorderImage:\n            border: 8, 8, 8, 8\n            pos: root.pos\n            size: root.size\n            source: 'atlas://data/images/defaulttheme/filechooser_selected'\n\n    Image:\n        size: '48dp', '48dp'\n        source: 'atlas://data/images/defaulttheme/filechooser_%s' % ('folder' if ctx.isdir else 'file')\n        pos: root.x + dp(24), root.y + dp(40)\n    Label:\n        text: ctx.name\n        text_size: (root.width, self.height)\n        halign: 'center'\n        shorten: True\n        size: '100dp', '16dp'\n        pos: root.x, root.y + dp(16)\n\n    Label:\n        text: '{}'.format(ctx.get_nice_size())\n        font_size: '11sp'\n        color: .8, .8, .8, 1\n        size: '100dp', '16sp'\n        pos: root.pos\n        halign: 'center'\n\n<FileChooserProgress>:\n    pos_hint: {'x': 0, 'y': 0}\n    canvas:\n        Color:\n            rgba: 0, 0, 0, .8\n        Rectangle:\n            pos: self.pos\n            size: self.size\n    Label:\n        pos_hint: {'x': .2, 'y': .6}\n        size_hint: .6, .2\n        text: 'Opening %s' % root.path\n    FloatLayout:\n        pos_hint: {'x': .2, 'y': .4}\n        size_hint: .6, .2\n        ProgressBar:\n            id: pb\n            pos_hint: {'x': 0, 'center_y': .5}\n            max: root.total\n            value: root.index\n        Label:\n            pos_hint: {'x': 0}\n            text: '%d / %d' % (root.index, root.total)\n            size_hint_y: None\n            height: self.texture_size[1]\n            y: pb.center_y - self.height - 8\n            font_size: '13sp'\n            color: (.8, .8, .8, .8)\n\n    AnchorLayout:\n        pos_hint: {'x': .2, 'y': .2}\n        size_hint: .6, .2\n\n        Button:\n            text: 'Cancel'\n            size_hint: None, None\n            size: 150, 44\n            on_release: root.cancel()\n\n\n\n# Switch widget\n<Switch>:\n    active_norm_pos: max(0., min(1., (int(self.active) + self.touch_distance / sp(41))))\n    canvas:\n        Color:\n            rgb: 1, 1, 1\n        Rectangle:\n            source: 'atlas://data/images/defaulttheme/switch-background{}'.format('_disabled' if self.disabled else '')\n            size: sp(83), sp(32)\n            pos: int(self.center_x - sp(41)), int(self.center_y - sp(16))\n        Rectangle:\n            source: 'atlas://data/images/defaulttheme/switch-button{}'.format('_disabled' if self.disabled else '')\n            size: sp(43), sp(32)\n            pos: int(self.center_x - sp(41) + self.active_norm_pos * sp(41)), int(self.center_y - sp(16))\n\n\n# ModalView widget\n<ModalView>:\n    canvas:\n        Color:\n            rgba: root.background_color[:3] + [root.background_color[-1] * self._anim_alpha]\n        Rectangle:\n            size: self._window.size if self._window else (0, 0)\n\n        Color:\n            rgb: 1, 1, 1\n        BorderImage:\n            source: root.background\n            border: root.border\n            pos: self.pos\n            size: self.size\n\n\n# Popup widget\n<Popup>:\n    _container: container\n    GridLayout:\n        padding: '12dp'\n        cols: 1\n        size_hint: None, None\n        pos: root.pos\n        size: root.size\n\n        Label:\n            text: root.title\n            color: root.title_color\n            size_hint_y: None\n            height: self.texture_size[1] + dp(16)\n            text_size: self.width - dp(16), None\n            font_size: root.title_size\n            font_name: root.title_font\n            halign: root.title_align\n\n        Widget:\n            size_hint_y: None\n            height: dp(4)\n            canvas:\n                Color:\n                    rgba: root.separator_color\n                Rectangle:\n                    pos: self.x, self.y + root.separator_height / 2.\n                    size: self.width, root.separator_height\n\n        BoxLayout:\n            id: container\n\n# =============================================================================\n# Spinner widget\n# =============================================================================\n\n<SpinnerOption>:\n    size_hint_y: None\n    height: '48dp'\n\n<Spinner>:\n    background_normal: 'atlas://data/images/defaulttheme/spinner'\n    background_disabled_normal: 'atlas://data/images/defaulttheme/spinner_disabled'\n    background_down: 'atlas://data/images/defaulttheme/spinner_pressed'\n\n# =============================================================================\n# ActionBar widget\n# =============================================================================\n\n<ActionBar>:\n    height: '48dp'\n    size_hint_y: None\n    spacing: '4dp'\n    canvas:\n        Color:\n            rgba: self.background_color\n        BorderImage:\n            border: root.border\n            pos: self.pos\n            size: self.size\n            source: self.background_image\n\n<ActionView>:\n    orientation: 'horizontal'\n    canvas:\n        Color:\n            rgba: self.background_color\n        BorderImage:\n            pos: self.pos\n            size: self.size\n            source: self.background_image\n\n<ActionSeparator>:\n    size_hint_x: None\n    minimum_width: '2sp'\n    width: self.minimum_width\n    canvas:\n        Rectangle:\n            pos: self.x, self.y + sp(4)\n            size: self.width, self.height - sp(8)\n            source: self.background_image\n\n<ActionButton,ActionToggleButton>:\n    background_normal: 'atlas://data/images/defaulttheme/' + ('action_bar' if self.inside_group else 'action_item')\n    background_down: 'atlas://data/images/defaulttheme/action_item_down'\n    size_hint_x: None if not root.inside_group else 1\n    width: [dp(48) if (root.icon and not root.inside_group) else max(dp(48), (self.texture_size[0] + dp(32))), self.size_hint_x][0]\n    color: self.color[:3] + [0 if (root.icon and not root.inside_group) else 1]\n\n    Image:\n        allow_stretch: True\n        opacity: 1 if (root.icon and not root.inside_group) else 0\n        source: root.icon\n        mipmap: root.mipmap\n        pos: root.x + dp(4), root.y + dp(4)\n        size: root.width - dp(8), root.height - sp(8)\n\n<ActionGroup>:\n    size_hint_x: None\n    width: self.texture_size[0] + dp(32)\n\n<ActionCheck>:\n    background_normal: 'atlas://data/images/defaulttheme/action_bar' if self.inside_group else 'atlas://data/images/defaulttheme/action_item'\n\n<ActionPreviousImage@Image>:\n    temp_width: 0\n    temp_height: 0\n\n<ActionPrevious>:\n    size_hint_x: 1\n    minimum_width: '100sp'\n    important: True\n    BoxLayout:\n        orientation: 'horizontal'\n        pos: root.pos\n        size: root.size\n        ActionPreviousImage:\n            id: prev_icon_image\n            source: root.previous_image\n            opacity: 1 if root.with_previous else 0\n            allow_stretch: True\n            size_hint_x: None\n            temp_width: root.previous_image_width or dp(prev_icon_image.texture_size[0])\n            temp_height: root.previous_image_height or dp(prev_icon_image.texture_size[1])\n            width:\n                (self.temp_width if self.temp_height <= self.height else \\\n                self.temp_width * (self.height / self.temp_height)) \\\n                if self.texture else dp(8)\n            mipmap: root.mipmap\n        ActionPreviousImage:\n            id: app_icon_image\n            source: root.app_icon\n            allow_stretch: True\n            size_hint_x: None\n            temp_width: root.app_icon_width or dp(app_icon_image.texture_size[0])\n            temp_height: root.app_icon_height or dp(app_icon_image.texture_size[1])\n            width:\n                (self.temp_width if self.temp_height <= self.height else \\\n                self.temp_width * (self.height / self.temp_height)) \\\n                if self.texture else dp(8)\n            mipmap: root.mipmap\n        Widget:\n            size_hint_x: None\n            width: '5sp'\n        Label:\n            text: root.title\n            text_size: self.size\n            color: root.color\n            shorten: True\n            halign: 'left'\n            valign: 'middle'\n\n<ActionGroup>:\n    background_normal: 'atlas://data/images/defaulttheme/action_group'\n    background_down: 'atlas://data/images/defaulttheme/action_group_down'\n    background_disabled_normal: 'atlas://data/images/defaulttheme/action_group_disabled'\n    border: 30, 30, 3, 3\n    ActionSeparator:\n        pos: root.pos\n        size: root.separator_width, root.height\n        opacity: 1 if root.use_separator else 0\n        background_image: root.separator_image if root.use_separator else 'action_view'\n\n<ActionOverflow>:\n    border: 3, 3, 3, 3\n    background_normal: 'atlas://data/images/defaulttheme/action_item'\n    background_down: 'atlas://data/images/defaulttheme/action_item_down'\n    background_disabled_normal: 'atlas://data/images/defaulttheme/button_disabled'\n    size_hint_x: None\n    minimum_width: '48sp'\n    width: self.texture_size[0] if self.texture else self.minimum_width\n    canvas.after:\n        Color:\n            rgb: 1, 1, 1\n        Rectangle:\n            pos: root.center_x - sp(16), root.center_y - sp(16)\n            size: sp(32), sp(32)\n            source: root.overflow_image\n\n<ActionDropDown>:\n    auto_width: False\n\n\n# =============================================================================\n# Accordion widget\n# =============================================================================\n\n[AccordionItemTitle@Label]:\n    text: ctx.title\n    normal_background: ctx.item.background_normal if ctx.item.collapse else ctx.item.background_selected\n    disabled_background: ctx.item.background_disabled_normal if ctx.item.collapse else ctx.item.background_disabled_selected\n    canvas.before:\n        Color:\n            rgba: self.disabled_color if self.disabled else self.color\n        BorderImage:\n            source: self.disabled_background if self.disabled else self.normal_background\n            pos: self.pos\n            size: self.size\n        PushMatrix\n        Translate:\n            xy: self.center_x, self.center_y\n        Rotate:\n            angle: 90 if ctx.item.orientation == 'horizontal' else 0\n            axis: 0, 0, 1\n        Translate:\n            xy: -self.center_x, -self.center_y\n    canvas.after:\n        PopMatrix\n\n\n<AccordionItem>:\n    container: container\n    container_title: container_title\n\n    BoxLayout:\n        orientation: root.orientation\n        pos: root.pos\n        BoxLayout:\n            size_hint_x: None if root.orientation == 'horizontal' else 1\n            size_hint_y: None if root.orientation == 'vertical' else 1\n            width: root.min_space if root.orientation == 'horizontal' else 100\n            height: root.min_space if root.orientation == 'vertical' else 100\n            id: container_title\n\n        StencilView:\n            id: sv\n\n            BoxLayout:\n                id: container\n                pos: sv.pos\n                size: root.content_size\n\n\n# =============================================================================\n# Settings\n# =============================================================================\n\n<SettingSpacer>:\n    size_hint_y: None\n    height: 5\n    canvas:\n        Color:\n            rgb: .2, .2, .2\n        Rectangle:\n            pos: self.x, self.center_y\n            size: self.width, 1\n\n<SettingItem>:\n    size_hint: .25, None\n    height: labellayout.texture_size[1] + dp(10)\n    content: content\n    canvas:\n        Color:\n            rgba: 47 / 255., 167 / 255., 212 / 255., self.selected_alpha\n        Rectangle:\n            pos: self.x, self.y + 1\n            size: self.size\n        Color:\n            rgb: .2, .2, .2\n        Rectangle:\n            pos: self.x, self.y - 2\n            size: self.width, 1\n\n    BoxLayout:\n        pos: root.pos\n\n        Label:\n            size_hint_x: .66\n            id: labellayout\n            markup: True\n            text: u'{0}\\n[size=13sp][color=999999]{1}[/color][/size]'.format(root.title or '', root.desc or '')\n            font_size: '15sp'\n            text_size: self.width - 32, None\n\n        BoxLayout:\n            id: content\n            size_hint_x: .33\n\n\n<SettingBoolean>:\n    Switch:\n        text: 'Boolean'\n        pos: root.pos\n        active: bool(root.values.index(root.value)) if root.value in root.values else False\n        on_active: root.value = root.values[int(args[1])]\n\n<SettingString>:\n    Label:\n        text: root.value or ''\n        pos: root.pos\n        font_size: '15sp'\n\n<SettingPath>:\n    Label:\n        text: root.value or ''\n        pos: root.pos\n        font_size: '15sp'\n\n<SettingOptions>:\n    Label:\n        text: root.value or ''\n        pos: root.pos\n        font_size: '15sp'\n\n<SettingTitle>:\n    text_size: self.width - 32, None\n    size_hint_y: None\n    height: max(dp(20), self.texture_size[1] + dp(20))\n    color: (.9, .9, .9, 1)\n    font_size: '15sp'\n    canvas:\n        Color:\n            rgba: .15, .15, .15, .5\n        Rectangle:\n            pos: self.x, self.y + 2\n            size: self.width, self.height - 2\n        Color:\n            rgb: .2, .2, .2\n        Rectangle:\n            pos: self.x, self.y - 2\n            size: self.width, 1\n\n<SettingSidebarLabel>:\n    size_hint: 1, None\n    text_size: self.width - 32, None\n    height: self.texture_size[1] + dp(20)\n    font_size: '15sp'\n    canvas.before:\n        Color:\n            rgba: 47 / 255., 167 / 255., 212 / 255., int(self.selected)\n        Rectangle:\n            pos: self.pos\n            size: self.size\n\n<SettingsPanel>:\n    spacing: 5\n    padding: 5\n    size_hint_y: None\n    height: self.minimum_height\n\n    Label:\n        size_hint_y: None\n        text: root.title\n        text_size: self.width - 32, None\n        height: max(50, self.texture_size[1] + 20)\n        color: (.5, .5, .5, 1)\n        font_size: '15sp'\n\n        canvas.after:\n            Color:\n                rgb: .2, .2, .2\n            Rectangle:\n                pos: self.x, self.y - 2\n                size: self.width, 1\n\n<Settings>:\n    orientation: 'horizontal'\n    canvas.before:\n        Color:\n            rgb: 0, 0, 0\n        Rectangle:\n            pos: self.pos\n            size: self.size\n\n<InterfaceWithSidebar>:\n    orientation: 'horizontal'\n    menu: menu\n    content: content\n    MenuSidebar:\n        id: menu\n    ContentPanel:\n        id: content\n        current_uid: menu.selected_uid\n\n<InterfaceWithSpinner>:\n    orientation: 'vertical'\n    menu: menu\n    content: content\n    MenuSpinner:\n        id: menu\n    ContentPanel:\n        id: content\n        current_uid: menu.selected_uid\n\n<MenuSpinner>:\n    orientation: 'horizontal'\n    size_hint_y: None\n    height: '50dp'\n    spinner: spinner\n    spinner_text: spinner.text\n    close_button: button\n    Spinner:\n        id: spinner\n    Button:\n        text: 'Close'\n        id: button\n        size_hint_x: None\n        width: min(dp(200), 0.4*root.width)\n        font_size: '15sp'\n\n\n<MenuSidebar>:\n    size_hint_x: None\n    width: '200dp'\n    buttons_layout: menu\n    close_button: button\n    GridLayout:\n        pos: root.pos\n        cols: 1\n        id: menu\n        orientation: 'vertical'\n        padding: 5\n\n        canvas.after:\n            Color:\n                rgb: .2, .2, .2\n            Rectangle:\n                pos: self.right - 1, self.y\n                size: 1, self.height\n\n    Button:\n        text: 'Close'\n        id: button\n        size_hint: None, None\n        width: root.width - dp(20)\n        height: max(50, self.texture_size[1] + dp(20))\n        pos: root.x + dp(10), root.y + dp(10)\n        font_size: '15sp'\n\n<ContentPanel>:\n    do_scroll_x: False\n    container: content\n    GridLayout:\n        id: content\n        cols: 1\n        size_hint_y: None\n        height: self.minimum_height\n\n<InterfaceWithTabbedPanel>:\n    tabbedpanel: tp\n    close_button: button\n    TabbedPanel:\n        id: tp\n        size: root.size\n        pos: root.pos\n        #do_default_tab: False\n        background_color: (0,0,0,1)\n    Button:\n        id: button\n        text: 'Close'\n        size_hint: None, None\n        height: '45dp'\n        width: min(dp(200), 0.3*root.width)\n        x: root.x + root.width - self.width\n        y: root.y + root.height - self.height\n\n\n<ScrollView>:\n    canvas.after:\n        Color:\n            rgba: self._bar_color if (self.do_scroll_y and self.viewport_size[1] > self.height) else [0, 0, 0, 0]\n        Rectangle:\n            pos: (self.right - self.bar_width - self.bar_margin) if self.bar_pos_y == 'right' else (self.x + self.bar_margin), self.y + self.height * self.vbar[0]\n            size: min(self.bar_width, self.width), self.height * self.vbar[1]\n        Color:\n            rgba: self._bar_color if (self.do_scroll_x and self.viewport_size[0] > self.width) else [0, 0, 0, 0]\n        Rectangle:\n            pos: self.x + self.width * self.hbar[0], (self.y + self.bar_margin) if self.bar_pos_x == 'bottom' else (self.top - self.bar_margin - self.bar_width)\n            size: self.width * self.hbar[1], min(self.bar_width, self.height)\n\n\n# =============================================================================\n# Video player\n# =============================================================================\n\n<VideoPlayerPreview>:\n    pos_hint: {'x': 0, 'y': 0}\n    image_overlay_play: 'atlas://data/images/defaulttheme/player-play-overlay'\n    image_loading: 'atlas://data/images/image-loading.gif'\n    Image:\n        source: root.source\n        color: (.5, .5, .5, 1)\n        pos_hint: {'x': 0, 'y': 0}\n    Image:\n        source: root.image_overlay_play if not root.click_done else root.image_loading\n        pos_hint: {'x': 0, 'y': 0}\n\n\n<VideoPlayerAnnotation>:\n    canvas.before:\n        Color:\n            rgba: self.annotation['bgcolor'] if 'bgcolor' in self.annotation else (0, 0, 0, 0.8)\n        BorderImage:\n            pos: self.pos\n            size: self.size\n            source: self.annotation['bgsource'] if 'bgsource' in self.annotation else None\n            border: self.annotation['border'] if 'border' in self.annotation else (0, 0, 0, 0)\n    size_hint: self.annotation['size_hint'] if 'size_hint' in self.annotation else (None, None)\n    size: self.annotation['size'] if 'size' in self.annotation else (self.texture_size[0] + 20, self.texture_size[1] + 20)\n    pos_hint: self.annotation['pos_hint'] if 'pos_hint' in self.annotation else {'center_x': .5, 'y': .05}\n\n<VideoPlayer>:\n    container: container\n    cols: 1\n\n    FloatLayout:\n        cols: 1\n        id: container\n\n    GridLayout:\n        rows: 1\n        size_hint_y: None\n        height: 44\n\n        VideoPlayerStop:\n            size_hint_x: None\n            video: root\n            width: 44\n            source: root.image_stop\n\n        VideoPlayerPlayPause:\n            size_hint_x: None\n            video: root\n            width: 44\n            source: root.image_pause if root.state == 'play' else root.image_play\n\n        VideoPlayerVolume:\n            video: root\n            size_hint_x: None\n            width: 44\n            source: root.image_volumehigh if root.volume > 0.8 else (root.image_volumemedium if root.volume > 0.4 else (root.image_volumelow if root.volume > 0 else root.image_volumemuted))\n\n        Widget:\n            size_hint_x: None\n            width: 5\n\n        VideoPlayerProgressBar:\n            video: root\n            max: max(root.duration, root.position, 1)\n            value: root.position\n\n        Widget:\n            size_hint_x: None\n            width: 10\n\n# =============================================================================\n# Checkbox\n# =============================================================================\n\n<CheckBox>:\n    _checkbox_state_image:\n        self.background_checkbox_down \\\n        if self.active else self.background_checkbox_normal\n    _checkbox_disabled_image:\n        self.background_checkbox_disabled_down \\\n        if self.active else self.background_checkbox_disabled_normal\n    _radio_state_image:\n        self.background_radio_down \\\n        if self.active else self.background_radio_normal\n    _radio_disabled_image:\n        self.background_radio_disabled_down \\\n        if self.active else self.background_radio_disabled_normal\n    _checkbox_image:\n        self._checkbox_disabled_image \\\n        if self.disabled else self._checkbox_state_image\n    _radio_image:\n        self._radio_disabled_image \\\n        if self.disabled else self._radio_state_image\n    canvas:\n        Color:\n            rgb: 1, 1, 1\n        Rectangle:\n            source: self._radio_image if self.group else self._checkbox_image\n            size: sp(32), sp(32)\n            pos: int(self.center_x - sp(16)), int(self.center_y - sp(16))\n\n# =============================================================================\n# Screen Manager\n# =============================================================================\n\n<ScreenManager>:\n    canvas.before:\n        StencilPush\n        Rectangle:\n            pos: self.pos\n            size: self.size\n        StencilUse\n    canvas.after:\n        StencilUnUse\n        Rectangle:\n            pos: self.pos\n            size: self.size\n        StencilPop\n\n# =============================================================================\n# Color Picker\n# =============================================================================\n<ColorPicker_Input@TextInput>\n    multiline: False\n    mroot: None\n    padding: sp(5)\n    border: 4, 9, 4, 9\n\n<ColorPicker_Label@Label>\n    mroot: None\n    size_hint_x: None\n    width: '30sp'\n    text_size: self.size\n    halign: \"center\"\n    valign: \"middle\"\n\n<ColorPicker_Selector@BoxLayout>\n    foreground_color: None\n    text: ''\n    mroot: None\n    mode: 'rgb'\n    color: 0\n    spacing: '2sp'\n    ColorPicker_Label:\n        text: root.text\n        mroot: root.mroot\n        color: root.foreground_color or (1, 1, 1, 1)\n    AnchorLayout:\n        size_hint_x: None\n        width: '50sp'\n        ColorPicker_Input:\n            mroot: root.mroot\n            text: str(int(sldr.value))\n            size_hint_y: None\n            height: '28sp'\n            on_text:\n                root.mroot._trigger_update_clr(root.mode, root.clr_idx, args[1])\n    Slider:\n        id: sldr\n        size_hint: 1, .25\n        pos_hint: {'center_y':.5}\n        range: 0, 255\n        value: root.color * 255\n        on_value:\n            root.mroot._trigger_update_clr(root.mode, root.clr_idx, args[1])\n\n<ColorPicker>:\n    foreground_color: (1, 1, 1, 1) if self.hsv[2] * wheel.a < .5 else (0, 0, 0, 1)\n    wheel: wheel\n    BoxLayout:\n        orientation: 'vertical' if root.width < root.height else 'horizontal'\n        spacing: '5sp'\n        StackLayout:\n            orientation: 'tb-lr'\n            size_hint_y: None if root.width < root.height else 1\n            height: sp(33) * 4 if root.width < root.height else self.height\n            canvas:\n                Color:\n                    rgba: root.color\n                Rectangle:\n                    size: self.size\n                    pos: self.pos\n\n            ColorPicker_Selector:\n                mroot: root\n                text: 'R'\n                clr_idx: 0\n                color: wheel.r\n                foreground_color: root.foreground_color\n                size_hint_y: None if root.width < root.height else 0.125\n                size_hint_x: .5 if root.width < root.height else 1\n                height: '33sp' if root.width < root.height else self.height\n\n            ColorPicker_Selector:\n                mroot: root\n                text: 'G'\n                clr_idx: 1\n                color: wheel.g\n                foreground_color: root.foreground_color\n                size_hint_y: None if root.width < root.height else 0.125\n                size_hint_x: .5 if root.width < root.height else 1\n                height: '33sp' if root.width < root.height else self.height\n\n            ColorPicker_Selector:\n                mroot: root\n                text: 'B'\n                clr_idx: 2\n                color: wheel.b\n                foreground_color: root.foreground_color\n                size_hint_y: None if root.width < root.height else 0.125\n                size_hint_x: .5 if root.width < root.height else 1\n                height: '33sp' if root.width < root.height else self.height\n\n            ColorPicker_Selector:\n                mroot: root\n                text: 'A'\n                clr_idx: 3\n                color: root.color[3]\n                foreground_color: root.foreground_color\n                size_hint_y: None if root.width < root.height else 0.125\n                size_hint_x: .5 if root.width < root.height else 1\n                height: '33sp' if root.width < root.height else self.height\n\n            ColorPicker_Selector:\n                mroot: root\n                mode: 'hsv'\n                text: 'H'\n                clr_idx: 0\n                color: root.hsv[0]\n                foreground_color: root.foreground_color\n                size_hint_y: None if root.width < root.height else 0.125\n                size_hint_x: .5 if root.width < root.height else 1\n                height: '33sp' if root.width < root.height else self.height\n\n            ColorPicker_Selector:\n                mroot: root\n                mode: 'hsv'\n                text: 'S'\n                clr_idx: 1\n                color: root.hsv[1]\n                foreground_color: root.foreground_color\n                size_hint_y: None if root.width < root.height else 0.125\n                size_hint_x: .5 if root.width < root.height else 1\n                height: '33sp' if root.width < root.height else self.height\n\n            ColorPicker_Selector:\n                mroot: root\n                mode: 'hsv'\n                text: 'V'\n                clr_idx: 2\n                color: root.hsv[2]\n                foreground_color: root.foreground_color\n                size_hint_y: None if root.width < root.height else 0.125\n                size_hint_x: .5 if root.width < root.height else 1\n                height: '33sp' if root.width < root.height else self.height\n\n            BoxLayout:\n                size_hint_y: None if root.width < root.height else 0.125\n                size_hint_x: .5 if root.width < root.height else 1\n                height: '33sp' if root.width < root.height else self.height\n\n                spacing: '2sp'\n                ColorPicker_Label:\n                    mroot: root\n                    text: 'X'\n                    color: root.foreground_color\n                AnchorLayout:\n                    ColorPicker_Input:\n                        size_hint_y: None\n                        height: '28sp'\n                        mroot: root\n                        text: str(root.hex_color)\n                        on_text: root._trigger_update_hex(args[1])\n\n\n        ColorWheel:\n            id: wheel\n            _origin: (self.center_x, self.center_y)\n            _radius: 0.45 * min(self.size)\n            color: root.color\n            on_color: root.color[:3] = args[1][:3]\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/effects/__init__.py",
    "content": "'''\nEffects\n=======\n\n.. versionadded:: 1.7.0\n\nEverything starts with the :class:`~kinetic.KineticEffect`, the base class for\ncomputing velocity out of a movement.\n\nThis base class is used to implement the :class:`~scroll.ScrollEffect`, a base\nclass used for our :class:`~kivy.uix.scrollview.ScrollView` widget effect.\nWe have multiple implementations:\n\n- :class:`~kivy.effects.scroll.ScrollEffect`: base class used for implementing\n  an effect. It only calculates the scrolling and the overscroll.\n- :class:`~kivy.effects.dampedscroll.DampedScrollEffect`: uses the overscroll\n  information to allow the user to drag more than expected. Once the user stops\n  the drag, the position is returned to one of the bounds.\n- :class:`~kivy.effects.opacityscroll.OpacityScrollEffect`: uses the overscroll\n  information to reduce the opacity of the scrollview widget. When the user\n  stops the drag, the opacity is set back to 1.\n\n'''\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/effects/dampedscroll.py",
    "content": "'''\nDamped scroll effect\n====================\n\n.. versionadded:: 1.7.0\n\nThis damped scroll effect will use the\n:attr:`~kivy.effects.scroll.ScrollEffect.overscroll` to calculate the scroll\nvalue, and slows going back to the upper or lower limit.\n\n'''\n\n__all__ = ('DampedScrollEffect',)\n\n\nfrom kivy.effects.scroll import ScrollEffect\nfrom kivy.properties import NumericProperty, BooleanProperty\nfrom kivy.metrics import sp\n\n\nclass DampedScrollEffect(ScrollEffect):\n    '''DampedScrollEffect class. See the module documentation for more\n    information.\n    '''\n\n    edge_damping = NumericProperty(0.25)\n    '''Edge damping.\n\n    :attr:`edge_damping` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.25\n    '''\n\n    spring_constant = NumericProperty(2.0)\n    '''Spring constant.\n\n    :attr:`spring_constant` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 2.0\n    '''\n\n    min_overscroll = NumericProperty(.5)\n    '''An overscroll less than this amount will be normalized to 0.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`min_overscroll` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to .5.\n    '''\n\n    round_value = BooleanProperty(True)\n    '''If True, when the motion stops, :attr:`value` is rounded to the nearest\n    integer.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`round_value` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n    def update_velocity(self, dt):\n        if abs(self.velocity) <= self.min_velocity and self.overscroll == 0:\n            self.velocity = 0\n            # why does this need to be rounded? For now refactored it.\n            if self.round_value:\n                self.value = round(self.value)\n            return\n\n        total_force = self.velocity * self.friction\n        if abs(self.overscroll) > self.min_overscroll:\n            total_force += self.velocity * self.edge_damping\n            total_force += self.overscroll * self.spring_constant\n        else:\n            self.overscroll = 0\n\n        stop_overscroll = ''\n        if not self.is_manual:\n            if self.overscroll > 0 and self.velocity < 0:\n                stop_overscroll = 'max'\n            elif self.overscroll < 0 and self.velocity > 0:\n                stop_overscroll = 'min'\n\n        self.velocity = self.velocity - total_force\n        if not self.is_manual:\n            self.apply_distance(self.velocity * dt)\n            if stop_overscroll == 'min' and self.value > self.min:\n                self.value = self.min\n                self.velocity = 0\n                return\n            if stop_overscroll == 'max' and self.value < self.max:\n                self.value = self.max\n                self.velocity = 0\n                return\n        self.trigger_velocity_update()\n\n    def on_value(self, *args):\n        scroll_min = self.min\n        scroll_max = self.max\n        if scroll_min > scroll_max:\n            scroll_min, scroll_max = scroll_max, scroll_min\n        if self.value < scroll_min:\n            self.overscroll = self.value - scroll_min\n        elif self.value > scroll_max:\n            self.overscroll = self.value - scroll_max\n        else:\n            self.overscroll = 0\n        self.scroll = self.value\n\n    def on_overscroll(self, *args):\n        self.trigger_velocity_update()\n\n    def apply_distance(self, distance):\n        os = abs(self.overscroll)\n        if os:\n            distance /= 1. + os / sp(200.)\n        super(DampedScrollEffect, self).apply_distance(distance)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/effects/kinetic.py",
    "content": "'''\nKinetic effect\n==============\n\n.. versionadded:: 1.7.0\n\nThe :class:`KineticEffect` is the base class that is used to compute the\nvelocity out of a movement. When the movement is finished, the effect will\ncompute the position of the movement according to the velocity, and reduce the\nvelocity with a friction. The movement stop until the velocity is 0.\n\nConceptually, the usage could be::\n\n    >>> effect = KineticEffect()\n    >>> effect.start(10)\n    >>> effect.update(15)\n    >>> effect.update(30)\n    >>> effect.stop(48)\n\nOver the time, you will start a movement of a value, update it, and stop the\nmovement. At this time, you'll get the movement value into\n:attr:`KineticEffect.value`. On the example i've typed manually, the computed\nvelocity will be::\n\n    >>> effect.velocity\n    3.1619100231163046\n\nAfter multiple clock interaction, the velocity will decrease according to\n:attr:`KineticEffect.friction`. The computed value will be stored in\n:attr:`KineticEffect.value`. The output of this `value` could be::\n\n    46.30038145219605\n    54.58302451968686\n    61.9229016256196\n    # ...\n\n'''\n\n__all__ = ('KineticEffect', )\n\n\nfrom time import time\nfrom kivy.event import EventDispatcher\nfrom kivy.properties import NumericProperty, BooleanProperty\nfrom kivy.clock import Clock\n\n\nclass KineticEffect(EventDispatcher):\n    '''Kinetic effect class. See module documentation for more information.\n    '''\n\n    velocity = NumericProperty(0)\n    '''Velocity of the movement.\n\n    :attr:`velocity` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    friction = NumericProperty(0.05)\n    '''Friction to apply on the velocity\n\n    :attr:`velocity` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.05.\n    '''\n\n    value = NumericProperty(0)\n    '''Value (during the movement and computed) of the effect.\n\n    :attr:`velocity` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    is_manual = BooleanProperty(False)\n    '''Indicate if a movement is in progress (True) or not (False).\n\n    :attr:`velocity` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    max_history = NumericProperty(5)\n    '''Save up to `max_history` movement value into the history. This is used\n    for correctly calculating the velocity according to the movement.\n\n    :attr:`max_history` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 5.\n    '''\n    min_distance = NumericProperty(.1)\n    '''The minimal distance for a movement to have nonzero velocity.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`min_distance` is :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.1.\n    '''\n\n    min_velocity = NumericProperty(.5)\n    '''Velocity below this quantity is normalized to 0. In other words,\n    any motion whose velocity falls below this number is stopped.\n\n    .. versionadded::1.8.0\n\n    :attr:`min_velocity` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.5.\n    '''\n\n    def __init__(self, **kwargs):\n        self.history = []\n        self.trigger_velocity_update = Clock.create_trigger(\n            self.update_velocity, 0)\n        super(KineticEffect, self).__init__(**kwargs)\n\n    def apply_distance(self, distance):\n        if abs(distance) < self.min_distance:\n            self.velocity = 0\n        self.value += distance\n\n    def start(self, val, t=None):\n        '''Start the movement.\n\n        :Parameters:\n            `val`: float or int\n                Value of the movement\n            `t`: float, defaults to None\n                Time when the movement happen. If no time is set, it will use\n                time.time()\n        '''\n        self.is_manual = True\n        t = t or time()\n        self.velocity = 0\n        self.history = [(t, val)]\n\n    def update(self, val, t=None):\n        '''Update the movement.\n\n        See :meth:`start` for the arguments.\n        '''\n        t = t or time()\n        distance = val - self.history[-1][1]\n        self.apply_distance(distance)\n        self.history.append((t, val))\n        if len(self.history) > self.max_history:\n            self.history.pop(0)\n\n    def stop(self, val, t=None):\n        '''Stop the movement.\n\n        See :meth:`start` for the arguments.\n        '''\n        self.is_manual = False\n        t = t or time()\n        distance = val - self.history[-1][1]\n        self.apply_distance(distance)\n        newest_sample = (t, val)\n        old_sample = self.history[0]\n        for sample in self.history:\n            if (newest_sample[0] - sample[0]) < 10. / 60.:\n                break\n            old_sample = sample\n        distance = newest_sample[1] - old_sample[1]\n        duration = abs(newest_sample[0] - old_sample[0])\n        self.velocity = (distance / max(duration, 0.0001))\n        self.trigger_velocity_update()\n\n    def cancel(self):\n        '''Cancel a movement. This can be used in case :meth:`stop` cannot be\n        called. It will reset :attr:`is_manual` to False, and compute the\n        movement if the velocity is > 0.\n        '''\n        self.is_manual = False\n        self.trigger_velocity_update()\n\n    def update_velocity(self, dt):\n        '''(internal) Update the velocity according to the frametime and\n        friction.\n        '''\n        if abs(self.velocity) <= self.min_velocity:\n            self.velocity = 0\n            return\n\n        self.velocity -= self.velocity * self.friction\n        self.apply_distance(self.velocity * dt)\n        self.trigger_velocity_update()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/effects/opacityscroll.py",
    "content": "'''\nOpacity scroll effect\n=====================\n\nBased on the :class:`~kivy.effects.damped.DampedScrollEffect`, this one will\nalso decrease the opacity of the target widget during the overscroll.\n\n'''\n\n__all__ = ('OpacityScrollEffect', )\n\n\nfrom kivy.effects.dampedscroll import DampedScrollEffect\n\n\nclass OpacityScrollEffect(DampedScrollEffect):\n    '''OpacityScrollEffect class. Uses the overscroll\n    information to reduce the opacity of the scrollview widget. When the user\n    stops the drag, the opacity is set back to 1.\n    '''\n\n    def on_overscroll(self, *args):\n        if self.target_widget and self.target_widget.height != 0:\n            alpha = (1.0 -\n                     abs(self.overscroll / float(self.target_widget.height)))\n            self.target_widget.opacity = min(1, alpha)\n        self.trigger_velocity_update()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/effects/scroll.py",
    "content": "'''\nScroll effect\n=============\n\n.. versionadded:: 1.7.0\n\nBased on the :class:`~kivy.effects.kinetic` effect, the :class:`ScrollEffect`\nwill limit the movement to bounds determined by its :attr:`~ScrollEffect.min`\nand :attr:`~ScrollEffect.max` properties. If the movement exceeds these\nbounds, it will calculate the amount of :attr:`~ScrollEffect.overscroll` and\ntry to return to the value of one of the bounds.\n\nThis is very useful for implementing a scrolling list. We actually use this\nclass as a base effect for our :class:`~kivy.uix.scrollview.ScrollView` widget.\n\n'''\n\n\n__all__ = ('ScrollEffect', )\n\n\nfrom kivy.effects.kinetic import KineticEffect\nfrom kivy.uix.widget import Widget\nfrom kivy.properties import NumericProperty, ObjectProperty\n\n\nclass ScrollEffect(KineticEffect):\n    '''ScrollEffect class. See the module documentation for more informations.\n    '''\n\n    drag_threshold = NumericProperty('20sp')\n    '''Minimum distance to travel before the movement is considered as a drag.\n\n    :attr:`velocity` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 20sp.\n    '''\n\n    min = NumericProperty(0)\n    '''Minimum boundary to use for scrolling.\n\n    :attr:`min` is a :class:`~kivy.properties.NumericProperty` and defaults to\n    0.\n    '''\n\n    max = NumericProperty(0)\n    '''Maximum boundary to use for scrolling.\n\n    :attr:`max` is a :class:`~kivy.properties.NumericProperty` and defaults to\n    0.\n    '''\n\n    scroll = NumericProperty(0)\n    '''Computed value for scrolling. This value is different from\n    :py:attr:`kivy.effects.kinetic.KineticEffect.value`\n    in that it will return to one of the min/max bounds.\n\n    :attr:`scroll` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 0.\n    '''\n\n    overscroll = NumericProperty(0)\n    '''Computed value when the user over-scrolls i.e. goes out of the bounds.\n\n    :attr:`overscroll` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    target_widget = ObjectProperty(None, allownone=True, baseclass=Widget)\n    '''Widget to attach to this effect. Even if this class doesn't make changes\n    to the `target_widget` by default, subclasses can use it to change the\n    graphics or apply custom transformations.\n\n    :attr:`target_widget` is a :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    displacement = NumericProperty(0)\n    '''Cumulative distance of the movement during the interaction. This is used\n    to determine if the movemenent is a drag (more than :attr:`drag_threshold`)\n    or not.\n\n    :attr:`displacement` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    def reset(self, pos):\n        '''(internal) Reset the value and the velocity to the `pos`.\n        Mostly used when the bounds are checked.\n        '''\n        self.value = pos\n        self.velocity = 0\n        if self.history:\n            val = self.history[-1][1]\n            super(ScrollEffect, self).start(val, None)\n\n    def on_value(self, *args):\n        scroll_min = self.min\n        scroll_max = self.max\n        if scroll_min > scroll_max:\n            scroll_min, scroll_max = scroll_max, scroll_min\n        if self.value < scroll_min:\n            self.overscroll = self.value - scroll_min\n            self.reset(scroll_min)\n        elif self.value > scroll_max:\n            self.overscroll = self.value - scroll_max\n            self.reset(scroll_max)\n        else:\n            self.scroll = self.value\n\n    def start(self, val, t=None):\n        self.is_manual = True\n        self.displacement = 0\n        return super(ScrollEffect, self).start(val, t)\n\n    def update(self, val, t=None):\n        self.displacement += abs(val - self.history[-1][1])\n        return super(ScrollEffect, self).update(val, t)\n\n    def stop(self, val, t=None):\n        self.is_manual = False\n        self.displacement += abs(val - self.history[-1][1])\n        if self.displacement <= self.drag_threshold:\n            self.velocity = 0\n            return\n        return super(ScrollEffect, self).stop(val, t)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/event.py",
    "content": "# This is a \"jumping\" module, required for python-for-android project\n# Because we are putting all the module into the same .so, their can be name\n# conflict. We have one conflict with pygame.event and kivy.event => Both are\n# python extension and have the same \"initevent\" symbol. So right now, just\n# rename this one.\n__all__ = ('EventDispatcher', 'ObjectWithUid', 'Observable')\n\nimport kivy._event\n__doc__ = kivy._event.__doc__\nEventDispatcher = kivy._event.EventDispatcher\nObjectWithUid = kivy._event.ObjectWithUid\nObservable = kivy._event.Observable\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/ext/__init__.py",
    "content": "'''\nExtension Support\n=================\n\nSometimes your application requires functionality that is beyond the scope of\nwhat Kivy can deliver. In those cases it is necessary to resort to external\nsoftware libraries. Given the richness of the Python ecosystem, there is already\na great number of software libraries that you can simply import and use right\naway.\n\nFor some third-party libraries, it's not as easy as that though. Some libraries\nrequire special *wrappers* to be written for them in order to be compatible with\nKivy.\nSome libraries might even need to be patched so that they can be used (e.g. if\nthey open their own OpenGL context to draw in and don't support proper offscreen\nrendering). On those occasions it is often possible to patch the library in\nquestion and to provide a Python wrapper around it that is compatible with Kivy.\nSticking with this example, you can't just use the wrapper with a 'normal'\ninstallation of the library because the patch would be missing.\n\nThat is where Kivy extensions come in handy. A Kivy extension represents a\nsingle third-party library that is provided in a way so that it can simply be\ndownloaded as a single file, put in a special directory and then offers the\nfunctionality of the wrapped library to Kivy applications.\nThese extensions will not pollute the global Python environment (as they might\nbe unusable on their own after potential patches have been applied) because they\nreside in special directories for Kivy that are not accessed by Python by\ndefault.\n\nKivy extensions are provided as ``*.kex`` files. They are really just zip files,\nbut you must not unzip them yourself. Kivy will do that for you as soon as it's\nappropriate to do so.\n\n.. warning::\n\n    Again, do not try to unzip ``*.kex`` files on your own. While unzipping will\n    work, Kivy will not be able to load the extension and will simply ignore it.\n\nWith Kivy's extension system, your application can use specially packaged\nthird-party libraries in a backwards compatible way (by specifying the version\nthat you require) even if the actual third-party library does not guarantee\nbackwards-compatibility. There will be no breakage if newer versions are\ninstalled (as a properly suited old version will still be used). For more\ninformation about that behaviour, consider the documentation of the\n:func:`~kivy.ext.load` function.\n\nIf you want to provide an extension on your own, there is a helper script that\nsets up the initial extension folder structure that Kivy requires for\nextensions. It can be found at kivy/tools/extensions/make-kivyext.py\n'''\n\nimport imp\nfrom glob import glob\nfrom os import listdir, mkdir, sep, environ\nfrom os.path import join, isdir, exists, dirname\nfrom zipfile import ZipFile\nfrom shutil import move\n\nfrom kivy.logger import Logger\n\nif not 'KIVY_DOC' in environ:\n    from kivy import kivy_userexts_dir, kivy_exts_dir\n\n    # The paths where extensions can be put as a .zip file by the user\n    EXTENSION_PATHS = [kivy_exts_dir, kivy_userexts_dir]\n\nNEED_UNZIP = True\n\n\ndef load(extname, version):\n    # XXX platform check?\n    '''Use this function to tell Kivy to load a specific version of the given\n    Extension. This is different from kivy's require() in that it will always\n    use the exact same major version you specify even if a newer (major)\n    version is available. This is because we cannot make the same\n    backwards-compatibility guarantee that we make with Kivy for third-party\n    extensions. You will still get fixes and optimizations that don't break\n    backwards compatibility via minor version upgrades of the extension.\n\n    The function will then return the loaded module as a Python module object\n    and you can bind it to a name of your choosing. This prevents clashes with\n    modules with the same name that might be installed in a system directory.\n\n    Usage example for this function::\n\n        from kivy.ext import load\n        myextension = load('myextension', (2, 1))\n        # You can now use myextension as if you had done ``import myextension``,\n        # but with the added benefit of using the proper version.\n\n    :Parameters:\n        `extname`: str\n            The exact name of the extension that you want to use.\n        `version`: two-tuple of ints\n            A tuple of the form (major, minor), where major and minor are ints\n            that specify the major and minor version number for the extension,\n            e.g. (1, 2) would be akin to 1.2. It is important to note that\n            between minor versions, backwards compatibility is guaranteed, but\n            between major versions it is not. I.e. if you change your extension\n            in a backwards incompatible way, increase the major version number\n            (and reset the minor to 0). If you just do a bug fix or add an\n            optional, backwards-compatible feature, you can just increase the\n            minor version number. If the application then requires version (1,\n            2), every version starting with that version number will be ok and\n            by default the latest version will be choosen.\n            The two ints major and minor can both be in range(0, infinity).\n    '''\n    #\n    global NEED_UNZIP\n    if NEED_UNZIP:\n        unzip_extensions()\n        NEED_UNZIP = False\n\n    # Find the one path that best satisfies the specified criteria, i.e. same\n    # extension name, same major version number, maximum available minor version\n    # number but at least the same as the specified minor version number.\n    majmatch = extname + '_' + str(version[0]) + '.*'\n    best = None\n    bestpath = None\n    globs = []\n    for epath in EXTENSION_PATHS:\n        globs.extend(glob(join(epath, majmatch)))\n    for p in globs:\n        # minmatch\n        cur = int(p.rsplit('.')[-1])\n        if best is None or cur > best:\n            best = cur\n            bestpath = p\n    if best >= version[1]:\n        searchpath = [bestpath]\n    else:\n        # Didn't find a matching extension\n        raise ImportError(\"No extension found that satisfies your criteria: \" +\n                          \"('%s', %s)\" % (extname, version))\n\n    file, pathname, desc = imp.find_module(extname, searchpath)\n    msg = 'Extension found for ' + repr(extname) + ':\\n\\t' + str(file) + \\\n          '\\n\\t' + str(pathname) + '\\n\\t' + str(desc)\n    Logger.debug(msg)\n\n    try:\n        mod = imp.load_module(extname, file, pathname, desc)\n    finally:\n        if file:\n            file.close()\n\n    return mod\n\n\ndef _is_valid_ext_name(name):\n    try:\n        extname, version = name.split('_')\n        major, minor = version.split('.')\n        major, minor = int(major), int(minor)\n    except:\n        print(\"The name '%s' is not a valid extension name.\" % name)\n        return False\n    return (extname, (major, minor))\n\n\ndef unzip_extensions():\n    '''Unzips Kivy extensions. Internal usage only: don't use it yourself unless\n    you know what you're doing and really want to trigger installation of new\n    extensions.\n\n    For your file to be recognized as an extension, it has to fulfil a few\n    requirements:\n\n     * We require that the file has the ``*.kex`` extension to make the\n       distinction between a Kivy extension and an ordinary zip file clear.\n\n     * We require that the ``*.kex`` extension files be put into any of the\n       directories listed in EXTENSION_PATHS which is normally\n       ~/.kivy/extensions and extensions/ inside kivy's base directory. We do\n       not look for extensions on sys.path or elsewhere in the system.\n\n     * We require that the Kivy extension is zipped in a way so that Python's\n       zipfile module can extract it properly.\n\n     * We require that the extension internally obeys the common Kivy extension\n       format, which looks like this::\n\n            |-- myextension/\n                |-- __init__.py\n                |-- data/\n\n       The ``__init__.py`` file is the main entrypoint to the extension. All\n       names that should be usable when the extension is loaded need to be\n       exported (i.e. made available) in the namespace of that file.\n\n       How the extension accesses the code of the library that it wraps (be it\n       pure Python or binary code) is up to the extension. For example there\n       could be another Python module adjacent to the ``__init__.py`` file from\n       which the ``__init__.py`` file imports the usable names that it wants to\n       expose.\n\n     * We require that the version of the extension be specified in the\n       ``setup.py`` file that is created by the Kivy extension wizard and that\n       the version specification format as explained in :func:`~kivy.ext.load`\n       be used.\n    '''\n    Logger.debug('Searching for new extension in %s' % EXTENSION_PATHS)\n\n    for epath in EXTENSION_PATHS:\n        if not isdir(epath):\n            try:\n                mkdir(epath)\n            except OSError:\n                continue\n            files = []\n        else:\n            files = listdir(epath)\n        for zipfn in glob(join(epath, '*.kex')):\n            # ZipFile only became a context manager in python 2.7...\n            # with ZipFile(zipfn, 'r') as zipf:\n            # fail = is_invalid = False\n            try:\n                zipf = ZipFile(zipfn)\n                # /path/to/MyExt-1.0.linux-x86_64.zip\n                # /path/to/MyExt-1.0.macos-10.6-x86_64.zip\n                extname = zipfn.rsplit(sep)[-1][:-4]\n                # MyExt-1.0.linux-x86_64\n                # MyExt-1.0.macosx-10.6-x86_64\n                t = extname.split('-')\n                extname = t[0]\n                version = '-'.join(t[1:])\n                version = '.'.join(version.split('.')[:2])\n\n                extdir = extname + '_' + version\n\n                # is_invalid = not _is_valid_ext_name(extdir)\n            except IOError:\n                Logger.warn(\"Malformed zipfile '%s'! Skipping it.\" % zipfn)\n                continue\n            except Exception as e:\n                Logger.warn(\"Malformed extension '%s'! Skipping it.\" % zipfn)\n                zipf.close()\n                continue\n\n            already_unzipped = False\n            if extdir in files:\n                Logger.trace((\"Extension '%s' has already been \" % extname) +\n                              \"extracted manually, just moving the zip.\")\n                already_unzipped = True\n\n            # Filter the namelist of zipfile to take only the members that start\n            # with the extension name (MyExt/...)\n            members = [x for x in zipf.namelist()\n                       if x.startswith(extname + '/')]\n\n            if not already_unzipped:\n                # Unzip the extension\n                try:\n                    cache_directories = []\n                    mkdir(join(epath, extdir))\n                    # I know that there is zipf.extract() and zipf.extractall(),\n                    # but on OSX, Python 2.6 is the default and in that version,\n                    # both methods have a bug. Fixed in 2.7 only. So use this\n                    # workaround until apple upgrades its python. See\n                    # http://bugs.python.org/issue4710\n                    for member in members:\n                        # In zipfiles, folders always end with '/' regardless\n                        # of the OS\n                        mempath = join(epath, extdir, member)\n                        directory = dirname(mempath)\n                        if not directory in cache_directories:\n                            cache_directories.append(directory)\n                            if not exists(directory):\n                                mkdir(join(epath, extdir, directory))\n                        with open(join(epath, extdir, member), 'wb') as fd:\n                            fd.write(zipf.read(member))\n                except Exception as e:\n                    # Catch any error, e.g. non-writable directory, etc.\n                    Logger.error(\"Failed installing extension \" +\n                                 \"'%s' %s.\" % (extname, e))\n                    return\n                finally:\n                    zipf.close()\n                Logger.info(\"Installed extension '%s'.\" % extname)\n\n            # Move the zip out of the way so that it won't be installed again\n            # The user can just delete it, but we'll keep it around in case the\n            # user needs it again.\n            consumed_dir = join(epath, '_consumed_zips')\n            if not isdir(consumed_dir):\n                mkdir(consumed_dir)\n            move(zipfn, consumed_dir)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/extras/__init__.py",
    "content": "\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/extras/highlight.py",
    "content": "'''Pygments lexer for kv language\n'''\nfrom pygments.lexer import RegexLexer, bygroups, using\nfrom pygments.lexers.agile import PythonLexer\nfrom pygments import highlight\nfrom pygments.token import *\nfrom pygments.formatters import get_formatter_by_name\nimport sys\n\n\nclass KivyLexer(RegexLexer):\n    name = 'Kivy'\n    aliases = ['kivy', 'kv']\n    filenames = ['*.kv']\n    tokens = {\n        'root': [\n            (r'#:.*?$', Comment.Preproc),\n            (r'#.*?$', using(PythonLexer)),\n            (r'\\s+', Text),\n            (r'<.+>', Name.Namespace),\n            (r'(\\[)(\\s*)(.*?)(\\s*)(@)',\n                bygroups(Punctuation, Text, Name.Class, Text, Operator),\n                'classList'),\n            (r'[A-Za-z][A-Za-z0-9]*$', Name.Attribute),\n            (r'(.*?)(\\s*)(:)(\\s*)$',\n                bygroups(Name.Class, Text, Punctuation, Text)),\n            (r'(.*?)(\\s*)(:)(\\s*)(.*?)$',\n                bygroups(Name.Attribute, Text, Punctuation, Text,\n                using(PythonLexer)))],\n        'classList': [\n            (r'(,)(\\s*)([A-Z][A-Za-z0-9]*)',\n                bygroups(Punctuation, Text, Name.Class)),\n            (r'(\\+)(\\s*)([A-Z][A-Za-z0-9]*)',\n                bygroups(Operator, Text, Name.Class)),\n            (r'\\s+', Text),\n            (r'[A-Z][A-Za-z0-9]*', Name.Class),\n            (r'\\]', Punctuation, '#pop')]}\n\n\nif __name__ == '__main__':\n    ''' This lexer will highlight .kv file. The first argument is the source\n    file, the second argument is the format of the destination and the third\n    argument is the output filename\n    '''\n    if len(sys.argv) is not 4:\n        raise Exception('Three arguments expected, found %s' %\n            (len(sys.argv) - 1))\n    k = KivyLexer()\n    with open(sys.argv[1], 'r') as fd:\n        with open(sys.argv[3], 'w') as out:\n            highlight(fd.read(), k, get_formatter_by_name(sys.argv[2]), out)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/factory.py",
    "content": "'''\nFactory object\n==============\n\nThe factory can be used to automatically register any class or module\nand instantiate classes from it anywhere in your project. It is an\nimplementation of the\n`Factory Pattern <http://en.wikipedia.org/wiki/Factory_pattern>`_.\n\nThe class list and available modules are automatically generated by setup.py.\n\nExample for registering a class/module::\n\n    >>> from kivy.factory import Factory\n    >>> Factory.register('Widget', module='kivy.uix.widget')\n    >>> Factory.register('Vector', module='kivy.vector')\n\nExample of using the Factory::\n\n    >>> from kivy.factory import Factory\n    >>> widget = Factory.Widget(pos=(456,456))\n    >>> vector = Factory.Vector(9, 2)\n\nExample using a class name::\n\n    >>> from kivy.factory import Factory\n    >>> Factory.register('MyWidget', cls=MyWidget)\n\nBy default, the first classname you register via the factory is permanent.\nIf you wish to change the registered class, you need to unregister the\nclassname before you re-assign it::\n\n    >>> from kivy.factory import Factory\n    >>> Factory.register('MyWidget', cls=MyWidget)\n    >>> widget = Factory.MyWidget()\n    >>> Factory.unregister('MyWidget')\n    >>> Factory.register('MyWidget', cls=CustomWidget)\n    >>> customWidget = Factory.MyWidget()\n'''\n\n__all__ = ('Factory', 'FactoryException')\n\nfrom kivy.logger import Logger\n\n\nclass FactoryException(Exception):\n    pass\n\n\nclass FactoryBase(object):\n\n    def __init__(self):\n        super(FactoryBase, self).__init__()\n        self.classes = {}\n\n    def is_template(self, classname):\n        '''Return True if the classname is a template from the\n        :class:`~kivy.lang.Builder`.\n\n        .. versionadded:: 1.0.5\n        '''\n        if classname in self.classes:\n            return self.classes[classname]['is_template']\n        else:\n            return False\n\n    def register(self, classname, cls=None, module=None, is_template=False,\n                 baseclasses=None, filename=None, warn=False):\n        '''Register a new classname referring to a real class or\n        class definition in a module. Warn, if True will emit a warning message\n        when a class is re-declared.\n\n        .. versionchanged:: 1.9.0\n            `warn` was added.\n\n        .. versionchanged:: 1.7.0\n            :attr:`baseclasses` and :attr:`filename` added\n\n        .. versionchanged:: 1.0.5\n            :attr:`is_template` has been added in 1.0.5.\n        '''\n        if cls is None and module is None and baseclasses is None:\n            raise ValueError(\n                'You must specify either cls= or module= or baseclasses =')\n        if classname in self.classes:\n            if warn:\n                info = self.classes[classname]\n                Logger.warning('Factory: Ignored class \"{}\" re-declaration. '\n                'Current -  module: {}, cls: {}, baseclass: {}, filename: {}. '\n                'Ignored -  module: {}, cls: {}, baseclass: {}, filename: {}.'.\n                format(classname, info['module'], info['cls'],\n                       info['baseclasses'], info['filename'], module, cls,\n                       baseclasses, filename))\n            return\n        self.classes[classname] = {\n            'module': module,\n            'cls': cls,\n            'is_template': is_template,\n            'baseclasses': baseclasses,\n            'filename': filename}\n\n    def unregister(self, *classnames):\n        '''Unregisters the classnames previously registered via the\n        register method. This allows the same classnames to be re-used in\n        different contexts.\n\n        .. versionadded:: 1.7.1\n        '''\n        for classname in classnames:\n            if classname in self.classes:\n                self.classes.pop(classname)\n\n    def unregister_from_filename(self, filename):\n        '''Unregister all the factory objects related to the filename passed in\n        the parameter.\n\n        .. versionadded:: 1.7.0\n        '''\n        to_remove = [x for x in self.classes\n                     if self.classes[x]['filename'] == filename]\n        for name in to_remove:\n            del self.classes[name]\n\n    def __getattr__(self, name):\n        classes = self.classes\n        if name not in classes:\n            if name[0] == name[0].lower():\n                # if trying to access attributes like checking for `bind`\n                # then raise AttributeError\n                raise AttributeError\n            raise FactoryException('Unknown class <%s>' % name)\n\n        item = classes[name]\n        cls = item['cls']\n\n        # No class to return, import the module\n        if cls is None:\n            if item['module']:\n                module = __import__(name=item['module'], fromlist='.')\n                if not hasattr(module, name):\n                    raise FactoryException(\n                        'No class named <%s> in module <%s>' % (\n                            name, item['module']))\n                cls = item['cls'] = getattr(module, name)\n\n            elif item['baseclasses']:\n                rootwidgets = []\n                for basecls in item['baseclasses'].split('+'):\n                    rootwidgets.append(Factory.get(basecls))\n                cls = item['cls'] = type(str(name), tuple(rootwidgets), {})\n\n            else:\n                raise FactoryException('No information to create the class')\n\n        return cls\n\n    get = __getattr__\n\n\n#: Factory instance to use for getting new classes\nFactory = FactoryBase()\n\n# Now import the file with all registers\n# automatically generated by build_factory\nimport kivy.factory_registers  # NOQA\nLogger.info('Factory: %d symbols loaded' % len(Factory.classes))\n\nif __name__ == '__main__':\n    Factory.register('Vector', module='kivy.vector')\n    Factory.register('Widget', module='kivy.uix.widget')\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/factory_registers.py",
    "content": "# Auto-generated file by setup.py build_factory\n\nfrom kivy.factory import Factory\n\nr = Factory.register\nr('Adapter', module='kivy.adapters.adapter')\nr('ListAdapter', module='kivy.adapters.listadapter')\nr('SimpleListAdapter', module='kivy.adapters.simplelistadapter')\nr('DictAdapter', module='kivy.adapters.dictadapter')\nr('SelectableDataItem', module='kivy.adapters.models')\nr('Animation', module='kivy.animation')\nr('AnimationTransition', module='kivy.animation')\nr('ExceptionHandler', module='kivy.base')\nr('Cache', module='kivy.cache')\nr('ClockBase', module='kivy.clock')\nr('ColorPicker', module='kivy.uix.colorpicker')\nr('ColorWheel', module='kivy.uix.colorpicker')\nr('ConfigParser', module='kivy.config')\nr('EventDispatcher', module='kivy.event')\nr('Observable', module='kivy.event')\nr('FactoryException', module='kivy.factory')\nr('Gesture', module='kivy.gesture')\nr('GestureDatabase', module='kivy.gesture')\nr('GesturePoint', module='kivy.gesture')\nr('GestureStroke', module='kivy.gesture')\nr('Parser', module='kivy.lang')\nr('LoaderBase', module='kivy.loader')\nr('ProxyImage', module='kivy.loader')\nr('LoggerHistory', module='kivy.logger')\nr('NumericProperty', module='kivy.properties')\nr('StringProperty', module='kivy.properties')\nr('ListProperty', module='kivy.properties')\nr('ObjectProperty', module='kivy.properties')\nr('BooleanProperty', module='kivy.properties')\nr('BoundedNumericProperty', module='kivy.properties')\nr('OptionProperty', module='kivy.properties')\nr('ReferenceListProperty', module='kivy.properties')\nr('AliasProperty', module='kivy.properties')\nr('NumericProperty', module='kivy.properties')\nr('Property', module='kivy.properties')\nr('SafeList', module='kivy.utils')\nr('Vector', module='kivy.vector')\nr('Color', module='kivy.graphics.context_instructions')\nr('BindTexture', module='kivy.graphics.context_instructions')\nr('PushMatrix', module='kivy.graphics.context_instructions')\nr('PopMatrix', module='kivy.graphics.context_instructions')\nr('Rotate', module='kivy.graphics.context_instructions')\nr('Scale', module='kivy.graphics.context_instructions')\nr('Translate', module='kivy.graphics.context_instructions')\nr('MatrixInstruction', module='kivy.graphics.context_instructions')\nr('Fbo', module='kivy.graphics.fbo')\nr('Instruction', module='kivy.graphics.instructions')\nr('InstructionGroup', module='kivy.graphics.instructions')\nr('ContextInstruction', module='kivy.graphics.instructions')\nr('VertexInstruction', module='kivy.graphics.instructions')\nr('Canvas', module='kivy.graphics.instructions')\nr('CanvasBase', module='kivy.graphics.instructions')\nr('RenderContext', module='kivy.graphics.instructions')\nr('Shader', module='kivy.graphics.shader')\nr('Texture', module='kivy.graphics.texture')\nr('TextureRegion', module='kivy.graphics.texture')\nr('Matrix', module='kivy.graphics.transformation')\nr('VBO', module='kivy.graphics.vbo')\nr('VertexBatch', module='kivy.graphics.vbo')\nr('StencilPush', module='kivy.graphics.stencil_instructions')\nr('StencilPop', module='kivy.graphics.stencil_instructions')\nr('StencilUse', module='kivy.graphics.stencil_instructions')\nr('StencilUnUse', module='kivy.graphics.stencil_instructions')\nr('Triangle', module='kivy.graphics.vertex_instructions')\nr('Quad', module='kivy.graphics.vertex_instructions')\nr('Rectangle', module='kivy.graphics.vertex_instructions')\nr('BorderImage', module='kivy.graphics.vertex_instructions')\nr('Ellipse', module='kivy.graphics.vertex_instructions')\nr('Line', module='kivy.graphics.vertex_instructions')\nr('SmoothLine', module='kivy.graphics.vertex_instructions')\nr('Point', module='kivy.graphics.vertex_instructions')\nr('Bezier', module='kivy.graphics.vertex_instructions')\nr('Mesh', module='kivy.graphics.vertex_instructions')\nr('Svg', module='kivy.graphics.svg')\nr('MotionEventFactory', module='kivy.input.factory')\nr('MotionEventProvider', module='kivy.input.provider')\nr('Shape', module='kivy.input.shape')\nr('ShapeRect', module='kivy.input.shape')\nr('ActionBar', module='kivy.uix.actionbar')\nr('ActionItem', module='kivy.uix.actionbar')\nr('ActionButton', module='kivy.uix.actionbar')\nr('ActionToggleButton', module='kivy.uix.actionbar')\nr('ActionCheck', module='kivy.uix.actionbar')\nr('ActionSeparator', module='kivy.uix.actionbar')\nr('ActionDropDown', module='kivy.uix.actionbar')\nr('ActionGroup', module='kivy.uix.actionbar')\nr('ActionOverflow', module='kivy.uix.actionbar')\nr('ActionView', module='kivy.uix.actionbar')\nr('ContextualActionView', module='kivy.uix.actionbar')\nr('AnchorLayout', module='kivy.uix.anchorlayout')\nr('BoxLayout', module='kivy.uix.boxlayout')\nr('GridLayout', module='kivy.uix.gridlayout')\nr('PageLayout', module='kivy.uix.pagelayout')\nr('Accordion', module='kivy.uix.accordion')\nr('AccordionItem', module='kivy.uix.accordion')\nr('Button', module='kivy.uix.button')\nr('ButtonBehavior', module='kivy.uix.behaviors')\nr('ToggleButtonBehavior', module='kivy.uix.behaviors')\nr('DragBehavior', module='kivy.uix.behaviors')\nr('FocusBehavior', module='kivy.uix.behaviors')\nr('CompoundSelectionBehavior', module='kivy.uix.behaviors')\nr('Bubble', module='kivy.uix.bubble')\nr('BubbleButton', module='kivy.uix.bubble')\nr('Camera', module='kivy.uix.camera')\nr('Carousel', module='kivy.uix.carousel')\nr('CodeInput', module='kivy.uix.codeinput')\nr('CheckBox', module='kivy.uix.checkbox')\nr('DropDown', module='kivy.uix.dropdown')\nr('EffectWidget', module='kivy.uix.effectwidget')\nr('FloatLayout', module='kivy.uix.floatlayout')\nr('RelativeLayout', module='kivy.uix.relativelayout')\nr('ScatterLayout', module='kivy.uix.scatterlayout')\nr('ScatterPlaneLayout', module='kivy.uix.scatterlayout')\nr('FileChooserListView', module='kivy.uix.filechooser')\nr('FileChooserIconView', module='kivy.uix.filechooser')\nr('FileChooser', module='kivy.uix.filechooser')\nr('Image', module='kivy.uix.image')\nr('AsyncImage', module='kivy.uix.image')\nr('Label', module='kivy.uix.label')\nr('Layout', module='kivy.uix.layout')\nr('AbstractView', module='kivy.uix.abstractview')\nr('CompositeListItem', module='kivy.uix.listview')\nr('ListItemButton', module='kivy.uix.listview')\nr('ListItemLabel', module='kivy.uix.listview')\nr('ListView', module='kivy.uix.listview')\nr('SelectableView', module='kivy.uix.listview')\nr('ModalView', module='kivy.uix.modalview')\nr('ProgressBar', module='kivy.uix.progressbar')\nr('Popup', module='kivy.uix.popup')\nr('Scatter', module='kivy.uix.scatter')\nr('ScatterPlane', module='kivy.uix.scatter')\nr('ScrollView', module='kivy.uix.scrollview')\nr('Settings', module='kivy.uix.settings')\nr('Slider', module='kivy.uix.slider')\nr('Screen', module='kivy.uix.screenmanager')\nr('ScreenManager', module='kivy.uix.screenmanager')\nr('Spinner', module='kivy.uix.spinner')\nr('Splitter', module='kivy.uix.splitter')\nr('StackLayout', module='kivy.uix.stacklayout')\nr('StencilView', module='kivy.uix.stencilview')\nr('Switch', module='kivy.uix.switch')\nr('TabbedPanel', module='kivy.uix.tabbedpanel')\nr('TabbedPanelHeader', module='kivy.uix.tabbedpanel')\nr('TextInput', module='kivy.uix.textinput')\nr('ToggleButton', module='kivy.uix.togglebutton')\nr('TreeView', module='kivy.uix.treeview')\nr('TreeViewLabel', module='kivy.uix.treeview')\nr('TreeViewNode', module='kivy.uix.treeview')\nr('ShaderTransition', module='kivy.uix.screenmanager')\nr('SlideTransition', module='kivy.uix.screenmanager')\nr('SwapTransition', module='kivy.uix.screenmanager')\nr('WipeTransition', module='kivy.uix.screenmanager')\nr('FadeTransition', module='kivy.uix.screenmanager')\nr('Sandbox', module='kivy.uix.sandbox')\nr('Video', module='kivy.uix.video')\nr('VideoPlayer', module='kivy.uix.videoplayer')\nr('VideoPlayerVolume', module='kivy.uix.videoplayer')\nr('VideoPlayerStop', module='kivy.uix.videoplayer')\nr('VideoPlayerPlayPause', module='kivy.uix.videoplayer')\nr('VideoPlayerProgressBar', module='kivy.uix.videoplayer')\nr('VKeyboard', module='kivy.uix.vkeyboard')\nr('Widget', module='kivy.uix.widget')\nr('WidgetException', module='kivy.uix.widget')\nr('RstDocument', module='kivy.uix.rst')\nr('KineticEffect', module='kivy.effects.kinetic')\nr('ScrollEffect', module='kivy.effects.scroll')\nr('DampedScrollEffect', module='kivy.effects.dampedscroll')\nr('OpacityScrollEffect', module='kivy.effects.opacityscroll')\nr('Recognizer', module='kivy.multistroke')\nr('MultistrokeGesture', module='kivy.multistroke')\nr('UnistrokeTemplate', module='kivy.multistroke')\nr('ProgressTracker', module='kivy.multistroke')\nr('GestureSurface', module='kivy.uix.gesturesurface')\nr('GestureContainer', module='kivy.uix.gesturesurface')\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/garden/__init__.py",
    "content": "'''\nGarden\n======\n\n.. versionadded:: 1.7.0\n\n.. versionchanged:: 1.8.0\n\nGarden is a project to centralize addons for Kivy maintained by users. You can\nfind more information at `Kivy Garden <http://kivy-garden.github.io/>`_. All\nthe garden packages are centralized on the `kivy-garden Github\n<https://github.com/kivy-garden>`_ repository.\n\nGarden is now distributed as a separate Python module, kivy-garden. You can\ninstall it with pip::\n\n    pip install kivy-garden\n\nThe garden module does not initially include any packages. You can download\nthem with the garden tool installed by the pip package::\n\n    # Installing a garden package\n    garden install graph\n\n    # Upgrade a garden package\n    garden install --upgrade graph\n\n    # Uninstall a garden package\n    garden uninstall graph\n\n    # List all the garden packages installed\n    garden list\n\n    # Search new packages\n    garden search\n\n    # Search all the packages that contain \"graph\"\n    garden search graph\n\n    # Show the help\n    garden --help\n\nAll the garden packages are installed by default in `~/.kivy/garden`.\n\n.. Note:: In previous versions of Kivy, garden was a tool at\n          kivy/tools/garden. This no longer exists, but the\n          kivy-garden module provides exactly the same functionality.\n\nPackaging\n---------\n\nIf you want to include garden packages in your application, you can add `--app`\nto the `install` command. This will create a `libs/garden` directory in your\ncurrent directory which will be used by `kivy.garden`.\n\nFor example::\n\n    cd myapp\n    garden install --app graph\n\n\n'''\n\n__path__ = 'kivy.garden'\n\nimport sys\nimport imp\nfrom os.path import dirname, join, realpath, exists, abspath\nfrom kivy import kivy_home_dir\nimport kivy\n\n#: system path where garden modules can be installed\ngarden_system_dir = join(kivy_home_dir, 'garden')\ngarden_kivy_dir = abspath(join(dirname(kivy.__file__), 'garden'))\n\n#: application path where garden modules can be installed\nif getattr(sys, 'frozen', False) and getattr(sys, '_MEIPASS', False):\n    garden_app_dir = join(realpath(sys._MEIPASS), 'libs', 'garden')\nelse:\n    garden_app_dir = join(realpath(dirname(sys.argv[0])), 'libs', 'garden')\n\n\nclass GardenImporter(object):\n\n    def find_module(self, fullname, path):\n        if path == 'kivy.garden':\n            return self\n\n    def load_module(self, fullname):\n        assert(fullname.startswith('kivy.garden'))\n\n        moddir = join(garden_kivy_dir, fullname.split('.', 2)[-1])\n        if exists(moddir):\n            return self._load_module(fullname, moddir)\n\n        modname = fullname.split('.', 1)[-1]\n        for directory in (garden_app_dir, garden_system_dir):\n            moddir = join(directory, modname)\n            if exists(moddir):\n                return self._load_module(fullname, moddir)\n\n    def _load_module(self, fullname, moddir):\n        mod = imp.load_module(fullname, None, moddir,\n                              ('', '', imp.PKG_DIRECTORY))\n        return mod\n\n\n# insert the garden importer as ultimate importer\nsys.meta_path.append(GardenImporter())\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/geometry.py",
    "content": "'''\nGeometry utilities\n==================\n\nThis module contains some helper functions for geometric calculations.\n'''\n\n__all__ = ('circumcircle', 'minimum_bounding_circle')\n\nfrom kivy.vector import Vector\n\n\ndef circumcircle(a, b, c):\n    '''\n    Computes the circumcircle of a triangle defined by a, b, c.\n    See: http://en.wikipedia.org/wiki/Circumscribed_circle\n\n    :Parameters:\n        `a` : iterable containing at least 2 values (for x and y)\n            The 1st point of the triangle.\n        `b` : iterable containing at least 2 values (for x and y)\n            The 2nd point of the triangle.\n        `c` : iterable containing at least 2 values (for x and y)\n            The 3rd point of the triangle.\n\n    :Return:\n        A tuple that defines the circle :\n         * The first element in the returned tuple is the center as (x, y)\n         * The second is the radius (float)\n    '''\n    P = Vector(a[0], a[1])\n    Q = Vector(b[0], b[1])\n    R = Vector(c[0], c[1])\n\n    mPQ = (P + Q) * .5\n    mQR = (Q + R) * .5\n\n    numer = -(- mPQ.y * R.y + mPQ.y * Q.y + mQR.y * R.y - mQR.y * Q.y\n              - mPQ.x * R.x + mPQ.x * Q.x + mQR.x * R.x - mQR.x * Q.x)\n    denom = (-Q.x * R.y + P.x * R.y - P.x * Q.y +\n             Q.y * R.x - P.y * R.x + P.y * Q.x)\n\n    t = numer / denom\n\n    cx = -t * (Q.y - P.y) + mPQ.x\n    cy = t * (Q.x - P.x) + mPQ.y\n\n    return ((cx, cy), (P - (cx, cy)).length())\n\n\ndef minimum_bounding_circle(points):\n    '''\n    Returns the minimum bounding circle for a set of points.\n\n    For a description of the problem being solved, see the `Smallest Circle\n    Problem <http://en.wikipedia.org/wiki/Smallest_circle_problem>`_.\n\n    The function uses Applet's Algorithm, the runtime is O\\(h^3, \\*n\\),\n    where h is the number of points in the convex hull of the set of points.\n    **But** it runs in linear time in almost all real world cases.\n    See: http://tinyurl.com/6e4n5yb\n\n    :Parameters:\n        `points` : iterable\n            A list of points (2 tuple with x,y coordinates)\n\n    :Return:\n        A tuple that defines the circle:\n            * The first element in the returned tuple is the center (x, y)\n            * The second the radius (float)\n\n    '''\n    points = [Vector(p[0], p[1]) for p in points]\n\n    if len(points) == 1:\n        return (points[0].x, points[0].y), 0.0\n\n    if len(points) == 2:\n        p1, p2 = points\n        return (p1 + p2) * .5, ((p1 - p2) * .5).length()\n\n    # determine a point P with the smallest y value\n    P = min(points, key=lambda p: p.y)\n\n    # find a point Q such that the angle of the line segment\n    # PQ with the x axis is minimal\n    def x_axis_angle(q):\n        if q == P:\n            return 1e10  # max val if the same, to skip\n        return abs((q - P).angle((1, 0)))\n    Q = min(points, key=x_axis_angle)\n\n    for p in points:\n        # find R such that angle PRQ is minimal\n        def angle_pq(r):\n            if r in (P, Q):\n                return 1e10  # max val if the same, to skip\n            return abs((r - P).angle(r - Q))\n        R = min(points, key=angle_pq)\n\n        # check for case 1 (angle PRQ is obtuse), the circle is determined\n        # by two points, P and Q. radius = |(P-Q)/2|, center = (P+Q)/2\n        if angle_pq(R) > 90.0:\n            return (P + Q) * .5, ((P - Q) * .5).length()\n\n        # if angle RPQ is obtuse, make P = R, and try again\n        if abs((R - P).angle(Q - P)) > 90:\n            P = R\n            continue\n\n        # if angle PQR is obtuse, make Q = R, and try again\n        if abs((P - Q).angle(R - Q)) > 90:\n            Q = R\n            continue\n\n        # all angles were acute..we just need the circle through the\n        # two points furthest apart!\n        break\n\n    # find the circumcenter for triangle given by P,Q,R\n    return circumcircle(P, Q, R)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/gesture.py",
    "content": "'''\nGesture recognition\n===================\n\nThis class allows you to easily create new\ngestures and compare them::\n\n    from kivy.gesture import Gesture, GestureDatabase\n\n    # Create a gesture\n    g = Gesture()\n    g.add_stroke(point_list=[(1,1), (3,4), (2,1)])\n    g.normalize()\n\n    # Add it to the database\n    gdb = GestureDatabase()\n    gdb.add_gesture(g)\n\n    # And for the next gesture, try to find it!\n    g2 = Gesture()\n    # ...\n    gdb.find(g2)\n\n.. warning::\n\n   You don't really want to do this: it's more of an example of how\n   to construct gestures dynamically. Typically, you would\n   need a lot more points, so it's better to record gestures in a file and\n   reload them to compare later. Look in the examples/gestures directory for\n   an example of how to do that.\n\n'''\n\n__all__ = ('Gesture', 'GestureDatabase', 'GesturePoint', 'GestureStroke')\n\nimport pickle\nimport base64\nimport zlib\nimport math\n\nfrom kivy.vector import Vector\n\nfrom io import BytesIO\n\n\nclass GestureDatabase(object):\n    '''Class to handle a gesture database.'''\n\n    def __init__(self):\n        self.db = []\n\n    def add_gesture(self, gesture):\n        '''Add a new gesture to the database.'''\n        self.db.append(gesture)\n\n    def find(self, gesture, minscore=0.9, rotation_invariant=True):\n        '''Find a matching gesture in the database.'''\n        if not gesture:\n            return\n\n        best = None\n        bestscore = minscore\n        for g in self.db:\n            score = g.get_score(gesture, rotation_invariant)\n            if score < bestscore:\n                continue\n            bestscore = score\n            best = g\n        if not best:\n            return\n        return (bestscore, best)\n\n    def gesture_to_str(self, gesture):\n        '''Convert a gesture into a unique string.'''\n        io = BytesIO()\n        p = pickle.Pickler(io)\n        p.dump(gesture)\n        data = base64.b64encode(zlib.compress(io.getvalue(), 9))\n        return data\n\n    def str_to_gesture(self, data):\n        '''Convert a unique string to a gesture.'''\n        io = BytesIO(zlib.decompress(base64.b64decode(data)))\n        p = pickle.Unpickler(io)\n        gesture = p.load()\n        return gesture\n\n\nclass GesturePoint:\n\n    def __init__(self, x, y):\n        '''Stores the x,y coordinates of a point in the gesture.'''\n        self.x = float(x)\n        self.y = float(y)\n\n    def scale(self, factor):\n        ''' Scales the point by the given factor.'''\n        self.x *= factor\n        self.y *= factor\n        return self\n\n    def __repr__(self):\n        return 'Mouse_point: %f,%f' % (self.x, self.y)\n\n\nclass GestureStroke:\n    ''' Gestures can be made up of multiple strokes.'''\n\n    def __init__(self):\n        ''' A stroke in the gesture.'''\n        self.points = list()\n        self.screenpoints = list()\n\n    # These return the min and max coordinates of the stroke\n    @property\n    def max_x(self):\n        if len(self.points) == 0:\n            return 0\n        return max(self.points, key=lambda pt: pt.x).x\n\n    @property\n    def min_x(self):\n        if len(self.points) == 0:\n            return 0\n        return min(self.points, key=lambda pt: pt.x).x\n\n    @property\n    def max_y(self):\n        if len(self.points) == 0:\n            return 0\n        return max(self.points, key=lambda pt: pt.y).y\n\n    @property\n    def min_y(self):\n        if len(self.points) == 0:\n            return 0\n        return min(self.points, key=lambda pt: pt.y).y\n\n    def add_point(self, x, y):\n        '''\n        add_point(x=x_pos, y=y_pos)\n        Adds a point to the stroke.\n        '''\n        self.points.append(GesturePoint(x, y))\n        self.screenpoints.append((x, y))\n\n    def scale_stroke(self, scale_factor):\n        '''\n        scale_stroke(scale_factor=float)\n        Scales the stroke down by scale_factor.\n        '''\n        self.points = [pt.scale(scale_factor) for pt in self.points]\n\n    def points_distance(self, point1, point2):\n        '''\n        points_distance(point1=GesturePoint, point2=GesturePoint)\n        Returns the distance between two GesturePoints.\n        '''\n        x = point1.x - point2.x\n        y = point1.y - point2.y\n        return math.sqrt(x * x + y * y)\n\n    def stroke_length(self, point_list=None):\n        '''Finds the length of the stroke. If a point list is given,\n           finds the length of that list.\n        '''\n        if point_list is None:\n            point_list = self.points\n        gesture_length = 0.0\n        if len(point_list) <= 1:  # If there is only one point -> no length\n            return gesture_length\n        for i in range(len(point_list) - 1):\n            gesture_length += self.points_distance(\n                point_list[i], point_list[i + 1])\n        return gesture_length\n\n    def normalize_stroke(self, sample_points=32):\n        '''Normalizes strokes so that every stroke has a standard number of\n           points. Returns True if stroke is normalized, False if it can't be\n           normalized. sample_points controls the resolution of the stroke.\n        '''\n        # If there is only one point or the length is 0, don't normalize\n        if len(self.points) <= 1 or self.stroke_length(self.points) == 0.0:\n            return False\n\n        # Calculate how long each point should be in the stroke\n        target_stroke_size = \\\n            self.stroke_length(self.points) / float(sample_points)\n        new_points = list()\n        new_points.append(self.points[0])\n\n        # We loop on the points\n        prev = self.points[0]\n        src_distance = 0.0\n        dst_distance = target_stroke_size\n        for curr in self.points[1:]:\n            d = self.points_distance(prev, curr)\n            if d > 0:\n                prev = curr\n                src_distance = src_distance + d\n\n                # The new point need to be inserted into the\n                # segment [prev, curr]\n                while dst_distance < src_distance:\n                    x_dir = curr.x - prev.x\n                    y_dir = curr.y - prev.y\n                    ratio = (src_distance - dst_distance) / d\n                    to_x = x_dir * ratio + prev.x\n                    to_y = y_dir * ratio + prev.y\n                    new_points.append(GesturePoint(to_x, to_y))\n                    dst_distance = self.stroke_length(self.points) / \\\n                        float(sample_points) * len(new_points)\n\n        # If this happens, we are into troubles...\n        if not len(new_points) == sample_points:\n            raise ValueError('Invalid number of strokes points; got '\n                             '%d while it should be %d' %\n                             (len(new_points), sample_points))\n\n        self.points = new_points\n        return True\n\n    def center_stroke(self, offset_x, offset_y):\n        '''Centers the stroke by offseting the points.'''\n        for point in self.points:\n            point.x -= offset_x\n            point.y -= offset_y\n\n\nclass Gesture:\n    '''A python implementation of a gesture recognition algorithm by\n    Oleg Dopertchouk: http://www.gamedev.net/reference/articles/article2039.asp\n\n    Implemented by Jeiel Aranal (chemikhazi@gmail.com),\n    released into the public domain.\n    '''\n\n    # Tolerance for evaluation using the '==' operator\n    DEFAULT_TOLERANCE = 0.1\n\n    def __init__(self, tolerance=None):\n        '''\n        Gesture([tolerance=float])\n        Creates a new gesture with an optional matching tolerance value.\n        '''\n        self.width = 0.\n        self.height = 0.\n        self.gesture_product = 0.\n        self.strokes = list()\n        if tolerance is None:\n            self.tolerance = Gesture.DEFAULT_TOLERANCE\n        else:\n            self.tolerance = tolerance\n\n    def _scale_gesture(self):\n        ''' Scales down the gesture to a unit of 1.'''\n        # map() creates a list of min/max coordinates of the strokes\n        # in the gesture and min()/max() pulls the lowest/highest value\n        min_x = min([stroke.min_x for stroke in self.strokes])\n        max_x = max([stroke.max_x for stroke in self.strokes])\n        min_y = min([stroke.min_y for stroke in self.strokes])\n        max_y = max([stroke.max_y for stroke in self.strokes])\n        x_len = max_x - min_x\n        self.width = x_len\n        y_len = max_y - min_y\n        self.height = y_len\n        scale_factor = max(x_len, y_len)\n        if scale_factor <= 0.0:\n            return False\n        scale_factor = 1.0 / scale_factor\n        for stroke in self.strokes:\n            stroke.scale_stroke(scale_factor)\n        return True\n\n    def _center_gesture(self):\n        ''' Centers the Gesture.points of the gesture.'''\n        total_x = 0.0\n        total_y = 0.0\n        total_points = 0\n\n        for stroke in self.strokes:\n            # adds up all the points inside the stroke\n            stroke_y = sum([pt.y for pt in stroke.points])\n            stroke_x = sum([pt.x for pt in stroke.points])\n            total_y += stroke_y\n            total_x += stroke_x\n            total_points += len(stroke.points)\n        if total_points == 0:\n            return False\n        # Average to get the offset\n        total_x /= total_points\n        total_y /= total_points\n        # Apply the offset to the strokes\n        for stroke in self.strokes:\n            stroke.center_stroke(total_x, total_y)\n        return True\n\n    def add_stroke(self, point_list=None):\n        '''Adds a stroke to the gesture and returns the Stroke instance.\n           Optional point_list argument is a list of the mouse points for\n           the stroke.\n        '''\n        self.strokes.append(GestureStroke())\n        if isinstance(point_list, list) or isinstance(point_list, tuple):\n            for point in point_list:\n                if isinstance(point, GesturePoint):\n                    self.strokes[-1].points.append(point)\n                elif isinstance(point, list) or isinstance(point, tuple):\n                    if len(point) != 2:\n                        raise ValueError(\"Stroke entry must have 2 values max\")\n                    self.strokes[-1].add_point(point[0], point[1])\n                else:\n                    raise TypeError(\"The point list should either be \"\n                                    \"tuples of x and y or a list of \"\n                                    \"GesturePoint objects\")\n        elif point_list is not None:\n            raise ValueError(\"point_list should be a tuple/list\")\n        return self.strokes[-1]\n\n    def normalize(self, stroke_samples=32):\n        '''Runs the gesture normalization algorithm and calculates the dot\n        product with self.\n        '''\n        if not self._scale_gesture() or not self._center_gesture():\n            self.gesture_product = False\n            return False\n        for stroke in self.strokes:\n            stroke.normalize_stroke(stroke_samples)\n        self.gesture_product = self.dot_product(self)\n\n    def get_rigid_rotation(self, dstpts):\n        '''\n        Extract the rotation to apply to a group of points to minimize the\n        distance to a second group of points. The two groups of points are\n        assumed to be centered. This is a simple version that just picks\n        an angle based on the first point of the gesture.\n        '''\n        if len(self.strokes) < 1 or len(self.strokes[0].points) < 1:\n            return 0\n        if len(dstpts.strokes) < 1 or len(dstpts.strokes[0].points) < 1:\n            return 0\n        p = dstpts.strokes[0].points[0]\n        target = Vector([p.x, p.y])\n        source = Vector([p.x, p.y])\n        return source.angle(target)\n\n    def dot_product(self, comparison_gesture):\n        ''' Calculates the dot product of the gesture with another gesture.'''\n        if len(comparison_gesture.strokes) != len(self.strokes):\n            return -1\n        if getattr(comparison_gesture, 'gesture_product', True) is False or \\\n           getattr(self, 'gesture_product', True) is False:\n            return -1\n        dot_product = 0.0\n        for stroke_index, (my_stroke, cmp_stroke) in enumerate(\n                list(zip(self.strokes, comparison_gesture.strokes))):\n            for pt_index, (my_point, cmp_point) in enumerate(\n                    list(zip(my_stroke.points, cmp_stroke.points))):\n                dot_product += (my_point.x * cmp_point.x +\n                                my_point.y * cmp_point.y)\n        return dot_product\n\n    def rotate(self, angle):\n        g = Gesture()\n        for stroke in self.strokes:\n            tmp = []\n            for j in stroke.points:\n                v = Vector([j.x, j.y]).rotate(angle)\n                tmp.append(v)\n            g.add_stroke(tmp)\n        g.gesture_product = g.dot_product(g)\n        return g\n\n    def get_score(self, comparison_gesture, rotation_invariant=True):\n        ''' Returns the matching score of the gesture against another gesture.\n        '''\n        if isinstance(comparison_gesture, Gesture):\n            if rotation_invariant:\n                # get orientation\n                angle = self.get_rigid_rotation(comparison_gesture)\n\n                # rotate the gesture to be in the same frame.\n                comparison_gesture = comparison_gesture.rotate(angle)\n\n            # this is the normal \"orientation\" code.\n            score = self.dot_product(comparison_gesture)\n            if score <= 0:\n                return score\n            score /= math.sqrt(\n                self.gesture_product * comparison_gesture.gesture_product)\n            return score\n\n    def __eq__(self, comparison_gesture):\n        ''' Allows easy comparisons between gesture instances.'''\n        if isinstance(comparison_gesture, Gesture):\n            # If the gestures don't have the same number of strokes, its\n            # definitely not the same gesture\n            score = self.get_score(comparison_gesture)\n            if (score > (1.0 - self.tolerance) and\n                    score < (1.0 + self.tolerance)):\n                return True\n            else:\n                return False\n        else:\n            return NotImplemented\n\n    def __ne__(self, comparison_gesture):\n        result = self.__eq__(comparison_gesture)\n        if result is NotImplemented:\n            return result\n        else:\n            return not result\n\n    def __lt__(self, comparison_gesture):\n        raise TypeError(\"Gesture cannot be evaluated with <\")\n\n    def __gt__(self, comparison_gesture):\n        raise TypeError(\"Gesture cannot be evaluated with >\")\n\n    def __le__(self, comparison_gesture):\n        raise TypeError(\"Gesture cannot be evaluated with <=\")\n\n    def __ge__(self, comparison_gesture):\n        raise TypeError(\"Gesture cannot be evaluated with >=\")\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/__init__.py",
    "content": "'''\nGraphics\n========\n\nThis package assembles many low level functions used for drawing. The whole\ngraphics package is compatible with OpenGL ES 2.0 and has many rendering\noptimizations.\n\nThe basics\n----------\n\nFor drawing on a screen, you will need :\n\n    1. a :class:`~kivy.graphics.instructions.Canvas` object.\n    2. :class:`~kivy.graphics.instructions.Instruction` objects.\n\nEach :class:`~kivy.uix.widget.Widget`\nin Kivy already has a :class:`Canvas` by default. When you create\na widget, you can create all the instructions needed for drawing. If\n`self` is your current widget, you can do::\n\n    from kivy.graphics import *\n    with self.canvas:\n        # Add a red color\n        Color(1., 0, 0)\n\n        # Add a rectangle\n        Rectangle(pos=(10, 10), size=(500, 500))\n\nThe instructions :class:`Color` and :class:`Rectangle` are automaticly added to\nthe canvas object and will be used when the window is drawn.\n\n.. note::\n\n    Kivy drawing instructions are not automatically relative to the widgets\n    position or size. You therefore you need to consider these factors when\n    drawing. In order to make your drawing instructions relative to the widget,\n    the instructions need either to be\n    declared in the :mod:`KvLang <kivy.lang>` or bound to pos and size changes.\n    Please see :ref:`adding_widget_background` for more detail.\n\nGL Reloading mechanism\n----------------------\n\n.. versionadded:: 1.2.0\n\nDuring the lifetime of the application, the OpenGL context might be lost. This\nhappens:\n\n- when the window is resized on MacOSX or the Windows platform and you're\n  using pygame as a window provider. This is due to SDL 1.2. In the SDL 1.2\n  design, it needs to recreate a GL context everytime the window is\n  resized. This was fixed in SDL 1.3 but pygame is not yet available on it\n  by default.\n\n- when Android releases the app resources: when your application goes to the\n  background, Android might reclaim your opengl context to give the\n  resource to another app. When the user switches back to your application, a\n  newly created gl context is given to your app.\n\nStarting from 1.2.0, we have introduced a mechanism for reloading all the\ngraphics resources using the GPU: Canvas, FBO, Shader, Texture, VBO,\nand VertexBatch:\n\n- VBO and VertexBatch are constructed by our graphics instructions. We have all\n  the data needed to reconstruct when reloading.\n\n- Shader: same as VBO, we store the source and values used in the\n  shader so we are able to recreate the vertex/fragment/program.\n\n- Texture: if the texture has a source (an image file or atlas), the image\n  is reloaded from the source and reuploaded to the GPU.\n\nYou should cover these cases yourself:\n\n- Textures without a source: if you manually created a texture and manually\n  blit data / a buffer to it, you must handle the reloading yourself. Check the\n  :doc:`api-kivy.graphics.texture` to learn how to manage that case. (The text\n  rendering already generates the texture and handles the reloading. You\n  don't need to reload text yourself.)\n\n- FBO: if you added / removed / drew things multiple times on the FBO, we\n  can't reload it. We don't keep a history of the instructions put on it.\n  As for textures without a source, check the :doc:`api-kivy.graphics.fbo` to\n  learn how to manage that case.\n\n'''\n\nfrom kivy.graphics.instructions import Callback, Canvas, CanvasBase, \\\n    ContextInstruction, Instruction, InstructionGroup, RenderContext, \\\n    VertexInstruction\nfrom kivy.graphics.context_instructions import BindTexture, Color, \\\n    PushState, ChangeState, PopState, MatrixInstruction, ApplyContextMatrix, \\\n    PopMatrix, PushMatrix, Rotate, Scale, Translate, LoadIdentity, \\\n    UpdateNormalMatrix, gl_init_resources\nfrom kivy.graphics.vertex_instructions import Bezier, BorderImage, Ellipse, \\\n    GraphicException, Line, Mesh, Point, Quad, Rectangle, Triangle\nfrom kivy.graphics.stencil_instructions import StencilPop, StencilPush, \\\n    StencilUse, StencilUnUse\nfrom kivy.graphics.gl_instructions import ClearColor, ClearBuffers\nfrom kivy.graphics.fbo import Fbo\n\n# very hacky way to avoid pyflakes warning...\n__all__ = (Bezier.__name__, BindTexture.__name__, BorderImage.__name__,\n           Callback.__name__, Canvas.__name__, CanvasBase.__name__,\n           Color.__name__, ContextInstruction.__name__,\n           Ellipse.__name__, Fbo.__name__, GraphicException.__name__,\n           Instruction.__name__, InstructionGroup.__name__,\n           Line.__name__, MatrixInstruction.__name__, Mesh.__name__,\n           Point.__name__, PopMatrix.__name__, PushMatrix.__name__,\n           Quad.__name__, Rectangle.__name__, RenderContext.__name__,\n           Rotate.__name__, Scale.__name__, StencilPop.__name__,\n           StencilPush.__name__, StencilUse.__name__,\n           StencilUnUse.__name__, Translate.__name__, Triangle.__name__,\n           VertexInstruction.__name__, ClearColor.__name__,\n           ClearBuffers.__name__, gl_init_resources.__name__,\n           PushState.__name__, ChangeState.__name__, PopState.__name__,\n           ApplyContextMatrix.__name__, UpdateNormalMatrix.__name__,\n           LoadIdentity.__name__)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/buffer.pxd",
    "content": "cdef class Buffer:\n    cdef void *data\n    cdef int *l_free\n    cdef int i_free\n    cdef long block_size\n    cdef long block_count\n\n    cdef void clear(self)\n    cdef void grow(self, long block_count)\n    cdef void add(self, void *blocks, unsigned short *indices, int count)\n    cdef void remove(self, unsigned short *indices, int count)\n    cdef int count(self)\n    cdef long size(self)\n    cdef void *pointer(self)\n    cdef void *offset_pointer(self, int offset)\n    cdef void update(self, int index, void* blocks, int count)\n\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/c_opengl.pxd",
    "content": "include \"config.pxi\"\n\ncdef extern from \"gl_redirect.h\":\n\n    ctypedef void               GLvoid\n    ctypedef char               GLchar\n    ctypedef unsigned int       GLenum\n    ctypedef unsigned char      GLboolean\n    ctypedef unsigned int       GLbitfield\n    ctypedef short              GLshort\n    ctypedef int                GLint\n    ctypedef int                GLsizei\n    ctypedef unsigned short     GLushort\n    ctypedef unsigned int       GLuint\n\n    #FIXME: figure out correct cross platform tydefs\n    #ctypedef khronos_float_t  GLfloat\n    #ctypedef khronos_float_t  GLclampf\n    #ctypedef khronos_int32_t  GLfixed\n    #ctypedef khronos_intptr_t GLintptr\n    #ctypedef khronos_ssize_t  GLsizeiptr\n    ctypedef signed char        GLbyte\n    ctypedef unsigned char      GLubyte\n    ctypedef float              GLfloat\n    ctypedef float              GLclampf\n    ctypedef int                GLfixed\n    ctypedef signed long int    GLintptr\n    ctypedef signed long int    GLsizeiptr\n\n\n    #int GL_ES_VERSION_2_0\n\n    int GL_DEPTH_BUFFER_BIT\n    int GL_STENCIL_BUFFER_BIT\n    int GL_COLOR_BUFFER_BIT\n\n    int GL_FALSE\n    int GL_TRUE\n\n    int GL_POINTS\n    int GL_LINES\n    int GL_LINE_LOOP\n    int GL_LINE_STRIP\n    int GL_TRIANGLES\n    int GL_TRIANGLE_STRIP\n    int GL_TRIANGLE_FAN\n\n    int GL_ZERO\n    int GL_ONE\n    int GL_SRC_COLOR\n    int GL_ONE_MINUS_SRC_COLOR\n    int GL_SRC_ALPHA\n    int GL_ONE_MINUS_SRC_ALPHA\n    int GL_DST_ALPHA\n    int GL_ONE_MINUS_DST_ALPHA\n\n    int GL_DST_COLOR\n    int GL_ONE_MINUS_DST_COLOR\n    int GL_SRC_ALPHA_SATURATE\n\n    int GL_FUNC_ADD\n    int GL_BLEND_EQUATION\n    int GL_BLEND_EQUATION_RGB\n    int GL_BLEND_EQUATION_ALPHA\n\n    int GL_FUNC_SUBTRACT\n    int GL_FUNC_REVERSE_SUBTRACT\n\n    int GL_BLEND_DST_RGB\n    int GL_BLEND_SRC_RGB\n    int GL_BLEND_DST_ALPHA\n    int GL_BLEND_SRC_ALPHA\n    int GL_ANT_COLOR\n    int GL_ONE_MINUS_ANT_COLOR\n    int GL_ANT_ALPHA\n    int GL_ONE_MINUS_ANT_ALPHA\n    int GL_BLEND_COLOR\n\n    int GL_ARRAY_BUFFER\n    int GL_ELEMENT_ARRAY_BUFFER\n    int GL_ARRAY_BUFFER_BINDING\n    int GL_ELEMENT_ARRAY_BUFFER_BINDING\n\n    int GL_STREAM_DRAW\n    int GL_STATIC_DRAW\n    int GL_DYNAMIC_DRAW\n\n    int GL_BUFFER_SIZE\n    int GL_BUFFER_USAGE\n\n    int GL_CURRENT_VERTEX_ATTRIB\n\n    int GL_FRONT\n    int GL_BACK\n    int GL_FRONT_AND_BACK\n\n    int GL_TEXTURE_2D\n    int GL_CULL_FACE\n    int GL_BLEND\n    int GL_DITHER\n    int GL_STENCIL_TEST\n    int GL_DEPTH_TEST\n    int GL_SCISSOR_TEST\n    int GL_POLYGON_OFFSET_FILL\n    int GL_SAMPLE_ALPHA_TO_COVERAGE\n    int GL_SAMPLE_COVERAGE\n\n    int GL_NO_ERROR\n    int GL_INVALID_ENUM\n    int GL_INVALID_VALUE\n    int GL_INVALID_OPERATION\n    int GL_OUT_OF_MEMORY\n\n    int GL_CW\n    int GL_CCW\n\n    int GL_LINE_WIDTH\n    int GL_ALIASED_POINT_SIZE_RANGE\n    int GL_ALIASED_LINE_WIDTH_RANGE\n    int GL_CULL_FACE_MODE\n    int GL_FRONT_FACE\n    int GL_DEPTH_RANGE\n    int GL_DEPTH_WRITEMASK\n    int GL_DEPTH_CLEAR_VALUE\n    int GL_DEPTH_FUNC\n    int GL_STENCIL_CLEAR_VALUE\n    int GL_STENCIL_FUNC\n    int GL_STENCIL_FAIL\n    int GL_STENCIL_PASS_DEPTH_FAIL\n    int GL_STENCIL_PASS_DEPTH_PASS\n    int GL_STENCIL_REF\n    int GL_STENCIL_VALUE_MASK\n    int GL_STENCIL_WRITEMASK\n    int GL_STENCIL_BACK_FUNC\n    int GL_STENCIL_BACK_FAIL\n    int GL_STENCIL_BACK_PASS_DEPTH_FAIL\n    int GL_STENCIL_BACK_PASS_DEPTH_PASS\n    int GL_STENCIL_BACK_REF\n    int GL_STENCIL_BACK_VALUE_MASK\n    int GL_STENCIL_BACK_WRITEMASK\n    int GL_VIEWPORT\n    int GL_SCISSOR_BOX\n\n    int GL_COLOR_CLEAR_VALUE\n    int GL_COLOR_WRITEMASK\n    int GL_UNPACK_ALIGNMENT\n    int GL_PACK_ALIGNMENT\n    int GL_MAX_TEXTURE_SIZE\n    int GL_MAX_VIEWPORT_DIMS\n    int GL_SUBPIXEL_BITS\n    int GL_RED_BITS\n    int GL_GREEN_BITS\n    int GL_BLUE_BITS\n    int GL_ALPHA_BITS\n    int GL_DEPTH_BITS\n    int GL_STENCIL_BITS\n    int GL_POLYGON_OFFSET_UNITS\n\n    int GL_POLYGON_OFFSET_FACTOR\n    int GL_TEXTURE_BINDING_2D\n    int GL_SAMPLE_BUFFERS\n    int GL_SAMPLES\n    int GL_SAMPLE_COVERAGE_VALUE\n    int GL_SAMPLE_COVERAGE_INVERT\n\n    int GL_NUM_COMPRESSED_TEXTURE_FORMATS\n    int GL_COMPRESSED_TEXTURE_FORMATS\n\n    int GL_DONT_CARE\n    int GL_FASTEST\n    int GL_NICEST\n\n    int GL_GENERATE_MIPMAP_HINT\n\n    int GL_BYTE\n    int GL_UNSIGNED_BYTE\n    int GL_SHORT\n    int GL_UNSIGNED_SHORT\n    int GL_INT\n    int GL_UNSIGNED_INT\n    int GL_FLOAT\n\n    int GL_DEPTH_COMPONENT\n    int GL_ALPHA\n    int GL_RGB\n    int GL_RGBA\n    int GL_LUMINANCE\n    int GL_LUMINANCE_ALPHA\n\n    int GL_UNSIGNED_SHORT_4_4_4_4\n    int GL_UNSIGNED_SHORT_5_5_5_1\n    int GL_UNSIGNED_SHORT_5_6_5\n\n    int GL_FRAGMENT_SHADER\n    int GL_VERTEX_SHADER\n    int GL_MAX_VERTEX_ATTRIBS\n    int GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS\n    int GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS\n    int GL_MAX_TEXTURE_IMAGE_UNITS\n    int GL_SHADER_TYPE\n    int GL_DELETE_STATUS\n    int GL_LINK_STATUS\n    int GL_VALIDATE_STATUS\n    int GL_ATTACHED_SHADERS\n    int GL_ACTIVE_UNIFORMS\n    int GL_ACTIVE_UNIFORM_MAX_LENGTH\n    int GL_ACTIVE_ATTRIBUTES\n    int GL_ACTIVE_ATTRIBUTE_MAX_LENGTH\n    int GL_SHADING_LANGUAGE_VERSION\n    int GL_CURRENT_PROGRAM\n\n    int GL_NEVER\n    int GL_LESS\n    int GL_EQUAL\n    int GL_LEQUAL\n    int GL_GREATER\n    int GL_NOTEQUAL\n    int GL_GEQUAL\n    int GL_ALWAYS\n\n    int GL_KEEP\n    int GL_REPLACE\n    int GL_INCR\n    int GL_DECR\n    int GL_INVERT\n    int GL_INCR_WRAP\n    int GL_DECR_WRAP\n\n    int GL_VENDOR\n    int GL_RENDERER\n    int GL_VERSION\n    int GL_EXTENSIONS\n\n    int GL_NEAREST\n    int GL_LINEAR\n\n    int GL_NEAREST_MIPMAP_NEAREST\n    int GL_LINEAR_MIPMAP_NEAREST\n    int GL_NEAREST_MIPMAP_LINEAR\n    int GL_LINEAR_MIPMAP_LINEAR\n\n    int GL_TEXTURE_MAG_FILTER\n    int GL_TEXTURE_MIN_FILTER\n    int GL_TEXTURE_WRAP_S\n    int GL_TEXTURE_WRAP_T\n\n    int GL_TEXTURE\n\n    int GL_TEXTURE_CUBE_MAP\n    int GL_TEXTURE_BINDING_CUBE_MAP\n    int GL_TEXTURE_CUBE_MAP_POSITIVE_X\n    int GL_TEXTURE_CUBE_MAP_NEGATIVE_X\n    int GL_TEXTURE_CUBE_MAP_POSITIVE_Y\n    int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y\n    int GL_TEXTURE_CUBE_MAP_POSITIVE_Z\n    int GL_TEXTURE_CUBE_MAP_NEGATIVE_Z\n    int GL_MAX_CUBE_MAP_TEXTURE_SIZE\n\n    int GL_TEXTURE0\n    int GL_TEXTURE1\n    int GL_TEXTURE2\n    int GL_TEXTURE3\n    int GL_TEXTURE4\n    int GL_TEXTURE5\n    int GL_TEXTURE6\n    int GL_TEXTURE7\n    int GL_TEXTURE8\n    int GL_TEXTURE9\n    int GL_TEXTURE10\n    int GL_TEXTURE11\n    int GL_TEXTURE12\n    int GL_TEXTURE13\n    int GL_TEXTURE14\n    int GL_TEXTURE15\n    int GL_TEXTURE16\n    int GL_TEXTURE17\n    int GL_TEXTURE18\n    int GL_TEXTURE19\n    int GL_TEXTURE20\n    int GL_TEXTURE21\n    int GL_TEXTURE22\n    int GL_TEXTURE23\n    int GL_TEXTURE24\n    int GL_TEXTURE25\n    int GL_TEXTURE26\n    int GL_TEXTURE27\n    int GL_TEXTURE28\n    int GL_TEXTURE29\n    int GL_TEXTURE30\n    int GL_TEXTURE31\n    int GL_ACTIVE_TEXTURE\n\n\n    int GL_REPEAT\n    int GL_CLAMP_TO_EDGE\n    int GL_MIRRORED_REPEAT\n\n    int GL_FLOAT_VEC2\n    int GL_FLOAT_VEC3\n    int GL_FLOAT_VEC4\n    int GL_INT_VEC2\n    int GL_INT_VEC3\n    int GL_INT_VEC4\n    int GL_BOOL\n    int GL_BOOL_VEC2\n    int GL_BOOL_VEC3\n    int GL_BOOL_VEC4\n    int GL_FLOAT_MAT2\n    int GL_FLOAT_MAT3\n    int GL_FLOAT_MAT4\n    int GL_SAMPLER_2D\n    int GL_SAMPLER_CUBE\n\n    int GL_VERTEX_ATTRIB_ARRAY_ENABLED\n    int GL_VERTEX_ATTRIB_ARRAY_SIZE\n    int GL_VERTEX_ATTRIB_ARRAY_STRIDE\n    int GL_VERTEX_ATTRIB_ARRAY_TYPE\n    int GL_VERTEX_ATTRIB_ARRAY_NORMALIZED\n    int GL_VERTEX_ATTRIB_ARRAY_POINTER\n    int GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING\n\n    int GL_COMPILE_STATUS\n    int GL_INFO_LOG_LENGTH\n    int GL_SHADER_SOURCE_LENGTH\n\n    int GL_SHADER_BINARY_FORMATS\n\n    int GL_FRAMEBUFFER\n    int GL_RENDERBUFFER\n\n    int GL_RGBA4\n    int GL_RGB5_A1\n    int GL_RGB565\n    int GL_DEPTH_COMPONENT16\n    int GL_STENCIL_INDEX8\n\n    int GL_RENDERBUFFER_WIDTH\n    int GL_RENDERBUFFER_HEIGHT\n    int GL_RENDERBUFFER_INTERNAL_FORMAT\n    int GL_RENDERBUFFER_RED_SIZE\n    int GL_RENDERBUFFER_GREEN_SIZE\n    int GL_RENDERBUFFER_BLUE_SIZE\n    int GL_RENDERBUFFER_ALPHA_SIZE\n    int GL_RENDERBUFFER_DEPTH_SIZE\n    int GL_RENDERBUFFER_STENCIL_SIZE\n\n    int GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE\n    int GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME\n    int GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL\n    int GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE\n\n    int GL_COLOR_ATTACHMENT0\n    int GL_DEPTH_ATTACHMENT\n    int GL_STENCIL_ATTACHMENT\n\n    int GL_NONE\n\n    int GL_FRAMEBUFFER_COMPLETE\n    int GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT\n    int GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT\n    int GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS\n    int GL_FRAMEBUFFER_UNSUPPORTED\n\n    int GL_FRAMEBUFFER_BINDING\n    int GL_RENDERBUFFER_BINDING\n    int GL_MAX_RENDERBUFFER_SIZE\n\n    int GL_INVALID_FRAMEBUFFER_OPERATION\n\n    IF USE_OPENGL_ES2:\n        int GL_FIXED\n        int GL_MAX_VERTEX_UNIFORM_VECTORS\n        int GL_MAX_VARYING_VECTORS\n        int GL_MAX_FRAGMENT_UNIFORM_VECTORS\n        int GL_IMPLEMENTATION_COLOR_READ_TYPE\n        int GL_IMPLEMENTATION_COLOR_READ_FORMAT\n        int GL_SHADER_COMPILER\n        int GL_NUM_SHADER_BINARY_FORMATS\n        int GL_LOW_FLOAT\n        int GL_MEDIUM_FLOAT\n        int GL_HIGH_FLOAT\n        int GL_LOW_INT\n        int GL_MEDIUM_INT\n        int GL_HIGH_INT\n\n    cdef void   glActiveTexture(GLenum texture) nogil\n    cdef void   glAttachShader(GLuint program, GLuint shader) nogil\n    cdef void   glBindAttribLocation(GLuint program, GLuint index,  GLchar* name) nogil\n    cdef void   glBindBuffer(GLenum target, GLuint buffer) nogil\n    cdef void   glBindFramebuffer(GLenum target, GLuint framebuffer) nogil\n    cdef void   glBindRenderbuffer(GLenum target, GLuint renderbuffer) nogil\n    cdef void   glBindTexture(GLenum target, GLuint texture) nogil\n    cdef void   glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) nogil\n    cdef void   glBlendEquation( GLenum mode ) nogil\n    cdef void   glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) nogil\n    cdef void   glBlendFunc(GLenum sfactor, GLenum dfactor) nogil\n    cdef void   glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) nogil\n    cdef void   glBufferData(GLenum target, GLsizeiptr size,  GLvoid* data, GLenum usage) nogil\n    cdef void   glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size,  GLvoid* data) nogil\n    cdef GLenum glCheckFramebufferStatus(GLenum target) nogil\n    cdef void   glClear(GLbitfield mask) nogil\n    cdef void   glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) nogil\n    cdef void   glClearDepthf(GLclampf depth) nogil\n    cdef void   glClearStencil(GLint s) nogil\n    cdef void   glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) nogil\n    cdef void   glCompileShader(GLuint shader) nogil\n    cdef void   glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize,  GLvoid* data) nogil\n    cdef void   glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize,  GLvoid* data) nogil\n    cdef void   glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) nogil\n    cdef void   glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) nogil\n    cdef GLuint glCreateProgram() nogil\n    cdef GLuint glCreateShader(GLenum type) nogil\n    cdef void   glCullFace(GLenum mode) nogil\n    cdef void   glDeleteBuffers(GLsizei n,  GLuint* buffers) nogil\n    cdef void   glDeleteFramebuffers(GLsizei n,  GLuint* framebuffers) nogil\n    cdef void   glDeleteProgram(GLuint program) nogil\n    cdef void   glDeleteRenderbuffers(GLsizei n,  GLuint* renderbuffers) nogil\n    cdef void   glDeleteShader(GLuint shader) nogil\n    cdef void   glDeleteTextures(GLsizei n,  GLuint* textures) nogil\n    cdef void   glDepthFunc(GLenum func) nogil\n    cdef void   glDepthMask(GLboolean flag) nogil\n    cdef void   glDepthRangef(GLclampf zNear, GLclampf zFar) nogil\n    cdef void   glDetachShader(GLuint program, GLuint shader) nogil\n    cdef void   glDisable(GLenum cap) nogil\n    cdef void   glDisableVertexAttribArray(GLuint index) nogil\n    cdef void   glDrawArrays(GLenum mode, GLint first, GLsizei count) nogil\n    cdef void   glDrawElements(GLenum mode, GLsizei count, GLenum type,  GLvoid* indices) nogil\n    cdef void   glEnable(GLenum cap) nogil\n    cdef void   glEnableVertexAttribArray(GLuint index) nogil\n    cdef void   glFinish() nogil\n    cdef void   glFlush() nogil\n    cdef void   glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) nogil\n    cdef void   glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) nogil\n    cdef void   glFrontFace(GLenum mode) nogil\n    cdef void   glGenBuffers(GLsizei n, GLuint* buffers) nogil\n    cdef void   glGenerateMipmap(GLenum target) nogil\n    cdef void   glGenFramebuffers(GLsizei n, GLuint* framebuffers) nogil\n    cdef void   glGenRenderbuffers(GLsizei n, GLuint* renderbuffers) nogil\n    cdef void   glGenTextures(GLsizei n, GLuint* textures) nogil\n    cdef void   glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) nogil\n    cdef void   glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) nogil\n    cdef void   glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) nogil\n    cdef int    glGetAttribLocation(GLuint program,  GLchar* name) nogil\n    cdef void   glGetBooleanv(GLenum pname, GLboolean* params) nogil\n    cdef void   glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params) nogil\n    cdef GLenum glGetError() nogil\n    cdef void   glGetFloatv(GLenum pname, GLfloat* params) nogil\n    cdef void   glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params) nogil\n    cdef void   glGetIntegerv(GLenum pname, GLint* params) nogil\n    cdef void   glGetProgramiv(GLuint program, GLenum pname, GLint* params) nogil\n    cdef void   glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog) nogil\n    cdef void   glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) nogil\n    cdef void   glGetShaderiv(GLuint shader, GLenum pname, GLint* params) nogil\n    cdef void   glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog) nogil\n    #cdef void   glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) nogil\n    cdef void   glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) nogil\n    cdef   GLubyte*  glGetString(GLenum name) nogil\n    cdef void   glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) nogil\n    cdef void   glGetTexParameteriv(GLenum target, GLenum pname, GLint* params) nogil\n    cdef void   glGetUniformfv(GLuint program, GLint location, GLfloat* params) nogil\n    cdef void   glGetUniformiv(GLuint program, GLint location, GLint* params) nogil\n    cdef int    glGetUniformLocation(GLuint program,  GLchar* name) nogil\n    cdef void   glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) nogil\n    cdef void   glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params) nogil\n    cdef void   glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer) nogil\n    cdef void   glHint(GLenum target, GLenum mode) nogil\n    cdef GLboolean  glIsBuffer(GLuint buffer) nogil\n    cdef GLboolean  glIsEnabled(GLenum cap) nogil\n    cdef GLboolean  glIsFramebuffer(GLuint framebuffer) nogil\n    cdef GLboolean  glIsProgram(GLuint program) nogil\n    cdef GLboolean  glIsRenderbuffer(GLuint renderbuffer) nogil\n    cdef GLboolean  glIsShader(GLuint shader) nogil\n    cdef GLboolean  glIsTexture(GLuint texture) nogil\n    cdef void  glLineWidth(GLfloat width) nogil\n    cdef void  glLinkProgram(GLuint program) nogil\n    cdef void  glPixelStorei(GLenum pname, GLint param) nogil\n    cdef void  glPolygonOffset(GLfloat factor, GLfloat units) nogil\n    cdef void  glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) nogil\n    # XXX This one is commented out because a) it's not necessary and\n    #\t    \t\t\t\tb) it's breaking on OSX for some reason\n    #cdef void  glReleaseShaderCompiler() nogil\n    cdef void  glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) nogil\n    cdef void  glSampleCoverage(GLclampf value, GLboolean invert) nogil\n    cdef void  glScissor(GLint x, GLint y, GLsizei width, GLsizei height) nogil\n    #cdef void  glShaderBinary(GLsizei n,  GLuint* shaders, GLenum binaryformat,  GLvoid* binary, GLsizei length) nogil\n    cdef void  glShaderSource(GLuint shader, GLsizei count,  GLchar** string,  GLint* length) nogil\n    cdef void  glStencilFunc(GLenum func, GLint ref, GLuint mask) nogil\n    cdef void  glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) nogil\n    cdef void  glStencilMask(GLuint mask) nogil\n    cdef void  glStencilMaskSeparate(GLenum face, GLuint mask) nogil\n    cdef void  glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) nogil\n    cdef void  glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) nogil\n    cdef void  glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type,  GLvoid* pixels) nogil\n    cdef void  glTexParameterf(GLenum target, GLenum pname, GLfloat param) nogil\n    cdef void  glTexParameterfv(GLenum target, GLenum pname,  GLfloat* params) nogil\n    cdef void  glTexParameteri(GLenum target, GLenum pname, GLint param) nogil\n    cdef void  glTexParameteriv(GLenum target, GLenum pname,  GLint* params) nogil\n    cdef void  glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,  GLvoid* pixels) nogil\n    cdef void  glUniform1f(GLint location, GLfloat x) nogil\n    cdef void  glUniform1fv(GLint location, GLsizei count,  GLfloat* v) nogil\n    cdef void  glUniform1i(GLint location, GLint x) nogil\n    cdef void  glUniform1iv(GLint location, GLsizei count,  GLint* v) nogil\n    cdef void  glUniform2f(GLint location, GLfloat x, GLfloat y) nogil\n    cdef void  glUniform2fv(GLint location, GLsizei count,  GLfloat* v) nogil\n    cdef void  glUniform2i(GLint location, GLint x, GLint y) nogil\n    cdef void  glUniform2iv(GLint location, GLsizei count,  GLint* v) nogil\n    cdef void  glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) nogil\n    cdef void  glUniform3fv(GLint location, GLsizei count,  GLfloat* v) nogil\n    cdef void  glUniform3i(GLint location, GLint x, GLint y, GLint z) nogil\n    cdef void  glUniform3iv(GLint location, GLsizei count,  GLint* v) nogil\n    cdef void  glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) nogil\n    cdef void  glUniform4fv(GLint location, GLsizei count,  GLfloat* v) nogil\n    cdef void  glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) nogil\n    cdef void  glUniform4iv(GLint location, GLsizei count,  GLint* v) nogil\n    cdef void  glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose,  GLfloat* value) nogil\n    cdef void  glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose,  GLfloat* value) nogil\n    cdef void  glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose,  GLfloat* value) nogil\n    cdef void  glUseProgram(GLuint program) nogil\n    cdef void  glValidateProgram(GLuint program) nogil\n    cdef void  glVertexAttrib1f(GLuint indx, GLfloat x) nogil\n    cdef void  glVertexAttrib1fv(GLuint indx,  GLfloat* values) nogil\n    cdef void  glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) nogil\n    cdef void  glVertexAttrib2fv(GLuint indx,  GLfloat* values) nogil\n    cdef void  glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z) nogil\n    cdef void  glVertexAttrib3fv(GLuint indx,  GLfloat* values) nogil\n    cdef void  glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) nogil\n    cdef void  glVertexAttrib4fv(GLuint indx,  GLfloat* values) nogil\n    cdef void  glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride,  GLvoid* ptr) nogil\n    cdef void  glViewport(GLint x, GLint y, GLsizei width, GLsizei height) nogil\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/c_opengl_debug.pxd",
    "content": "ctypedef void               GLvoid\nctypedef char               GLchar\nctypedef unsigned int       GLenum\nctypedef unsigned char      GLboolean\nctypedef unsigned int       GLbitfield\nctypedef short              GLshort\nctypedef int                GLint\nctypedef int                GLsizei\nctypedef unsigned short     GLushort\nctypedef unsigned int       GLuint\nctypedef signed char        GLbyte\nctypedef unsigned char      GLubyte\nctypedef float              GLfloat\nctypedef float              GLclampf\nctypedef int                GLfixed\nctypedef signed long int    GLintptr\nctypedef signed long int    GLsizeiptr\n\ncdef void   glActiveTexture (GLenum texture) with gil\ncdef void   glAttachShader (GLuint program, GLuint shader) with gil\ncdef void   glBindAttribLocation (GLuint program, GLuint index,  GLchar* name) with gil\ncdef void   glBindBuffer (GLenum target, GLuint buffer) with gil\ncdef void   glBindFramebuffer (GLenum target, GLuint framebuffer) with gil\ncdef void   glBindRenderbuffer (GLenum target, GLuint renderbuffer) with gil\ncdef void   glBindTexture (GLenum target, GLuint texture) with gil\ncdef void   glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) with gil\ncdef void   glBlendEquation ( GLenum mode ) with gil\ncdef void   glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha) with gil\ncdef void   glBlendFunc (GLenum sfactor, GLenum dfactor) with gil\ncdef void   glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) with gil\ncdef void   glBufferData (GLenum target, GLsizeiptr size,  GLvoid* data, GLenum usage) with gil\ncdef void   glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size,  GLvoid* data) with gil\ncdef GLenum glCheckFramebufferStatus (GLenum target) with gil\ncdef void   glClear (GLbitfield mask) with gil\ncdef void   glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) with gil\n# crash on android platform\n#cdef void   glClearDepthf (GLclampf depth) with gil\ncdef void   glClearStencil (GLint s) with gil\ncdef void   glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) with gil\ncdef void   glCompileShader (GLuint shader) with gil\ncdef void   glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize,  GLvoid* data) with gil\ncdef void   glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize,  GLvoid* data) with gil\ncdef void   glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) with gil\ncdef void   glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) with gil\ncdef GLuint glCreateProgram () with gil\ncdef GLuint glCreateShader (GLenum type) with gil\ncdef void   glCullFace (GLenum mode) with gil\ncdef void   glDeleteBuffers (GLsizei n,  GLuint* buffers) with gil\ncdef void   glDeleteFramebuffers (GLsizei n,  GLuint* framebuffers) with gil\ncdef void   glDeleteProgram (GLuint program) with gil\ncdef void   glDeleteRenderbuffers (GLsizei n,  GLuint* renderbuffers) with gil\ncdef void   glDeleteShader (GLuint shader) with gil\ncdef void   glDeleteTextures (GLsizei n,  GLuint* textures) with gil\ncdef void   glDepthFunc (GLenum func) with gil\ncdef void   glDepthMask (GLboolean flag) with gil\n# crash on android platform\n#cdef void   glDepthRangef (GLclampf zNear, GLclampf zFar) with gil\ncdef void   glDetachShader (GLuint program, GLuint shader) with gil\ncdef void   glDisable (GLenum cap) with gil\ncdef void   glDisableVertexAttribArray (GLuint index) with gil\ncdef void   glDrawArrays (GLenum mode, GLint first, GLsizei count) with gil\ncdef void   glDrawElements (GLenum mode, GLsizei count, GLenum type,  GLvoid* indices) with gil\ncdef void   glEnable (GLenum cap) with gil\ncdef void   glEnableVertexAttribArray (GLuint index) with gil\ncdef void   glFinish () with gil\ncdef void   glFlush () with gil\ncdef void   glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) with gil\ncdef void   glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) with gil\ncdef void   glFrontFace (GLenum mode) with gil\ncdef void   glGenBuffers (GLsizei n, GLuint* buffers) with gil\ncdef void   glGenerateMipmap (GLenum target) with gil\ncdef void   glGenFramebuffers (GLsizei n, GLuint* framebuffers) with gil\ncdef void   glGenRenderbuffers (GLsizei n, GLuint* renderbuffers) with gil\ncdef void   glGenTextures (GLsizei n, GLuint* textures) with gil\ncdef void   glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) with gil\ncdef void   glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) with gil\ncdef void   glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) with gil\ncdef int    glGetAttribLocation (GLuint program,  GLchar* name) with gil\ncdef void   glGetBooleanv (GLenum pname, GLboolean* params) with gil\ncdef void   glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params) with gil\ncdef GLenum glGetError () with gil\ncdef void   glGetFloatv (GLenum pname, GLfloat* params) with gil\ncdef void   glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params) with gil\ncdef void   glGetIntegerv (GLenum pname, GLint* params) with gil\ncdef void   glGetProgramiv (GLuint program, GLenum pname, GLint* params) with gil\ncdef void   glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog) with gil\ncdef void   glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params) with gil\ncdef void   glGetShaderiv (GLuint shader, GLenum pname, GLint* params) with gil\ncdef void   glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog) with gil\n#cdef void   glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) with gil\ncdef void   glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) with gil\ncdef   GLubyte*  glGetString (GLenum name) with gil\ncdef void   glGetTexParameterfv (GLenum target, GLenum pname, GLfloat* params) with gil\ncdef void   glGetTexParameteriv (GLenum target, GLenum pname, GLint* params) with gil\ncdef void   glGetUniformfv (GLuint program, GLint location, GLfloat* params) with gil\ncdef void   glGetUniformiv (GLuint program, GLint location, GLint* params) with gil\ncdef int    glGetUniformLocation (GLuint program,  GLchar* name) with gil\ncdef void   glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params) with gil\ncdef void   glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params) with gil\ncdef void   glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid** pointer) with gil\ncdef void   glHint (GLenum target, GLenum mode) with gil\ncdef GLboolean  glIsBuffer (GLuint buffer) with gil\ncdef GLboolean  glIsEnabled (GLenum cap) with gil\ncdef GLboolean  glIsFramebuffer (GLuint framebuffer) with gil\ncdef GLboolean  glIsProgram (GLuint program) with gil\ncdef GLboolean  glIsRenderbuffer (GLuint renderbuffer) with gil\ncdef GLboolean  glIsShader (GLuint shader) with gil\ncdef GLboolean  glIsTexture (GLuint texture) with gil\ncdef void  glLineWidth (GLfloat width) with gil\ncdef void  glLinkProgram (GLuint program) with gil\ncdef void  glPixelStorei (GLenum pname, GLint param) with gil\ncdef void  glPolygonOffset (GLfloat factor, GLfloat units) with gil\ncdef void  glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) with gil\n# XXX This one is commented out because a) it's not necessary and\n#\t    \t\t\t\tb) it's breaking on OSX for some reason\n#cdef void  glReleaseShaderCompiler () with gil\ncdef void  glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height) with gil\ncdef void  glSampleCoverage (GLclampf value, GLboolean invert) with gil\ncdef void  glScissor (GLint x, GLint y, GLsizei width, GLsizei height) with gil\n#cdef void  glShaderBinary (GLsizei n,  GLuint* shaders, GLenum binaryformat,  GLvoid* binary, GLsizei length) with gil\ncdef void  glShaderSource (GLuint shader, GLsizei count,  GLchar** string,  GLint* length) with gil\ncdef void  glStencilFunc (GLenum func, GLint ref, GLuint mask) with gil\ncdef void  glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask) with gil\ncdef void  glStencilMask (GLuint mask) with gil\ncdef void  glStencilMaskSeparate (GLenum face, GLuint mask) with gil\ncdef void  glStencilOp (GLenum fail, GLenum zfail, GLenum zpass) with gil\ncdef void  glStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass) with gil\ncdef void  glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type,  GLvoid* pixels) with gil\ncdef void  glTexParameterf (GLenum target, GLenum pname, GLfloat param) with gil\ncdef void  glTexParameterfv (GLenum target, GLenum pname,  GLfloat* params) with gil\ncdef void  glTexParameteri (GLenum target, GLenum pname, GLint param) with gil\ncdef void  glTexParameteriv (GLenum target, GLenum pname,  GLint* params) with gil\ncdef void  glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,  GLvoid* pixels) with gil\ncdef void  glUniform1f (GLint location, GLfloat x) with gil\ncdef void  glUniform1fv (GLint location, GLsizei count,  GLfloat* v) with gil\ncdef void  glUniform1i (GLint location, GLint x) with gil\ncdef void  glUniform1iv (GLint location, GLsizei count,  GLint* v) with gil\ncdef void  glUniform2f (GLint location, GLfloat x, GLfloat y) with gil\ncdef void  glUniform2fv (GLint location, GLsizei count,  GLfloat* v) with gil\ncdef void  glUniform2i (GLint location, GLint x, GLint y) with gil\ncdef void  glUniform2iv (GLint location, GLsizei count,  GLint* v) with gil\ncdef void  glUniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z) with gil\ncdef void  glUniform3fv (GLint location, GLsizei count,  GLfloat* v) with gil\ncdef void  glUniform3i (GLint location, GLint x, GLint y, GLint z) with gil\ncdef void  glUniform3iv (GLint location, GLsizei count,  GLint* v) with gil\ncdef void  glUniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) with gil\ncdef void  glUniform4fv (GLint location, GLsizei count,  GLfloat* v) with gil\ncdef void  glUniform4i (GLint location, GLint x, GLint y, GLint z, GLint w) with gil\ncdef void  glUniform4iv (GLint location, GLsizei count,  GLint* v) with gil\ncdef void  glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose,  GLfloat* value) with gil\ncdef void  glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose,  GLfloat* value) with gil\ncdef void  glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose,  GLfloat* value) with gil\ncdef void  glUseProgram (GLuint program) with gil\ncdef void  glValidateProgram (GLuint program) with gil\ncdef void  glVertexAttrib1f (GLuint indx, GLfloat x) with gil\ncdef void  glVertexAttrib1fv (GLuint indx,  GLfloat* values) with gil\ncdef void  glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y) with gil\ncdef void  glVertexAttrib2fv (GLuint indx,  GLfloat* values) with gil\ncdef void  glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z) with gil\ncdef void  glVertexAttrib3fv (GLuint indx,  GLfloat* values) with gil\ncdef void  glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) with gil\ncdef void  glVertexAttrib4fv (GLuint indx,  GLfloat* values) with gil\ncdef void  glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride,  GLvoid* ptr) with gil\ncdef void  glViewport (GLint x, GLint y, GLsizei width, GLsizei height) with gil\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/common.pxi",
    "content": "#\n# Common definition\n#\n\nDEF PI2 = 1.5707963267948966\nDEF PI = 3.1415926535897931\n\ncdef extern from *:\n    ctypedef char* const_char_ptr \"const char*\"\n\ncdef double pi = PI\ncdef extern from \"math.h\":\n    double cos(double) nogil\n    double acos(double) nogil\n    double sin(double) nogil\n    double sqrt(double) nogil\n    double pow(double x, double y) nogil\n    double atan2(double y, double x) nogil\n    double tan(double) nogil\n    double fabs(double) nogil\n\ncdef extern from \"stdlib.h\":\n    ctypedef unsigned long size_t\n    void free(void *ptr) nogil\n    void *realloc(void *ptr, size_t size) nogil\n    void *malloc(size_t size) nogil\n    void *calloc(size_t nmemb, size_t size) nogil\n\ncdef extern from \"string.h\":\n    void *memcpy(void *dest, void *src, size_t n) nogil\n    void *memset(void *dest, int c, size_t len)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/compiler.pxd",
    "content": "cdef class GraphicsCompiler\n\nfrom instructions cimport InstructionGroup\n\ncdef class GraphicsCompiler:\n    cdef InstructionGroup compile(self, InstructionGroup group)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/config.h",
    "content": "// Autogenerated file for Kivy C configuration\n#define __PY3 0\n#define __USE_RPI 0\n#define __USE_OPENGL_ES2 1\n#define __USE_OPENGL_DEBUG 0\n#define __USE_GLEW 0\n#define __USE_SDL2 1\n#define __USE_IOS 0\n#define __USE_MESAGL 0\n#define __USE_X11 0\n#define __USE_GSTREAMER 1\n#define __USE_AVFOUNDATION 0\n#define __USE_OSX_FRAMEWORKS 0\n#if __USE_GLEW && defined(_WIN32)\n#   define GLEW_BUILD\n#endif"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/config.pxi",
    "content": "# Autogenerated file for Kivy Cython configuration\nDEF PY3 = 0\nDEF USE_RPI = 0\nDEF USE_OPENGL_ES2 = 1\nDEF USE_OPENGL_DEBUG = 0\nDEF USE_GLEW = 0\nDEF USE_SDL2 = 1\nDEF USE_IOS = 0\nDEF USE_MESAGL = 0\nDEF USE_X11 = 0\nDEF USE_GSTREAMER = 1\nDEF USE_AVFOUNDATION = 0\nDEF USE_OSX_FRAMEWORKS = 0\nDEF DEBUG = False\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/context.pxd",
    "content": "from kivy.graphics.instructions cimport Instruction, Canvas\nfrom kivy.graphics.texture cimport Texture\nfrom kivy.graphics.vbo cimport VBO, VertexBatch\nfrom kivy.graphics.shader cimport Shader\nfrom kivy.graphics.fbo cimport Fbo\n\ncdef class Context:\n    cdef list observers\n    cdef list observers_before\n    cdef list l_texture\n    cdef list l_canvas\n    cdef list l_fbo\n\n    cdef object lr_texture\n    cdef list lr_canvas\n    cdef object lr_vbo\n    cdef object lr_fbo_rb\n    cdef object lr_fbo_fb\n    cdef object lr_shadersource\n    cdef list lr_shader\n\n    cdef void register_texture(self, Texture texture)\n    cdef void register_canvas(self, Canvas canvas)\n    cdef void register_fbo(self, Fbo fbo)\n\n    cdef void dealloc_texture(self, Texture texture)\n    cdef void dealloc_vbo(self, VBO vbo)\n    cdef void dealloc_vertexbatch(self, VertexBatch vbo)\n    cdef void dealloc_shader(self, Shader shader)\n    cdef void dealloc_shader_source(self, int shader)\n    cdef void dealloc_fbo(self, Fbo fbo)\n\n    cdef object trigger_gl_dealloc\n    cdef void flush(self)\n\ncpdef Context get_context()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/context_instructions.pxd",
    "content": "cdef class LineWidth\ncdef class Color\ncdef class BindTexture\n\nfrom transformation cimport Matrix\nfrom instructions cimport ContextInstruction\nfrom texture cimport Texture\n\ncdef class PushState(ContextInstruction):\n    pass\n\ncdef class ChangeState(ContextInstruction):\n    pass\n\ncdef class PopState(ContextInstruction):\n    pass\n\ncdef class LineWidth(ContextInstruction):\n    cdef int apply(self) except -1\n\ncdef class Color(ContextInstruction):\n    cdef int apply(self) except -1\n\ncdef class BindTexture(ContextInstruction):\n    cdef int _index\n    cdef object _source\n    cdef Texture _texture\n    cdef int apply(self) except -1\n\n\ncdef class LoadIdentity(ContextInstruction):\n    pass\n\ncdef class PushMatrix(ContextInstruction):\n    cdef int apply(self) except -1\n\ncdef class PopMatrix(ContextInstruction):\n    cdef int apply(self) except -1\n\ncdef class ApplyContextMatrix(ContextInstruction):\n    cdef object _target_stack\n    cdef object _source_stack\n    cdef int apply(self) except -1\n\ncdef class UpdateNormalMatrix(ContextInstruction):\n    cdef int apply(self) except -1\n\ncdef class MatrixInstruction(ContextInstruction):\n    cdef object _stack\n    cdef Matrix _matrix\n    cdef int apply(self) except -1\n\ncdef class Transform(MatrixInstruction):\n    cpdef transform(self, Matrix trans)\n    cpdef translate(self, float tx, float ty, float tz)\n    cpdef rotate(self, float angle, float ax, float ay, float az)\n    cpdef scale(self, float s)\n    cpdef identity(self)\n\ncdef class Rotate(Transform):\n    cdef float _angle\n    cdef tuple _axis\n    cdef tuple _origin\n    cdef int apply(self) except -1\n    cdef void compute(self)\n\ncdef class Scale(Transform):\n    cdef tuple _origin\n    cdef float _x, _y, _z\n    cdef int apply(self) except -1\n    cdef set_scale(self, double x, double y, double z)\n\ncdef class Translate(Transform):\n    cdef double _x, _y, _z\n    cdef int apply(self) except -1\n    cdef set_translate(self, double x, double y, double z)\n\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/fbo.pxd",
    "content": "from c_opengl cimport *\nfrom instructions cimport RenderContext, Canvas\nfrom texture cimport Texture\n\ncdef class Fbo(RenderContext):\n    cdef int _width\n    cdef int _height\n    cdef int _depthbuffer_attached\n    cdef int _stencilbuffer_attached\n    cdef int _push_viewport\n    cdef float _clear_color[4]\n    cdef GLuint buffer_id\n    cdef GLuint depthbuffer_id\n    cdef GLuint stencilbuffer_id\n    cdef GLint _viewport[4]\n    cdef Texture _texture\n    cdef int _is_bound\n    cdef list observers\n\n    cpdef clear_buffer(self)\n    cpdef bind(self)\n    cpdef release(self)\n    cpdef get_pixel_color(self, int wx, int wy)\n\n    cdef void create_fbo(self)\n    cdef void delete_fbo(self)\n    cdef int apply(self) except -1\n    cdef void raise_exception(self, str message, int status=?)\n    cdef str resolve_status(self, int status)\n    cdef void reload(self)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/img_tools.pxi",
    "content": "from kivy.graphics.opengl_utils cimport (gl_has_texture_native_format,\n    gl_has_texture_conversion)\ncimport cython\nfrom cython cimport view as cyview\nfrom cpython.array cimport array, clone\n\n\n@cython.boundscheck(False)\n@cython.wraparound(False)\ncdef inline convert_to_gl_format(data, fmt):\n    ''' Takes data as a bytes object or an instance that implements the python\n    buffer interface. If the data format is supported by opengl, the data\n    is returned unchanged. Otherwise, the data is converted to a supported\n    format, when possible, and returned as a python array object.\n\n    Note that conversion is currently only supported for bytes data.\n    '''\n    cdef array ret_array\n    cdef char *src_buffer\n    cdef char *dst_buffer\n    cdef char [::1] view\n    cdef int datasize\n    cdef str ret_format\n    cdef int i\n    cdef char c\n\n    # if native support of this format is available, use it\n    if gl_has_texture_native_format(fmt):\n        return data, fmt\n\n    # no native support, can we at least convert it ?\n    if not gl_has_texture_conversion(fmt):\n        raise Exception('Unimplemented texture conversion for {}'.format(fmt))\n\n    # do appropriate conversion, since we accepted it\n    if isinstance(data, bytes):\n        datasize = len(data)\n        ret_array = clone(array('b'), datasize, False)\n        src_buffer = <char *>data\n    else:\n        view = data\n        datasize = view.nbytes\n        ret_array = clone(array('b'), datasize, False)\n        src_buffer = &view[0]\n    dst_buffer = ret_array.data.as_chars\n\n    # BGR -> RGB\n    if fmt == 'bgr':\n        ret_format = 'rgb'\n        memcpy(dst_buffer, src_buffer, datasize)\n        # note, this is the fastest copying method. copying element by element\n        # from a memoryview is slower then copying the whole buffer and then\n        # properly modifying the elements\n        with nogil:\n            for i in range(0, datasize, 3):\n                c = dst_buffer[i]\n                dst_buffer[i] = dst_buffer[i + 2]\n                dst_buffer[i + 2] = c\n\n    # BGRA -> RGBA\n    elif fmt == 'bgra':\n        ret_format = 'rgba'\n        memcpy(dst_buffer, src_buffer, datasize)\n        with nogil:\n            for i in range(0, datasize, 4):\n                c = dst_buffer[i]\n                dst_buffer[i] = dst_buffer[i + 2]\n                dst_buffer[i + 2] = c\n\n    else:\n        assert False, 'Non implemented texture conversion {}'.format(fmt)\n\n    return ret_array, ret_format\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/instructions.pxd",
    "content": "include \"config.pxi\"\n\ncdef class Instruction\ncdef class InstructionGroup\ncdef class ContextInstruction\ncdef class VertexInstruction\ncdef class CanvasBase\ncdef class Canvas\ncdef class RenderContext\n\nfrom vbo cimport *\nfrom compiler cimport *\nfrom shader cimport *\nfrom texture cimport Texture\nfrom kivy._event cimport ObjectWithUid\n\ncdef void reset_gl_context()\n\ncdef class Instruction\ncdef class InstructionGroup(Instruction)\n\ncdef class Instruction(ObjectWithUid):\n    cdef int flags\n    cdef str group\n    cdef InstructionGroup parent\n    cdef object __weakref__\n    cdef object __proxy_ref\n\n    cdef int apply(self) except -1\n    IF DEBUG:\n        cdef int flag_update(self, int do_parent=?, list _instrs=?) except -1\n    ELSE:\n        cdef void flag_update(self, int do_parent=?)\n    cdef void flag_update_done(self)\n    cdef void set_parent(self, Instruction parent)\n    cdef void reload(self)\n\n    cdef void radd(self, InstructionGroup ig)\n    cdef void rinsert(self, InstructionGroup ig, int index)\n    cdef void rremove(self, InstructionGroup ig)\n\ncdef class InstructionGroup(Instruction):\n    cdef public list children\n    cdef InstructionGroup compiled_children\n    cdef GraphicsCompiler compiler\n    cdef void build(self)\n    cdef void reload(self)\n    cpdef add(self, Instruction c)\n    cpdef insert(self, int index, Instruction c)\n    cpdef remove(self, Instruction c)\n    cpdef clear(self)\n    cpdef remove_group(self, str groupname)\n    cpdef get_group(self, str groupname)\n\ncdef class ContextInstruction(Instruction):\n    cdef dict context_state\n    cdef list context_push\n    cdef list context_pop\n\n    cdef RenderContext get_context(self)\n    cdef int set_state(self, str name, value) except -1\n    cdef int push_state(self, str name) except -1\n    cdef int pop_state(self, str name) except -1\n\n\nfrom context_instructions cimport BindTexture\n\ncdef class VertexInstruction(Instruction):\n    cdef BindTexture texture_binding\n    cdef VertexBatch batch\n    cdef float _tex_coords[8]\n\n    cdef void radd(self, InstructionGroup ig)\n    cdef void rinsert(self, InstructionGroup ig, int index)\n    cdef void rremove(self, InstructionGroup ig)\n\n    cdef void build(self)\n\ncdef class Callback(Instruction):\n    cdef Shader _shader\n    cdef object func\n    cdef int _reset_context\n    cdef int apply(self) except -1\n    cdef int enter(self) except -1\n\n\n\ncdef CanvasBase getActiveCanvas()\n\ncdef class CanvasBase(InstructionGroup):\n    pass\n\ncdef class Canvas(CanvasBase):\n    cdef float _opacity\n    cdef CanvasBase _before\n    cdef CanvasBase _after\n    cdef void reload(self)\n    cpdef clear(self)\n    cpdef add(self, Instruction c)\n    cpdef remove(self, Instruction c)\n    cpdef draw(self)\n    cdef int apply(self) except -1\n\n\ncdef class RenderContext(Canvas):\n    cdef Shader _shader\n    cdef dict state_stacks\n    cdef Texture default_texture\n    cdef dict bind_texture\n    cdef int _use_parent_projection\n    cdef int _use_parent_modelview\n\n    cdef void set_texture(self, int index, Texture texture)\n    cdef void set_state(self, str name, value, int apply_now=?)\n    cdef get_state(self, str name)\n    cdef int set_states(self, dict states) except -1\n    cdef int push_state(self, str name) except -1\n    cdef int push_states(self, list names) except -1\n    cdef int pop_state(self, str name) except -1\n    cdef int pop_states(self, list names) except -1\n    cdef int enter(self) except -1\n    cdef int leave(self) except -1\n    cdef int apply(self) except -1\n    cpdef draw(self)\n    cdef void reload(self)\n\ncdef RenderContext getActiveContext()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/opcodes.pxi",
    "content": "cdef int GI_NOOP         = 1 << 0\ncdef int GI_IGNORE       = 1 << 1\ncdef int GI_NEEDS_UPDATE = 1 << 2\ncdef int GI_GROUP        = 1 << 3\ncdef int GI_CONTEXT_MOD  = 1 << 4\ncdef int GI_VERTEX_DATA  = 1 << 5\ncdef int GI_COMPILER\t = 1 << 6\ncdef int GI_NO_APPLY_ONCE = 1 << 7\ncdef int GI_NO_REMOVE    = 1 << 8\n\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/opengl_utils.pxd",
    "content": "cpdef list gl_get_extensions()\ncpdef int gl_has_extension(name)\ncpdef gl_register_get_size(int constid, int size)\ncpdef int gl_has_capability(int cap)\ncpdef tuple gl_get_texture_formats()\ncpdef int gl_has_texture_native_format(fmt)\ncpdef int gl_has_texture_conversion(fmt)\ncpdef int gl_has_texture_format(fmt)\ncpdef tuple gl_get_version()\ncpdef int gl_get_version_major()\ncpdef int gl_get_version_minor()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/opengl_utils_def.pxi",
    "content": "# c definition\ncdef int c_GLCAP_BGRA = 0x0001\ncdef int c_GLCAP_NPOT = 0x0002\ncdef int c_GLCAP_S3TC = 0x0003\ncdef int c_GLCAP_DXT1 = 0x0004\ncdef int c_GLCAP_PVRTC = 0x0005\ncdef int c_GLCAP_ETC1 = 0x0006\ncdef int c_GLCAP_UNPACK_SUBIMAGE = 0x0007\n\n# for python export\nGLCAP_BGRA = c_GLCAP_NPOT\nGLCAP_NPOT = c_GLCAP_NPOT\nGLCAP_S3TC = c_GLCAP_S3TC\nGLCAP_DXT1 = c_GLCAP_DXT1\nGLCAP_PVRTC = c_GLCAP_PVRTC\nGLCAP_ETC1 = c_GLCAP_ETC1\nGLCAP_UNPACK_SUBIMAGE = c_GLCAP_UNPACK_SUBIMAGE\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/shader.pxd",
    "content": "from c_opengl cimport GLuint\nfrom transformation cimport Matrix\nfrom vertex cimport VertexFormat\n\ncdef class ShaderSource:\n    cdef int shader\n    cdef int shadertype\n    cdef set_source(self, char *source)\n    cdef get_shader_log(self, int shader)\n    cdef void process_message(self, str ctype, message)\n    cdef int is_compiled(self)\n\ncdef class Shader:\n    cdef object __weakref__\n\n    cdef int _success\n    cdef VertexFormat _current_vertex_format\n    cdef unsigned int program\n    cdef ShaderSource vertex_shader\n    cdef ShaderSource fragment_shader\n    cdef object _source\n    cdef object vert_src\n    cdef object frag_src\n    cdef dict uniform_locations\n    cdef dict uniform_values\n\n    cdef void use(self)\n    cdef void stop(self)\n    cdef int set_uniform(self, str name, value) except -1\n    cdef int upload_uniform(self, str name, value) except -1\n    cdef void upload_uniform_matrix(self, int loc, Matrix value)\n    cdef int get_uniform_loc(self, str name) except *\n    cdef int build(self) except -1\n    cdef int build_vertex(self, int link=*) except -1\n    cdef int build_fragment(self, int link=*) except -1\n    cdef int link_program(self) except -1\n    cdef int is_linked(self)\n    cdef ShaderSource compile_shader(self, str source, int shadertype)\n    cdef get_program_log(self, shader)\n    cdef void process_message(self, str ctype, message)\n    cdef void reload(self)\n    cdef void bind_vertex_format(self, VertexFormat vertex_format)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/stencil_instructions.pxd",
    "content": "from kivy.graphics.instructions cimport Instruction\n\ncdef class StencilPush(Instruction):\n    cdef int apply(self) except -1 \ncdef class StencilPop(Instruction):\n    cdef int apply(self) except -1\ncdef class StencilUse(Instruction):\n    cdef unsigned int _op\n    cdef int apply(self) except -1\ncdef class StencilUnUse(Instruction):\n    cdef int apply(self) except -1\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/svg.pxd",
    "content": "cdef class Matrix\ncdef class Svg\n\nfrom cython cimport view\nfrom kivy.graphics.instructions cimport RenderContext\nfrom kivy.graphics.texture cimport Texture\nfrom kivy.graphics.vertex cimport VertexFormat\nfrom kivy.graphics.vertex_instructions cimport StripMesh\nfrom cpython cimport array\nfrom array import array\n\ncdef set COMMANDS\ncdef set UPPERCASE\ncdef object RE_LIST\ncdef object RE_COMMAND\ncdef object RE_FLOAT\ncdef object RE_POLYLINE\ncdef object RE_TRANSFORM\ncdef VertexFormat VERTEX_FORMAT\nctypedef double matrix_t[6]\ncdef list kv_color_to_int_color(color)\ncdef float parse_float(txt)\ncdef list parse_list(string)\ncdef dict parse_style(string)\ncdef parse_color(c, current_color=?)\n\ncdef class Matrix:\n    cdef matrix_t mat\n    cdef void transform(self, float ox, float oy, float *x, float *y)\n    cpdef Matrix inverse(self)\n\ncdef class Svg(RenderContext):\n    cdef public double width\n    cdef public double height\n    cdef float line_width\n    cdef list paths\n    cdef object transform\n    cdef object fill\n    cdef public object current_color\n    cdef object stroke\n    cdef float opacity\n    cdef float x\n    cdef float y\n    cdef int close_index\n    cdef list path\n    cdef array.array loop\n    cdef int bezier_points\n    cdef int circle_points\n    cdef public object gradients\n    cdef view.array bezier_coefficients\n    cdef float anchor_x\n    cdef float anchor_y\n    cdef double last_cx\n    cdef double last_cy\n    cdef Texture line_texture\n    cdef StripMesh last_mesh\n\n    cdef parse_tree(self, tree)\n    cdef parse_element(seld, e)\n    cdef list parse_transform(self, transform_def)\n    cdef parse_path(self, pathdef)\n    cdef void new_path(self)\n    cdef void close_path(self)\n    cdef void set_position(self, float x, float y, int absolute=*)\n    cdef arc_to(self, float rx, float ry, float phi, float large_arc,\n            float sweep, float x, float y)\n    cdef void curve_to(self, float x1, float y1, float x2, float y2,\n            float x, float y)\n    cdef void end_path(self)\n    cdef void push_mesh(self, float[:] path, fill, Matrix transform, mode)\n    cdef void push_strip_mesh(self, float *vertices, int vindex, int count,\n                              int mode=*)\n    cdef void push_line_mesh(self, float[:] path, fill, Matrix transform)\n    cdef void render(self)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/tesselator.pxd",
    "content": "cdef class Tesselator:\n    cdef void *tess\n    cdef int element_type\n    cdef int polysize\n    cdef void add_contour_data(self, void *cdata, int count)\n    cdef iterate_vertices(self, int mode)\n    cpdef int tesselate(\n            self, int winding_rule=?,\n            int element_type=?, int polysize=?)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/texture.pxd",
    "content": "from c_opengl cimport GLuint\n\ncdef class Texture:\n    cdef object __weakref__\n    cdef unsigned int flags\n\n    cdef object _source\n    cdef float _tex_coords[8]\n    cdef int _width\n    cdef int _height\n    cdef GLuint _target\n    cdef GLuint _id\n    cdef int _mipmap\n    cdef object _wrap\n    cdef object _min_filter\n    cdef object _mag_filter\n    cdef int _rectangle\n    cdef object _colorfmt\n    cdef object _icolorfmt\n    cdef object _bufferfmt\n    cdef float _uvx\n    cdef float _uvy\n    cdef float _uvw\n    cdef float _uvh\n    cdef int _is_allocated\n    cdef int _nofree\n    cdef list observers\n    cdef object _proxyimage\n    cdef object _callback\n\n    cdef void update_tex_coords(self)\n    cdef void set_min_filter(self, x)\n    cdef void set_mag_filter(self, x)\n    cdef void set_wrap(self, x)\n    cdef void reload(self)\n    cdef void _reload_propagate(self, Texture texture)\n    cdef void allocate(self)\n\n    cpdef flip_vertical(self)\n    cpdef flip_horizontal(self)\n    cpdef get_region(self, x, y, width, height)\n    cpdef bind(self)\n\ncdef class TextureRegion(Texture):\n    cdef int x\n    cdef int y\n    cdef Texture owner\n    cdef void reload(self)\n    cpdef bind(self)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/transformation.pxd",
    "content": "ctypedef double matrix_t[16]\n\ncdef class Matrix:\n    cdef matrix_t mat\n\n    cpdef Matrix identity(self)\n\n    cpdef Matrix inverse(self)\n\n    cpdef Matrix transpose(self)\n\n    cpdef Matrix multiply(Matrix self, Matrix mb)\n\n    cpdef Matrix scale(Matrix self, double x, double y, double z)\n\n    cpdef Matrix translate(Matrix self, double x, double y, double z)\n\n    cpdef Matrix rotate(Matrix self,\n            double angle, double x, double y, double z)\n\n    cpdef Matrix view_clip(Matrix self, double left, double right,\n            double bottom, double top,\n            double near, double far, int perspective)\n\n    cpdef Matrix perspective(Matrix self, double fovy, double aspect,\n            double zNear, double zFar)\n\n    cpdef look_at(Matrix self, double eyex, double eyey, double eyez,\n            double centerx, double centery, double centerz,\n            double upx, double upy, double upz)\n\n    cpdef Matrix normal_matrix(self)\n\n    cpdef tuple transform_point(Matrix self, double x, double y, double z,\n            t=?)\n\n    cpdef project(Matrix self, double objx, double objy, double objz, Matrix model, Matrix proj,\n            double vx, double vy, double vw, double vh)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/vbo.pxd",
    "content": "from buffer cimport Buffer\nfrom c_opengl cimport GLuint\nfrom vertex cimport vertex_t, vertex_attr_t, VertexFormat\n\ncdef VertexFormat default_vertex\n\ncdef class VBO:\n    cdef object __weakref__\n\n    cdef GLuint id\n    cdef int usage\n    cdef int target\n    cdef vertex_attr_t *format\n    cdef long format_count\n    cdef long format_size\n    cdef Buffer data\n    cdef short flags\n    cdef long vbo_size\n    cdef VertexFormat vertex_format\n\n    cdef void update_buffer(self)\n    cdef void bind(self)\n    cdef void unbind(self)\n    cdef void add_vertex_data(self, void *v, unsigned short* indices, int count)\n    cdef void update_vertex_data(self, int index, void* v, int count)\n    cdef void remove_vertex_data(self, unsigned short* indices, int count)\n    cdef void reload(self)\n    cdef int have_id(self)\n\n\ncdef class VertexBatch:\n    cdef object __weakref__\n\n    cdef VBO vbo\n    cdef Buffer elements\n    cdef Buffer vbo_index\n    cdef GLuint mode\n    cdef str mode_str\n    cdef GLuint id\n    cdef int usage\n    cdef short flags\n    cdef long elements_size\n\n    cdef void clear_data(self)\n    cdef void set_data(self, void *vertices, int vertices_count,\n                       unsigned short *indices, int indices_count)\n    cdef void append_data(self, void *vertices, int vertices_count,\n                          unsigned short *indices, int indices_count)\n    cdef void draw(self)\n    cdef void set_mode(self, str mode)\n    cdef str get_mode(self)\n    cdef int count(self)\n    cdef void reload(self)\n    cdef int have_id(self)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/vertex.pxd",
    "content": "from c_opengl cimport GLuint\n\ncdef struct vertex_t:\n    float x, y\n    float s0, t0\n\nctypedef struct vertex_attr_t:\n    char *name\n    unsigned int index\n    unsigned int size\n    GLuint type\n    unsigned int bytesize\n    int per_vertex\n\ncdef class VertexFormat:\n    cdef vertex_attr_t *vattr\n    cdef long vattr_count\n    cdef unsigned int vsize\n    cdef unsigned int vbytesize\n    cdef object last_shader\n\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/vertex_instructions.pxd",
    "content": "from kivy.graphics.instructions cimport VertexInstruction\nfrom kivy.graphics.vertex cimport VertexFormat\n\n\ncdef class Bezier(VertexInstruction):\n    cdef list _points\n    cdef int _segments\n    cdef bint _loop\n    cdef int _dash_offset, _dash_length\n\n    cdef void build(self)\n\n\ncdef class StripMesh(VertexInstruction):\n    cdef int icount\n    cdef int li, lic\n    cdef int add_triangle_strip(self, float *vertices, int vcount, int icount,\n            int mode)\n\n\ncdef class Mesh(VertexInstruction):\n    cdef list _vertices\n    cdef list _indices\n    cdef VertexFormat vertex_format\n    cdef int is_built\n\n    cdef void build_triangle_fan(self, float *vertices, int vcount, int icount)\n    cdef void build(self)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/graphics/vertex_instructions_line.pxi",
    "content": "DEF LINE_CAP_NONE = 0\nDEF LINE_CAP_SQUARE = 1\nDEF LINE_CAP_ROUND = 2\n\nDEF LINE_JOINT_NONE = 0\nDEF LINE_JOINT_MITER = 1\nDEF LINE_JOINT_BEVEL = 2\nDEF LINE_JOINT_ROUND = 3\n\nDEF LINE_MODE_POINTS = 0\nDEF LINE_MODE_ELLIPSE = 1\nDEF LINE_MODE_CIRCLE = 2\nDEF LINE_MODE_RECTANGLE = 3\nDEF LINE_MODE_ROUNDED_RECTANGLE = 4\nDEF LINE_MODE_BEZIER = 5\n\nfrom kivy.graphics.stencil_instructions cimport StencilUse, StencilUnUse, StencilPush, StencilPop\n\ncdef float PI = 3.1415926535\n\ncdef inline int line_intersection(double x1, double y1, double x2, double y2,\n        double x3, double y3, double x4, double y4, double *px, double *py):\n    cdef double u = (x1 * y2 - y1 * x2)\n    cdef double v = (x3 * y4 - y3 * x4)\n    cdef double denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)\n    if denom == 0:\n        return 0\n    px[0] = (u * (x3 - x4) - (x1 - x2) * v) / denom\n    py[0] = (u * (y3 - y4) - (y1 - y2) * v) / denom\n    return 1\n\ncdef class Line(VertexInstruction):\n    '''A 2d line.\n\n    Drawing a line can be done easily::\n\n        with self.canvas:\n            Line(points=[100, 100, 200, 100, 100, 200], width=10)\n\n    The line has 3 internal drawing modes that you should be aware of\n    for optimal results:\n\n    #. If the :attr:`width` is 1.0, then the standard GL_LINE drawing from\n       OpenGL will be used. :attr:`dash_length` and :attr:`dash_offset` will\n       work, while properties for cap and joint have no meaning here.\n    #. If the :attr:`width` is > 1.0, then a custom drawing method will be used,\n       based on triangles. :attr:`dash_length` and :attr:`dash_offset` do not\n       work in this mode.\n       Additionally, if the current color has an alpha < 1.0, a stencil will be\n       used internally to draw the line.\n\n    .. image:: images/line-instruction.png\n        :align: center\n\n    :Parameters:\n        `points`: list\n            List of points in the format (x1, y1, x2, y2...)\n        `dash_length`: int\n            Length of a segment (if dashed), defaults to 1.\n        `dash_offset`: int\n            Offset between the end of a segments and the begining of the\n            next one, defaults to 0. Changing this makes it dashed.\n        `width`: float\n            Width of the line, defaults to 1.0.\n        `cap`: str, defaults to 'round'\n            See :attr:`cap` for more information.\n        `joint`: str, defaults to 'round'\n            See :attr:`joint` for more information.\n        `cap_precision`: int, defaults to 10\n            See :attr:`cap_precision` for more information\n        `joint_precision`: int, defaults to 10\n            See :attr:`joint_precision` for more information\n            See :attr:`cap_precision` for more information.\n        `joint_precision`: int, defaults to 10\n            See :attr:`joint_precision` for more information.\n        `close`: bool, defaults to False\n            If True, the line will be closed.\n        `circle`: list\n            If set, the :attr:`points` will be set to build a circle. Check\n            :attr:`circle` for more information.\n        `ellipse`: list\n            If set, the :attr:`points` will be set to build an ellipse. Check\n            :attr:`ellipse` for more information.\n        `rectangle`: list\n            If set, the :attr:`points` will be set to build a rectangle. Check\n            :attr:`rectangle` for more information.\n        `bezier`: list\n            If set, the :attr:`points` will be set to build a bezier line. Check\n            :attr:`bezier` for more information.\n        `bezier_precision`: int, defaults to 180\n            Precision of the Bezier drawing.\n\n    .. versionchanged:: 1.0.8\n        `dash_offset` and `dash_length` have been added\n\n    .. versionchanged:: 1.4.1\n        `width`, `cap`, `joint`, `cap_precision`, `joint_precision`, `close`,\n        `ellipse`, `rectangle` have been added.\n\n    .. versionchanged:: 1.4.1\n        `bezier`, `bezier_precision` have been added.\n\n    '''\n    cdef int _cap\n    cdef int _cap_precision\n    cdef int _joint_precision\n    cdef int _bezier_precision\n    cdef int _joint\n    cdef list _points\n    cdef float _width\n    cdef int _dash_offset, _dash_length\n    cdef int _use_stencil\n    cdef int _close\n    cdef int _mode\n    cdef Instruction _stencil_rect\n    cdef Instruction _stencil_push\n    cdef Instruction _stencil_use\n    cdef Instruction _stencil_unuse\n    cdef Instruction _stencil_pop\n    cdef double _bxmin, _bxmax, _bymin, _bymax\n    cdef tuple _mode_args\n\n    def __init__(self, **kwargs):\n        VertexInstruction.__init__(self, **kwargs)\n        v = kwargs.get('points')\n        self.points = v if v is not None else []\n        self.batch.set_mode('line_strip')\n        self._dash_length = kwargs.get('dash_length') or 1\n        self._dash_offset = kwargs.get('dash_offset') or 0\n        self._width = kwargs.get('width') or 1.0\n        self.joint = kwargs.get('joint') or 'round'\n        self.cap = kwargs.get('cap') or 'round'\n        self._cap_precision = kwargs.get('cap_precision') or 10\n        self._joint_precision = kwargs.get('joint_precision') or 10\n        self._bezier_precision = kwargs.get('bezier_precision') or 180\n        self._close = int(bool(kwargs.get('close', 0)))\n        self._stencil_rect = None\n        self._stencil_push = None\n        self._stencil_use = None\n        self._stencil_unuse = None\n        self._stencil_pop = None\n        self._use_stencil = 0\n\n        if 'ellipse' in kwargs:\n            self.ellipse = kwargs['ellipse']\n        if 'circle' in kwargs:\n            self.circle = kwargs['circle']\n        if 'rectangle' in kwargs:\n            self.rectangle = kwargs['rectangle']\n        if 'bezier' in kwargs:\n            self.bezier = kwargs['bezier']\n\n    cdef void build(self):\n        if self._mode == LINE_MODE_ELLIPSE:\n            self.prebuild_ellipse()\n        elif self._mode == LINE_MODE_CIRCLE:\n            self.prebuild_circle()\n        elif self._mode == LINE_MODE_RECTANGLE:\n            self.prebuild_rectangle()\n        elif self._mode == LINE_MODE_ROUNDED_RECTANGLE:\n            self.prebuild_rounded_rectangle()\n        elif self._mode == LINE_MODE_BEZIER:\n            self.prebuild_bezier()\n        if self._width == 1.0:\n            self.build_legacy()\n        else:\n            self.build_extended()\n\n    cdef void ensure_stencil(self):\n        if self._stencil_rect == None:\n            self._stencil_rect = Rectangle()\n            self._stencil_push = StencilPush()\n            self._stencil_pop = StencilPop()\n            self._stencil_use = StencilUse(op='lequal')\n            self._stencil_unuse = StencilUnUse()\n\n    cdef int apply(self) except -1:\n        if self._width == 1.:\n            VertexInstruction.apply(self)\n            return 0\n\n        cdef double alpha = getActiveContext()['color'][-1]\n        self._use_stencil = alpha < 1\n        if self._use_stencil:\n            self.ensure_stencil()\n\n            self._stencil_push.apply()\n            VertexInstruction.apply(self)\n            self._stencil_use.apply()\n            self._stencil_rect.pos = self._bxmin, self._bymin\n            self._stencil_rect.size = self._bxmax - self._bxmin, self._bymax - self._bymin\n            self._stencil_rect.apply()\n            self._stencil_unuse.apply()\n            VertexInstruction.apply(self)\n            self._stencil_pop.apply()\n        else:\n            VertexInstruction.apply(self)\n        return 0\n\n    cdef void build_legacy(self):\n        cdef int i\n        cdef long count = len(self.points) / 2\n        cdef list p = self.points\n        cdef vertex_t *vertices = NULL\n        cdef unsigned short *indices = NULL\n        cdef float tex_x\n        cdef char *buf = NULL\n        cdef Texture texture = self.texture\n\n        if count < 2:\n            self.batch.clear_data()\n            return\n\n        if self._close:\n            p = p + [p[0], p[1]]\n            count += 1\n\n        self.batch.set_mode('line_strip')\n        if self._dash_offset != 0:\n            if texture is None or texture._width != \\\n                (self._dash_length + self._dash_offset) or \\\n                texture._height != 1:\n\n                self.texture = texture = Texture.create(\n                        size=(self._dash_length + self._dash_offset, 1))\n                texture.wrap = 'repeat'\n\n            # create a buffer to fill our texture\n            buf = <char *>malloc(4 * (self._dash_length + self._dash_offset))\n            memset(buf, 255, self._dash_length * 4)\n            memset(buf + self._dash_length * 4, 0, self._dash_offset * 4)\n            p_str = buf[:(self._dash_length + self._dash_offset) * 4]\n\n            self.texture.blit_buffer(p_str, colorfmt='rgba', bufferfmt='ubyte')\n            free(buf)\n\n        elif texture is not None:\n            self.texture = None\n\n        vertices = <vertex_t *>malloc(count * sizeof(vertex_t))\n        if vertices == NULL:\n            raise MemoryError('vertices')\n\n        indices = <unsigned short *>malloc(count * sizeof(unsigned short))\n        if indices == NULL:\n            free(vertices)\n            raise MemoryError('indices')\n\n        tex_x = 0\n        for i in xrange(count):\n            if self._dash_offset != 0 and i > 0:\n                tex_x += sqrt(\n                        pow(p[i * 2]     - p[(i - 1) * 2], 2)  +\n                        pow(p[i * 2 + 1] - p[(i - 1) * 2 + 1], 2)) / (\n                                self._dash_length + self._dash_offset)\n\n                vertices[i].s0 = tex_x\n                vertices[i].t0 = 0\n\n            vertices[i].x = p[i * 2]\n            vertices[i].y = p[i * 2 + 1]\n            indices[i] = i\n\n        self.batch.set_data(vertices, <int>count, indices, <int>count)\n\n        free(vertices)\n        free(indices)\n\n    cdef void build_extended(self):\n        cdef int i, j\n        cdef long count = len(self.points) / 2\n        cdef list p = self.points\n        cdef vertex_t *vertices = NULL\n        cdef unsigned short *indices = NULL\n        cdef float tex_x\n        cdef int cap\n        cdef char *buf = NULL\n        cdef Texture texture = self.texture\n\n        self._bxmin = 999999999\n        self._bymin = 999999999\n        self._bxmax = -999999999\n        self._bymax = -999999999\n\n        if count < 2:\n            self.batch.clear_data()\n            return\n\n        cap = self._cap\n        if self._close and count > 2:\n            p = p + p[0:4]\n            count += 2\n            cap = LINE_CAP_NONE\n\n        self.batch.set_mode('triangles')\n        cdef unsigned long vertices_count = (count - 1) * 4\n        cdef unsigned long indices_count = (count - 1) * 6\n        cdef unsigned int iv = 0, ii = 0\n\n        if self._joint == LINE_JOINT_BEVEL:\n            indices_count += (count - 2) * 3\n            vertices_count += (count - 2)\n        elif self._joint == LINE_JOINT_ROUND:\n            indices_count += (self._joint_precision * 3) * (count - 2)\n            vertices_count += (self._joint_precision) * (count - 2)\n        elif self._joint == LINE_JOINT_MITER:\n            indices_count += (count - 2) * 6\n            vertices_count += (count - 2) * 2\n\n        if cap == LINE_CAP_SQUARE:\n            indices_count += 12\n            vertices_count += 4\n        elif cap == LINE_CAP_ROUND:\n            indices_count += (self._cap_precision * 3) * 2\n            vertices_count += (self._cap_precision) * 2\n\n        vertices = <vertex_t *>malloc(vertices_count * sizeof(vertex_t))\n        if vertices == NULL:\n            raise MemoryError('vertices')\n\n        indices = <unsigned short *>malloc(indices_count * sizeof(unsigned short))\n        if indices == NULL:\n            free(vertices)\n            raise MemoryError('indices')\n\n        cdef double ax, ay, bx, _by, cx, cy, angle, a1, a2\n        cdef double x1, y1, x2, y2, x3, y3, x4, y4\n        cdef double sx1, sy1, sx4, sy4, sangle\n        cdef double pcx, pcy, px1, py1, px2, py2, px3, py3, px4, py4, pangle, pangle2\n        cdef double w = self._width\n        cdef double ix, iy\n        cdef unsigned int piv, pii2, piv2\n        cdef double jangle\n        angle = sangle = 0\n        piv = pcx = pcy = cx = cy = ii = iv = ix = iy = 0\n        px1 = px2 = px3 = px4 = py1 = py2 = py3 = py4 = 0\n        sx1 = sy1 = sx4 = sy4 = 0\n        x1 = x2 = x3 = x4 = y1 = y2 = y3 = y4 = 0\n        cdef double cos1 = 0, cos2 = 0, sin1 = 0, sin2 = 0\n        for i in range(0, count - 1):\n            ax = p[i * 2]\n            ay = p[i * 2 + 1]\n            bx = p[i * 2 + 2]\n            _by = p[i * 2 + 3]\n\n            if i > 0 and self._joint != LINE_JOINT_NONE:\n                pcx = cx\n                pcy = cy\n                px1 = x1\n                px2 = x2\n                px3 = x3\n                px4 = x4\n                py1 = y1\n                py2 = y2\n                py3 = y3\n                py4 = y4\n\n            piv2 = piv\n            piv = iv\n            pangle2 = pangle\n            pangle = angle\n\n            # calculate the orientation of the segment, between pi and -pi\n            cx = bx - ax\n            cy = _by - ay\n            angle = atan2(cy, cx)\n            a1 = angle - PI2\n            a2 = angle + PI2\n\n            # calculate the position of the segment\n            cos1 = cos(a1) * w\n            sin1 = sin(a1) * w\n            cos2 = cos(a2) * w\n            sin2 = sin(a2) * w\n            x1 = ax + cos1\n            y1 = ay + sin1\n            x4 = ax + cos2\n            y4 = ay + sin2\n            x2 = bx + cos1\n            y2 = _by + sin1\n            x3 = bx + cos2\n            y3 = _by + sin2\n\n            if i == 0:\n                sx1 = x1\n                sy1 = y1\n                sx4 = x4\n                sy4 = y4\n                sangle = angle\n\n            indices[ii    ] = iv\n            indices[ii + 1] = iv + 1\n            indices[ii + 2] = iv + 2\n            indices[ii + 3] = iv\n            indices[ii + 4] = iv + 2\n            indices[ii + 5] = iv + 3\n            ii += 6\n\n            vertices[iv].x = x1\n            vertices[iv].y = y1\n            vertices[iv].s0 = 0\n            vertices[iv].t0 = 0\n            iv += 1\n            vertices[iv].x = x2\n            vertices[iv].y = y2\n            vertices[iv].s0 = 1\n            vertices[iv].t0 = 0\n            iv += 1\n            vertices[iv].x = x3\n            vertices[iv].y = y3\n            vertices[iv].s0 = 1\n            vertices[iv].t0 = 1\n            iv += 1\n            vertices[iv].x = x4\n            vertices[iv].y = y4\n            vertices[iv].s0 = 0\n            vertices[iv].t0 = 1\n            iv += 1\n\n            # joint generation\n            if i == 0 or self._joint == LINE_JOINT_NONE:\n                continue\n\n            # calculate the angle of the previous and current segment\n            jangle = atan2(\n                cx * pcy - cy * pcx,\n                cx * pcx + cy * pcy)\n\n            # in case of the angle is NULL, avoid the generation\n            if jangle == 0:\n                if self._joint == LINE_JOINT_ROUND:\n                    vertices_count -= self._joint_precision\n                    indices_count -= self._joint_precision * 3\n                elif self._joint == LINE_JOINT_BEVEL:\n                    vertices_count -= 1\n                    indices_count -= 3\n                elif self._joint == LINE_JOINT_MITER:\n                    vertices_count -= 2\n                    indices_count -= 6\n                continue\n\n            if self._joint == LINE_JOINT_BEVEL:\n                vertices[iv].x = ax\n                vertices[iv].y = ay\n                vertices[iv].s0 = 0\n                vertices[iv].t0 = 0\n                if jangle < 0:\n                    indices[ii] = piv2 + 1\n                    indices[ii + 1] = piv\n                    indices[ii + 2] = iv\n                else:\n                    indices[ii] = piv2 + 2\n                    indices[ii + 1] = piv + 3\n                    indices[ii + 2] = iv\n                ii += 3\n                iv += 1\n\n            elif self._joint == LINE_JOINT_MITER:\n                vertices[iv].x = ax\n                vertices[iv].y = ay\n                vertices[iv].s0 = 0\n                vertices[iv].t0 = 0\n                if jangle < 0:\n                    if line_intersection(px1, py1, px2, py2, x1, y1, x2, y2, &ix, &iy) == 0:\n                        vertices_count -= 2\n                        indices_count -= 6\n                        continue\n                    vertices[iv + 1].x = ix\n                    vertices[iv + 1].y = iy\n                    vertices[iv + 1].s0 = 0\n                    vertices[iv + 1].t0 = 0\n                    indices[ii] = iv\n                    indices[ii + 1] = iv + 1\n                    indices[ii + 2] = piv2 + 1\n                    indices[ii + 3] = iv\n                    indices[ii + 4] = piv\n                    indices[ii + 5] = iv + 1\n                    ii += 6\n                    iv += 2\n                else:\n                    if line_intersection(px3, py3, px4, py4, x3, y3, x4, y4, &ix, &iy) == 0:\n                        vertices_count -= 2\n                        indices_count -= 6\n                        continue\n                    vertices[iv + 1].x = ix\n                    vertices[iv + 1].y = iy\n                    vertices[iv + 1].s0 = 0\n                    vertices[iv + 1].t0 = 0\n                    indices[ii] = iv\n                    indices[ii + 1] = iv + 1\n                    indices[ii + 2] = piv2 + 2\n                    indices[ii + 3] = iv\n                    indices[ii + 4] = piv + 3\n                    indices[ii + 5] = iv + 1\n                    ii += 6\n                    iv += 2\n\n\n\n            elif self._joint == LINE_JOINT_ROUND:\n\n                # cap end\n                if jangle < 0:\n                    a1 = pangle2 - PI2\n                    a2 = angle + PI2\n                    a0 = a2\n                    step = (abs(jangle)) / float(self._joint_precision)\n                    pivstart = piv + 3\n                    pivend = piv2 + 1\n                else:\n                    a1 = angle - PI2\n                    a2 = pangle2 + PI2\n                    a0 = a1\n                    step = -(abs(jangle)) / float(self._joint_precision)\n                    pivstart = piv\n                    pivend = piv2 + 2\n                siv = iv\n                vertices[iv].x = ax\n                vertices[iv].y = ay\n                vertices[iv].s0 = 0\n                vertices[iv].t0 = 0\n                iv += 1\n                for j in xrange(0, self._joint_precision - 1):\n                    vertices[iv].x = ax - cos(a0 - step * j) * w\n                    vertices[iv].y = ay - sin(a0 - step * j) * w\n                    vertices[iv].s0 = 0\n                    vertices[iv].t0 = 0\n                    if j == 0:\n                        indices[ii] = siv\n                        indices[ii + 1] = pivstart\n                        indices[ii + 2] = iv\n                    else:\n                        indices[ii] = siv\n                        indices[ii + 1] = iv - 1\n                        indices[ii + 2] = iv\n                    iv += 1\n                    ii += 3\n                indices[ii] = siv\n                indices[ii + 1] = iv - 1\n                indices[ii + 2] = pivend\n                ii += 3\n\n        # caps\n        if cap == LINE_CAP_SQUARE:\n            vertices[iv].x = x2 + cos(angle) * w\n            vertices[iv].y = y2 + sin(angle) * w\n            vertices[iv].s0 = 0\n            vertices[iv].t0 = 0\n            vertices[iv + 1].x = x3 + cos(angle) * w\n            vertices[iv + 1].y = y3 + sin(angle) * w\n            vertices[iv + 1].s0 = 0\n            vertices[iv + 1].t0 = 0\n            indices[ii] = piv + 1\n            indices[ii + 1] = piv + 2\n            indices[ii + 2] = iv + 1\n            indices[ii + 3] = piv + 1\n            indices[ii + 4] = iv\n            indices[ii + 5] = iv + 1\n            ii += 6\n            iv += 2\n            vertices[iv].x = sx1 - cos(sangle) * w\n            vertices[iv].y = sy1 - sin(sangle) * w\n            vertices[iv].s0 = 0\n            vertices[iv].t0 = 0\n            vertices[iv + 1].x = sx4 - cos(sangle) * w\n            vertices[iv + 1].y = sy4 - sin(sangle) * w\n            vertices[iv + 1].s0 = 0\n            vertices[iv + 1].t0 = 0\n            indices[ii] = 0\n            indices[ii + 1] = 3\n            indices[ii + 2] = iv + 1\n            indices[ii + 3] = 0\n            indices[ii + 4] = iv\n            indices[ii + 5] = iv + 1\n            ii += 6\n            iv += 2\n\n        elif cap == LINE_CAP_ROUND:\n\n            # cap start\n            a1 = sangle - PI2\n            a2 = sangle + PI2\n            step = (a1 - a2) / float(self._cap_precision)\n            siv = iv\n            cx = p[0]\n            cy = p[1]\n            vertices[iv].x = cx\n            vertices[iv].y = cy\n            vertices[iv].s0 = 0\n            vertices[iv].t0 = 0\n            iv += 1\n            for i in xrange(0, self._cap_precision - 1):\n                vertices[iv].x = cx + cos(a1 + step * i) * w\n                vertices[iv].y = cy + sin(a1 + step * i) * w\n                vertices[iv].s0 = 1\n                vertices[iv].t0 = 1\n                if i == 0:\n                    indices[ii] = siv\n                    indices[ii + 1] = 0\n                    indices[ii + 2] = iv\n                else:\n                    indices[ii] = siv\n                    indices[ii + 1] = iv - 1\n                    indices[ii + 2] = iv\n                iv += 1\n                ii += 3\n            indices[ii] = siv\n            indices[ii + 1] = iv - 1\n            indices[ii + 2] = 3\n            ii += 3\n\n            # cap end\n            a1 = angle - PI2\n            a2 = angle + PI2\n            step = (a2 - a1) / float(self._cap_precision)\n            siv = iv\n            cx = p[-2]\n            cy = p[-1]\n            vertices[iv].x = cx\n            vertices[iv].y = cy\n            vertices[iv].s0 = 0\n            vertices[iv].t0 = 0\n            iv += 1\n            for i in xrange(0, self._cap_precision - 1):\n                vertices[iv].x = cx + cos(a1 + step * i) * w\n                vertices[iv].y = cy + sin(a1 + step * i) * w\n                vertices[iv].s0 = 0\n                vertices[iv].t0 = 0\n                if i == 0:\n                    indices[ii] = siv\n                    indices[ii + 1] = piv + 1\n                    indices[ii + 2] = iv\n                else:\n                    indices[ii] = siv\n                    indices[ii + 1] = iv - 1\n                    indices[ii + 2] = iv\n                iv += 1\n                ii += 3\n            indices[ii] = siv\n            indices[ii + 1] = iv - 1\n            indices[ii + 2] = piv + 2\n            ii += 3\n\n        # compute bbox\n        for i in xrange(vertices_count):\n            if vertices[i].x < self._bxmin:\n                self._bxmin = vertices[i].x\n            if vertices[i].x > self._bxmax:\n                self._bxmax = vertices[i].x\n            if vertices[i].y < self._bymin:\n                self._bymin = vertices[i].y\n            if vertices[i].y > self._bymax:\n                self._bymax = vertices[i].y\n\n        self.batch.set_data(vertices, <int>vertices_count,\n                           indices, <int>indices_count)\n\n        free(vertices)\n        free(indices)\n\n\n\n    property points:\n        '''Property for getting/settings points of the line\n\n        .. warning::\n\n            This will always reconstruct the whole graphics from the new points\n            list. It can be very CPU expensive.\n        '''\n        def __get__(self):\n            return self._points\n        def __set__(self, points):\n            self._points = list(points)\n            self.flag_update()\n\n    property dash_length:\n        '''Property for getting/setting the length of the dashes in the curve\n\n        .. versionadded:: 1.0.8\n        '''\n        def __get__(self):\n            return self._dash_length\n\n        def __set__(self, value):\n            if value < 0:\n                raise GraphicException('Invalid dash_length value, must be >= 0')\n            self._dash_length = value\n            self.flag_update()\n\n    property dash_offset:\n        '''Property for getting/setting the offset between the dashes in the curve\n\n        .. versionadded:: 1.0.8\n        '''\n        def __get__(self):\n            return self._dash_offset\n\n        def __set__(self, value):\n            if value < 0:\n                raise GraphicException('Invalid dash_offset value, must be >= 0')\n            self._dash_offset = value\n            self.flag_update()\n\n    property width:\n        '''Determine the width of the line, defaults to 1.0.\n\n        .. versionadded:: 1.4.1\n        '''\n        def __get__(self):\n            return self._width\n\n        def __set__(self, value):\n            if value <= 0:\n                raise GraphicException('Invalid width value, must be > 0')\n            self._width = value\n            self.flag_update()\n\n    property cap:\n        '''Determine the cap of the line, defaults to 'round'. Can be one of\n        'none', 'square' or 'round'\n\n        .. versionadded:: 1.4.1\n        '''\n        def __get__(self):\n            if self._cap == LINE_CAP_SQUARE:\n                return 'square'\n            elif self._cap == LINE_CAP_ROUND:\n                return 'round'\n            return 'none'\n\n        def __set__(self, value):\n            if value not in ('none', 'square', 'round'):\n                raise GraphicException('Invalid cap, must be one of '\n                        '\"none\", \"square\", \"round\"')\n            if value == 'square':\n                self._cap = LINE_CAP_SQUARE\n            elif value == 'round':\n                self._cap = LINE_CAP_ROUND\n            else:\n                self._cap = LINE_CAP_NONE\n            self.flag_update()\n\n    property joint:\n        '''Determine the join of the line, defaults to 'round'. Can be one of\n        'none', 'round', 'bevel', 'miter'.\n\n        .. versionadded:: 1.4.1\n        '''\n\n        def __get__(self):\n            if self._joint == LINE_JOINT_ROUND:\n                return 'round'\n            elif self._joint == LINE_JOINT_BEVEL:\n                return 'bevel'\n            elif self._joint == LINE_JOINT_MITER:\n                return 'miter'\n            return 'none'\n\n        def __set__(self, value):\n            if value not in ('none', 'miter', 'bevel', 'round'):\n                raise GraphicException('Invalid joint, must be one of '\n                    '\"none\", \"miter\", \"bevel\", \"round\"')\n            if value == 'round':\n                self._joint = LINE_JOINT_ROUND\n            elif value == 'bevel':\n                self._joint = LINE_JOINT_BEVEL\n            elif value == 'miter':\n                self._joint = LINE_JOINT_MITER\n            else:\n                self._joint = LINE_JOINT_NONE\n            self.flag_update()\n\n    property cap_precision:\n        '''Number of iteration for drawing the \"round\" cap, defaults to 10.\n        The cap_precision must be at least 1.\n\n        .. versionadded:: 1.4.1\n        '''\n\n        def __get__(self):\n            return self._cap_precision\n\n        def __set__(self, value):\n            if value < 1:\n                raise GraphicException('Invalid cap_precision value, must be >= 1')\n            self._cap_precision = int(value)\n            self.flag_update()\n\n    property joint_precision:\n        '''Number of iteration for drawing the \"round\" joint, defaults to 10.\n        The joint_precision must be at least 1.\n\n        .. versionadded:: 1.4.1\n        '''\n\n        def __get__(self):\n            return self._joint_precision\n\n        def __set__(self, value):\n            if value < 1:\n                raise GraphicException('Invalid joint_precision value, must be >= 1')\n            self._joint_precision = int(value)\n            self.flag_update()\n\n    property close:\n        '''If True, the line will be closed.\n\n        .. versionadded:: 1.4.1\n        '''\n\n        def __get__(self):\n            return self._close\n\n        def __set__(self, value):\n            self._close = int(bool(value))\n            self.flag_update()\n\n    property ellipse:\n        '''Use this property to build an ellipse, without calculating the\n        :attr:`points`. You can only set this property, not get it.\n\n        The argument must be a tuple of (x, y, width, height, angle_start,\n        angle_end, segments):\n\n        * x and y represent the bottom left of the ellipse\n        * width and height represent the size of the ellipse\n        * (optional) angle_start and angle_end are in degree. The default\n            value is 0 and 360.\n        * (optional) segments is the precision of the ellipse. The default\n            value is calculated from the range between angle.\n\n        Note that it's up to you to :attr:`close` the ellipse or not.\n\n        For example, for building a simple ellipse, in python::\n\n            # simple ellipse\n            Line(ellipse=(0, 0, 150, 150))\n\n            # only from 90 to 180 degrees\n            Line(ellipse=(0, 0, 150, 150, 90, 180))\n\n            # only from 90 to 180 degrees, with few segments\n            Line(ellipse=(0, 0, 150, 150, 90, 180, 20))\n\n        .. versionadded:: 1.4.1\n        '''\n\n        def __set__(self, args):\n            if args == None:\n                raise GraphicException(\n                        'Invalid ellipse value: {0!r}'.format(args))\n            if len(args) not in (4, 6, 7):\n                raise GraphicException('Invalid number of arguments: '\n                        '{0} instead of 4, 6 or 7.'.format(len(args)))\n            self._mode_args = tuple(args)\n            self._mode = LINE_MODE_ELLIPSE\n            self.flag_update()\n\n    cdef void prebuild_ellipse(self):\n        cdef double x, y, w, h, angle_start = 0, angle_end = 360\n        cdef int angle_dir, segments = 0\n        cdef double angle_range\n        cdef tuple args = self._mode_args\n\n        if len(args) == 4:\n            x, y, w, h = args\n        elif len(args) == 6:\n            x, y, w, h, angle_start, angle_end = args\n        elif len(args) == 7:\n            x, y, w, h, angle_start, angle_end, segments = args\n            segments += 2\n        else:\n            x = y = w = h = 0\n            assert(0)\n\n        if angle_end > angle_start:\n            angle_dir = 1\n        else:\n            angle_dir = -1\n        if segments == 0:\n            segments = int(abs(angle_end - angle_start) / 2) + 3\n            if segments % 2 == 1:\n                segments += 1\n        # rad = deg * (pi / 180), where pi/180 = 0.0174...\n        angle_start = angle_start * 0.017453292519943295\n        angle_end = angle_end * 0.017453292519943295\n        angle_range = abs(angle_end - angle_start) / (segments - 2)\n\n        cdef list points = [0, ] * segments\n        cdef double angle\n        cdef double rx = w * 0.5\n        cdef double ry = h * 0.5\n        for i in xrange(0, segments, 2):\n            angle = angle_start + (angle_dir * (i - 1) * angle_range)\n            points[i] = (x + rx) + (rx * sin(angle))\n            points[i + 1] = (y + ry) + (ry * cos(angle))\n\n        self._points = points\n\n\n    property circle:\n        '''Use this property to build a circle, without calculate the\n        :attr:`points`. You can only set this property, not get it.\n\n        The argument must be a tuple of (center_x, center_y, radius, angle_start,\n        angle_end, segments):\n\n        * center_x and center_y represent the center of the circle\n        * radius represent the radius of the circle\n        * (optional) angle_start and angle_end are in degree. The default\n            value is 0 and 360.\n        * (optional) segments is the precision of the ellipse. The default\n            value is calculated from the range between angle.\n\n        Note that it's up to you to :attr:`close` the circle or not.\n\n        For example, for building a simple ellipse, in python::\n\n            # simple circle\n            Line(circle=(150, 150, 50))\n\n            # only from 90 to 180 degrees\n            Line(circle=(150, 150, 50, 90, 180))\n\n            # only from 90 to 180 degrees, with few segments\n            Line(circle=(150, 150, 50, 90, 180, 20))\n\n        .. versionadded:: 1.4.1\n        '''\n\n        def __set__(self, args):\n            if args == None:\n                raise GraphicException(\n                        'Invalid circle value: {0!r}'.format(args))\n            if len(args) not in (3, 5, 6):\n                raise GraphicException('Invalid number of arguments: '\n                        '{0} instead of 3, 5 or 6.'.format(len(args)))\n            self._mode_args = tuple(args)\n            self._mode = LINE_MODE_CIRCLE\n            self.flag_update()\n\n    cdef void prebuild_circle(self):\n        cdef double x, y, r, angle_start = 0, angle_end = 360\n        cdef int angle_dir, segments = 0\n        cdef double angle_range\n        cdef tuple args = self._mode_args\n\n        if len(args) == 3:\n            x, y, r = args\n        elif len(args) == 5:\n            x, y, r, angle_start, angle_end = args\n        elif len(args) == 6:\n            x, y, r, angle_start, angle_end, segments = args\n            segments += 1\n        else:\n            x = y = r = 0\n            assert(0)\n\n        if angle_end > angle_start:\n            angle_dir = 1\n        else:\n            angle_dir = -1\n        if segments == 0:\n            segments = int(abs(angle_end - angle_start) / 2) + 3\n        \n        segmentpoints = segments * 2\n        \n        # rad = deg * (pi / 180), where pi/180 = 0.0174...\n        angle_start = angle_start * 0.017453292519943295\n        angle_end = angle_end * 0.017453292519943295\n        angle_range = abs(angle_end - angle_start) / (segmentpoints - 2)\n\n        cdef list points = [0, ] * segmentpoints\n        cdef double angle\n        for i in xrange(0, segmentpoints, 2):\n            angle = angle_start + (angle_dir * i * angle_range)\n            points[i] = x + (r * sin(angle))\n            points[i + 1] = y + (r * cos(angle))\n        self._points = points\n\n    property rectangle:\n        '''Use this property to build a rectangle, without calculating the\n        :attr:`points`. You can only set this property, not get it.\n\n        The argument must be a tuple of (x, y, width, height)\n        angle_end, segments):\n\n        * x and y represent the bottom-left position of the rectangle\n        * width and height represent the size\n\n        The line is automatically closed.\n\n        Usage::\n\n            Line(rectangle=(0, 0, 200, 200))\n\n        .. versionadded:: 1.4.1\n        '''\n\n        def __set__(self, args):\n            if args == None:\n                raise GraphicException(\n                        'Invalid rectangle value: {0!r}'.format(args))\n            if len(args) != 4:\n                raise GraphicException('Invalid number of arguments: '\n                        '{0} instead of 4.'.format(len(args)))\n            self._mode_args = tuple(args)\n            self._mode = LINE_MODE_RECTANGLE\n            self.flag_update()\n\n    cdef void prebuild_rectangle(self):\n        cdef double x, y, width, height\n        cdef int angle_dir, segments = 0\n        cdef double angle_range\n        cdef tuple args = self._mode_args\n\n        if args == None:\n            raise GraphicException(\n                    'Invalid ellipse value: {0!r}'.format(args))\n\n        if len(args) == 4:\n            x, y, width, height = args\n        else:\n            x = y = width = height = 0\n            assert(0)\n\n        self._points = [x, y, x + width, y, x + width, y + height, x, y + height]\n        self._close = 1\n\n    property rounded_rectangle:\n        '''Use this property to build a rectangle, without calculating the\n        :attr:`points`. You can only set this property, not get it.\n\n        The argument must be a tuple of one of the following forms:\n\n        * (x, y, width, height, corner_radius)\n        * (x, y, width, height, corner_radius, resolution)\n        * (x, y, width, height, corner_radius1, corner_radius2, corner_radius3, corner_radius4)\n        * (x, y, width, height, corner_radius1, corner_radius2, corner_radius3, corner_radius4, resolution)\n\n        * x and y represent the bottom-left position of the rectangle\n        * width and height represent the size\n        * corner_radius is the number of pixels between two borders and the center of the circle arc joining them\n        * resolution is the numper of line segment that will be used to draw the circle arc at each corner (defaults to 30)\n\n        The line is automatically closed.\n\n        Usage::\n\n            Line(rounded_rectangle=(0, 0, 200, 200, 10, 20, 30, 40, 100))\n\n        .. versionadded:: 1.9.0\n        '''\n        def __set__(self, args):\n            if args == None:\n                raise GraphicException(\n                    'Invlid rounded rectangle value: {0!r}'.format(args))\n            if len(args) not in (5, 6, 8, 9):\n                raise GraphicException('invalid number of arguments:'\n                        '{0} not in (5, 6, 8, 9)'.format(len(args)))\n            self._mode_args = tuple(args)\n            self._mode = LINE_MODE_ROUNDED_RECTANGLE\n            self.flag_update()\n\n    cdef void prebuild_rounded_rectangle(self):\n        cdef float a, px, py, x, y, w, h, c1, c2, c3, c4\n        cdef resolution = 30\n        cdef int l = len(self._mode_args)\n\n        self._points = []\n        a = -PI\n        x, y, w, h = self._mode_args [:4]\n\n        if l == 5:\n            c1 = c2 = c3 = c4 = self._mode_args[4]\n        elif l == 6:\n            c1 = c2 = c3 = c4 = self._mode_args[4]\n            resolution = self._mode_args[5]\n        elif l == 8:\n            c1, c2, c3, c4 = self._mode_args[4:]\n        else:  # l == 9, but else make the compiler happy about uninitialization\n            c1, c2, c3, c4 = self._mode_args[4:8]\n            resolution = self._mode_args[8]\n\n        px = x + c1\n        py = y + c1\n\n        while a < - PI / 2.:\n            a += pi / resolution\n            self._points.extend([\n                px + cos(a) * c1,\n                py + sin(a) * c1])\n\n        px = x + w - c2\n        py = y + c2\n\n        while a < 0:\n            a += PI / resolution\n            self._points.extend([\n                px + cos(a) * c2,\n                py + sin(a) * c2])\n\n        px = x + w - c3\n        py = y + h - c3\n\n        while a < PI / 2.:\n            a += PI / resolution\n            self._points.extend([\n                px + cos(a) * c3,\n                py + sin(a) * c3])\n\n        px = x + c4\n        py = y + h - c4\n\n        while a < PI:\n            a += PI / resolution\n            self._points.extend([\n                px + cos(a) * c4,\n                py + sin(a) * c4])\n\n        self._close = 1\n\n    property bezier:\n        '''Use this property to build a bezier line, without calculating the\n        :attr:`points`. You can only set this property, not get it.\n\n        The argument must be a tuple of 2n elements, n being the number of points.\n\n        Usage::\n\n            Line(bezier=(x1, y1, x2, y2, x3, y3)\n\n        .. versionadded:: 1.4.2\n\n        .. note:: Bezier lines calculations are inexpensive for a low number of\n            points, but complexity is quadratic, so lines with a lot of points\n            can be very expensive to build, use with care!\n        '''\n\n        def __set__(self, args):\n            if args == None or len(args) % 2:\n                raise GraphicException(\n                        'Invalid bezier value: {0!r}'.format(args))\n            self._mode_args = tuple(args)\n            self._mode = LINE_MODE_BEZIER\n            self.flag_update()\n\n    cdef void prebuild_bezier(self):\n        cdef double x, y, l\n        cdef int segments = self._bezier_precision\n        cdef list T = list(self._mode_args)[:]\n\n        self._points = []\n        for x in xrange(segments):\n            l = x / (1.0 * segments)\n            # http://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm\n            # as the list is in the form of (x1, y1, x2, y2...) iteration is\n            # done on each item and the current item (xn or yn) in the list is\n            # replaced with a calculation of \"xn + x(n+1) - xn\" x(n+1) is\n            # placed at n+2. Each iteration makes the list one item shorter\n            for i in range(1, len(T)):\n                for j in xrange(len(T) - 2*i):\n                    T[j] = T[j] + (T[j+2] - T[j]) * l\n\n            # we got the coordinates of the point in T[0] and T[1]\n            self._points.append(T[0])\n            self._points.append(T[1])\n\n        # add one last point to join the curve to the end\n        self._points.append(T[-2])\n        self._points.append(T[-1])\n\n    property bezier_precision:\n        '''Number of iteration for drawing the bezier between 2 segments,\n        defaults to 180. The bezier_precision must be at least 1.\n\n        .. versionadded:: 1.4.2\n        '''\n\n        def __get__(self):\n            return self._bezier_precision\n\n        def __set__(self, value):\n            if value < 1:\n                raise GraphicException('Invalid bezier_precision value, must be >= 1')\n            self._bezier_precision = int(value)\n            self.flag_update()\n\n\ncdef class SmoothLine(Line):\n    '''Experimental line using over-draw method to get better antialiasing\n    results. It has few drawbacks:\n\n    - drawing line with alpha will unlikely doesn't give the intended result if\n      the line cross itself\n    - no cap or joint are supported\n    - it use a custom texture with premultiplied alpha\n    - dash is not supported\n    - line under 1px width are not supported, it will look the same\n\n    .. warning::\n\n        This is an unfinished work, experimental, subject to crash.\n\n    .. versionadded:: 1.9.0\n    '''\n\n    cdef float _owidth\n\n    def __init__(self, **kwargs):\n        VertexInstruction.__init__(self, **kwargs)\n        self._owidth = kwargs.get(\"overdraw_width\") or 1.2\n        self.batch.set_mode(\"triangles\")\n        self.texture = self.premultiplied_texture()\n\n    def premultiplied_texture(self):\n        texture = Texture.create(size=(4, 1), colorfmt=\"rgba\")\n        texture.add_reload_observer(self._smooth_reload_observer)\n        self._smooth_reload_observer(texture)\n        return texture\n\n    cpdef _smooth_reload_observer(self, texture):\n        cdef bytes GRADIENT_DATA = (\n            b\"\\xff\\xff\\xff\\x00\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x00\")\n        texture.blit_buffer(GRADIENT_DATA, colorfmt=\"rgba\")\n\n    cdef void build(self):\n        if self._mode == LINE_MODE_ELLIPSE:\n            self.prebuild_ellipse()\n        elif self._mode == LINE_MODE_CIRCLE:\n            self.prebuild_circle()\n        elif self._mode == LINE_MODE_RECTANGLE:\n            self.prebuild_rectangle()\n        elif self._mode == LINE_MODE_ROUNDED_RECTANGLE:\n            self.prebuild_rounded_rectangle()\n        elif self._mode == LINE_MODE_BEZIER:\n            self.prebuild_bezier()\n\n        self.build_smooth()\n\n    cdef int apply(self) except -1:\n        VertexInstruction.apply(self)\n        return 0\n\n    cdef void build_smooth(self):\n        cdef:\n            list p = self.points\n            float width = max(0, (self._width - 1.))\n            float owidth = width + self._owidth\n            vertex_t *vertices = NULL\n            unsigned short *indices = NULL\n            unsigned short *tindices = NULL\n            double ax, ay, bx = 0., by = 0., rx = 0., ry = 0., last_angle = 0., angle, av_angle\n            float cos1, sin1, cos2, sin2, ocos1, ocos2, osin1, osin2\n            long index, vindex, vcount, icount, iv, ii, max_vindex, count\n            unsigned short i0, i1, i2, i3, i4, i5, i6, i7\n\n        iv = vindex = 0\n        count = len(p) / 2\n        if count < 2:\n            self.batch.clear_data()\n            return\n\n        vcount = count * 4\n        icount = (count - 1) * 18\n        if self._close:\n            icount += 18\n\n        vertices = <vertex_t *>malloc(vcount * sizeof(vertex_t))\n        if vertices == NULL:\n            raise MemoryError(\"vertices\")\n\n        indices = <unsigned short *>malloc(icount * sizeof(unsigned short))\n        if indices == NULL:\n            free(vertices)\n            raise MemoryError(\"indices\")\n\n        if self._close:\n            ax = p[-2]\n            ay = p[-1]\n            bx = p[0]\n            by = p[1]\n            rx = bx - ax\n            ry = by - ay\n            last_angle = atan2(ry, rx)\n\n        max_index = len(p)\n        for index in range(0, max_index, 2):\n            ax = p[index]\n            ay = p[index + 1]\n            if index < max_index - 2:\n                bx = p[index + 2]\n                by = p[index + 3]\n                rx = bx - ax\n                ry = by - ay\n                angle = atan2(ry, rx)\n            else:\n                angle = last_angle\n\n            if index == 0 and not self._close:\n                av_angle = angle\n                ad_angle = pi\n            else:\n                av_angle = atan2(\n                        sin(angle) + sin(last_angle),\n                        cos(angle) + cos(last_angle))\n\n                ad_angle = abs(pi - abs(angle - last_angle))\n\n            a1 = av_angle - PI2\n            a2 = av_angle + PI2\n            '''\n            cos1 = cos(a1) * width\n            sin1 = sin(a1) * width\n            cos2 = cos(a2) * width\n            sin2 = sin(a2) * width\n            ocos1 = cos(a1) * owidth\n            osin1 = sin(a1) * owidth\n            ocos2 = cos(a2) * owidth\n            osin2 = sin(a2) * owidth\n            print 'angle diff', ad_angle\n            '''\n            #l = width\n            #ol = owidth\n\n            if index == 0 or index >= max_index - 2:\n                l = width\n                ol = owidth\n            else:\n                la1 = last_angle - PI2\n                la2 = angle - PI2\n                ra1 = last_angle + PI2\n                ra2 = angle + PI2\n                ox = p[index - 2]\n                oy = p[index - 1]\n                if line_intersection(\n                    ox + cos(la1) * width,\n                    oy + sin(la1) * width,\n                    ax + cos(la1) * width,\n                    ay + sin(la1) * width,\n                    ax + cos(la2) * width,\n                    ay + sin(la2) * width,\n                    bx + cos(la2) * width,\n                    by + sin(la2) * width,\n                    &rx, &ry) == 0:\n                    #print 'ERROR LINE INTERSECTION 1'\n                    pass\n\n                l = sqrt((ax - rx) ** 2 + (ay - ry) ** 2)\n\n                if line_intersection(\n                    ox + cos(ra1) * owidth,\n                    oy + sin(ra1) * owidth,\n                    ax + cos(ra1) * owidth,\n                    ay + sin(ra1) * owidth,\n                    ax + cos(ra2) * owidth,\n                    ay + sin(ra2) * owidth,\n                    bx + cos(ra2) * owidth,\n                    by + sin(ra2) * owidth,\n                    &rx, &ry) == 0:\n                    #print 'ERROR LINE INTERSECTION 2'\n                    pass\n\n                ol = sqrt((ax - rx) ** 2 + (ay - ry) ** 2)\n\n            last_angle = angle\n\n            #l = sqrt(width ** 2 * (1. / sin(av_angle)) ** 2)\n            #l = width / tan(av_angle / 2.)\n            #l = width * sqrt(1 + 1 / (av_angle / 2.))\n            #l = 2 * (width * width * sin(av_angle))\n            #l = 2 * (cos(av_angle / 2.) * width)\n            #l = width / abs(cos(PI2 - 1.5 * ad_angle))\n            cos1 = cos(a1) * l\n            sin1 = sin(a1) * l\n            cos2 = cos(a2) * l\n            sin2 = sin(a2) * l\n\n            #ol = sqrt(owidth ** 2 * (1. / sin(av_angle)) ** 2)\n            #ol = owidth / tan(av_angle / 2.)\n            #ol = owidth * sqrt(1 + 1 / (av_angle / 2.))\n            #ol = 2 * (owidth * owidth * sin(av_angle))\n            #ol = 2 * (cos(av_angle / 2.) * owidth)\n            #ol = owidth / abs(cos(PI2 - 1.5 * ad_angle))\n            ocos1 = cos(a1) * ol\n            osin1 = sin(a1) * ol\n            ocos2 = cos(a2) * ol\n            osin2 = sin(a2) * ol\n\n            x1 = ax + cos1\n            y1 = ay + sin1\n            x2 = ax + cos2\n            y2 = ay + sin2\n\n            ox1 = ax + ocos1\n            oy1 = ay + osin1\n            ox2 = ax + ocos2\n            oy2 = ay + osin2\n\n            vertices[iv].x = x1\n            vertices[iv].y = y1\n            vertices[iv].s0 = 0.5\n            vertices[iv].t0 = 0.25\n            iv += 1\n            vertices[iv].x = x2\n            vertices[iv].y = y2\n            vertices[iv].s0 = 0.5\n            vertices[iv].t0 = 0.75\n            iv += 1\n            vertices[iv].x = ox1\n            vertices[iv].y = oy1\n            vertices[iv].s0 = 1\n            vertices[iv].t0 = 0\n            iv += 1\n            vertices[iv].x = ox2\n            vertices[iv].y = oy2\n            vertices[iv].s0 = 1\n            vertices[iv].t0 = 1\n            iv += 1\n\n        tindices = indices\n        for vindex in range(0, vcount - 4, 4):\n            tindices[0] = vindex\n            tindices[1] = vindex + 2\n            tindices[2] = vindex + 6\n            tindices[3] = vindex\n            tindices[4] = vindex + 6\n            tindices[5] = vindex + 4\n            tindices[6] = vindex + 1\n            tindices[7] = vindex\n            tindices[8] = vindex + 4\n            tindices[9] = vindex + 1\n            tindices[10] = vindex + 4\n            tindices[11] = vindex + 5\n            tindices[12] = vindex + 3\n            tindices[13] = vindex + 1\n            tindices[14] = vindex + 5\n            tindices[15] = vindex + 3\n            tindices[16] = vindex + 5\n            tindices[17] = vindex + 7\n            tindices = tindices + 18\n\n        if self._close:\n            vindex = vcount - 4\n            i0 = vindex\n            i1 = vindex + 1\n            i2 = vindex + 2\n            i3 = vindex + 3\n            i4 = 0\n            i5 = 1\n            i6 = 2\n            i7 = 3\n            tindices[0] = i0\n            tindices[1] = i2\n            tindices[2] = i6\n            tindices[3] = i0\n            tindices[4] = i6\n            tindices[5] = i4\n            tindices[6] = i1\n            tindices[7] = i0\n            tindices[8] = i4\n            tindices[9] = i1\n            tindices[10] = i4\n            tindices[11] = i5\n            tindices[12] = i3\n            tindices[13] = i1\n            tindices[14] = i5\n            tindices[15] = i3\n            tindices[16] = i5\n            tindices[17] = i7\n            tindices = tindices + 18\n\n        #print 'tindices', <long>tindices, <long>indices, (<long>tindices - <long>indices) / sizeof(unsigned short)\n\n\n        self.batch.set_data(vertices, <int>vcount, indices, <int>icount)\n\n        #free(vertices)\n        #free(indices)\n\n\n    property overdraw_width:\n        '''Determine the overdraw width of the line, defaults to 1.2\n        '''\n        def __get__(self):\n            return self._owidth\n\n        def __set__(self, value):\n            if value <= 0:\n                raise GraphicException('Invalid width value, must be > 0')\n            self._owidth = value\n            self.flag_update()\n\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/__init__.py",
    "content": "# pylint: disable=W0611\n'''\nInput management\n================\n\nOur input system is wide and simple at the same time. We are currently able to\nnatively support :\n\n* Windows multitouch events (pencil and finger)\n* MacOSX touchpads\n* Linux multitouch events (kernel and mtdev)\n* Linux wacom drivers (pencil and finger)\n* TUIO\n\nAll the input management is configurable in the Kivy :mod:`~kivy.config`. You\ncan easily use many multitouch devices in one Kivy application.\n\nWhen the events have been read from the devices, they are dispatched through\na post processing module before being sent to your application. We also have\nseveral default modules for :\n\n* Double tap detection\n* Decreasing jittering\n* Decreasing the inaccuracy of touch on \"bad\" DIY hardware\n* Ignoring regions\n'''\n\n\nfrom kivy.input.motionevent import MotionEvent\nfrom kivy.input.postproc import kivy_postproc_modules\nfrom kivy.input.provider import MotionEventProvider\nfrom kivy.input.factory import MotionEventFactory\nimport kivy.input.providers\n\n__all__ = (\n    MotionEvent.__name__,\n    MotionEventProvider.__name__,\n    MotionEventFactory.__name__,\n    'kivy_postproc_modules')\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/factory.py",
    "content": "'''\nMotion Event Factory\n====================\n\nFactory of :class:`~kivy.input.motionevent.MotionEvent` providers.\n'''\n\n__all__ = ('MotionEventFactory', )\n\n\nclass MotionEventFactory:\n    '''MotionEvent factory is a class that registers all availables input\n    factories. If you create a new input factory, you need to register\n    it here::\n\n        MotionEventFactory.register('myproviderid', MyInputProvider)\n\n    '''\n    __providers__ = {}\n\n    @staticmethod\n    def register(name, classname):\n        '''Register a input provider in the database'''\n        MotionEventFactory.__providers__[name] = classname\n\n    @staticmethod\n    def list():\n        '''Get a list of all available providers'''\n        return MotionEventFactory.__providers__\n\n    @staticmethod\n    def get(name):\n        '''Get a provider class from the provider id'''\n        if name in MotionEventFactory.__providers__:\n            return MotionEventFactory.__providers__[name]\n        return None\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/motionevent.py",
    "content": "'''\n.. _motionevent:\n\nMotion Event\n============\n\nThe :class:`MotionEvent` is the base class used for every touch and non-touch\nevent. This class defines all the properties and methods needed to\nhandle 2D and 3D movements but has many more capabilities.\n\n.. note::\n\n    You never create the :class:`MotionEvent` yourself: this is the role of the\n    :mod:`~kivy.input.providers`.\n\nMotion Event and Touch\n----------------------\n\nWe differentiate between a Motion Event and Touch event. A Touch event is a\n:class:`MotionEvent` with the `pos` profile. Only these events are dispatched\nthroughout the widget tree.\n\n1. The :class:`MotionEvent` 's are gathered from input providers.\n2. All the :class:`MotionEvent` 's are dispatched from\n    :meth:`~kivy.core.window.WindowBase.on_motion`.\n3. If a :class:`MotionEvent` has a `pos` profile, we dispatch it through\n    :meth:`~kivy.core.window.WindowBase.on_touch_down`,\n    :meth:`~kivy.core.window.WindowBase.on_touch_move` and\n    :meth:`~kivy.core.window.WindowBase.on_touch_up`.\n\nListening to a Motion Event\n---------------------------\n\nIf you want to receive all MotionEvents, Touch or not, you can bind the\nMotionEvent from the :class:`~kivy.core.window.Window` to your own callback::\n\n    def on_motion(self, etype, motionevent):\n        # will receive all motion events.\n        pass\n\n    Window.bind(on_motion=on_motion)\n\nYou can also listen to changes of the mouse position by watching\n:attr:`~kivy.core.window.WindowBase.mouse_pos`.\n\nProfiles\n--------\n\nA capability is the ability of a :class:`MotionEvent` to store new\ninformation or a way to indicate what is supported by the MotionEvent.\nFor example, you can receive a MotionEvent that has an angle, a fiducial\nID, or even a shape. You can check the :attr:`~MotionEvent.profile`\nattribute to check what is currently supported by the MotionEvent and\nhow to access it.\n\nThis is a tiny list of the supported profiles by default. Check other input\nproviders to see if there are other profiles available.\n\n============== ================================================================\nProfile name   Description\n-------------- ----------------------------------------------------------------\nangle          2D angle. Use property `a`\nbutton         Mouse button (left, right, middle, scrollup, scrolldown)\n               Use property `button`\nmarkerid       Marker or Fiducial ID. Use property `fid`\npos            2D position. Use properties `x`, `y` or `pos``\npos3d          3D position. Use properties `x`, `y`, `z`\npressure       Pressure of the contact. Use property `pressure`\nshape          Contact shape. Use property `shape`\n============== ================================================================\n\nIf you want to know whether the current :class:`MotionEvent` has an angle::\n\n    def on_touch_move(self, touch):\n        if 'angle' in touch.profile:\n            print('The touch angle is', touch.a)\n\nIf you want to select only the fiducials::\n\n    def on_touch_move(self, touch):\n        if 'markerid' not in touch.profile:\n            return\n\n'''\n\n__all__ = ('MotionEvent', )\n\nimport weakref\nfrom inspect import isroutine\nfrom copy import copy\nfrom time import time\nfrom kivy.vector import Vector\n\n\nclass EnhancedDictionary(dict):\n\n    def __getattr__(self, attr):\n        try:\n            return self.__getitem__(attr)\n        except KeyError:\n            return super(EnhancedDictionary, self).__getattr__(attr)\n\n    def __setattr__(self, attr, value):\n        self.__setitem__(attr, value)\n\n\nclass MotionEventMetaclass(type):\n\n    def __new__(mcs, name, bases, attrs):\n        __attrs__ = []\n        for base in bases:\n            if hasattr(base, '__attrs__'):\n                __attrs__.extend(base.__attrs__)\n        if '__attrs__' in attrs:\n            __attrs__.extend(attrs['__attrs__'])\n        attrs['__attrs__'] = tuple(__attrs__)\n        return super(MotionEventMetaclass, mcs).__new__(mcs, name,\n                                                        bases, attrs)\n\n\nMotionEventBase = MotionEventMetaclass('MotionEvent', (object, ), {})\n\n\nclass MotionEvent(MotionEventBase):\n    '''Abstract class to represent a touch and non-touch object.\n\n    :Parameters:\n        `id` : str\n            unique ID of the MotionEvent\n        `args` : list\n            list of parameters, passed to the depack() function\n    '''\n\n    __uniq_id = 0\n    __attrs__ = \\\n        ('device', 'push_attrs', 'push_attrs_stack',\n         'is_touch', 'id', 'shape', 'profile',\n         # current position, in 0-1 range\n         'sx', 'sy', 'sz',\n         # first position set, in 0-1 range\n         'osx', 'osy', 'osz',\n         # last position set, in 0-1 range\n         'psx', 'psy', 'psz',\n         # delta from the last position and current one, in 0-1 range\n         'dsx', 'dsy', 'dsz',\n         # current position, in screen range\n         'x', 'y', 'z',\n         # first position set, in screen range\n         'ox', 'oy', 'oz',\n         # last position set, in 0-1 range\n         'px', 'py', 'pz',\n         # delta from the last position and current one, in screen range\n         'dx', 'dy', 'dz',\n         'time_start',\n         'is_double_tap', 'double_tap_time',\n         'is_triple_tap', 'triple_tap_time',\n         'ud')\n\n    def __init__(self, device, id, args):\n        if self.__class__ == MotionEvent:\n            raise NotImplementedError('class MotionEvent is abstract')\n        MotionEvent.__uniq_id += 1\n\n        #: True if the Motion Event is a Touch. Can be also verified is\n        #: `pos` is :attr:`profile`.\n        self.is_touch = False\n\n        #: Attributes to push by default, when we use :meth:`push` : x, y, z,\n        #: dx, dy, dz, ox, oy, oz, px, py, pz.\n        self.push_attrs_stack = []\n        self.push_attrs = ('x', 'y', 'z', 'dx', 'dy', 'dz', 'ox', 'oy', 'oz',\n                           'px', 'py', 'pz', 'pos')\n\n        #: Uniq ID of the touch. You can safely use this property, it will be\n        #: never the same accross all existing touches.\n        self.uid = MotionEvent.__uniq_id\n\n        #: Device used for creating this touch\n        self.device = device\n\n        # For grab\n        self.grab_list = []\n        self.grab_exclusive_class = None\n        self.grab_state = False\n\n        #: Used to determine which widget the touch is being dispatched to.\n        #: Check the :meth:`grab` function for more information.\n        self.grab_current = None\n\n        #: Profiles currently used in the touch\n        self.profile = []\n\n        #: Id of the touch, not uniq. This is generally the Id set by the input\n        #: provider, like ID in TUIO. If you have multiple TUIO source,\n        #: the same id can be used. Prefer to use :attr:`uid` attribute\n        #: instead.\n        self.id = id\n\n        #: Shape of the touch, subclass of\n        #: :class:`~kivy.input.shape.Shape`.\n        #: By default, the property is set to None\n        self.shape = None\n\n        #: X position, in 0-1 range\n        self.sx = 0.0\n        #: Y position, in 0-1 range\n        self.sy = 0.0\n        #: Z position, in 0-1 range\n        self.sz = 0.0\n        #: Origin X position, in 0-1 range.\n        self.osx = None\n        #: Origin Y position, in 0-1 range.\n        self.osy = None\n        #: Origin Z position, in 0-1 range.\n        self.osz = None\n        #: Previous X position, in 0-1 range.\n        self.psx = None\n        #: Previous Y position, in 0-1 range.\n        self.psy = None\n        #: Previous Z position, in 0-1 range.\n        self.psz = None\n        #: Delta between self.sx and self.psx, in 0-1 range.\n        self.dsx = None\n        #: Delta between self.sy and self.psy, in 0-1 range.\n        self.dsy = None\n        #: Delta between self.sz and self.psz, in 0-1 range.\n        self.dsz = None\n        #: X position, in window range\n        self.x = 0.0\n        #: Y position, in window range\n        self.y = 0.0\n        #: Z position, in window range\n        self.z = 0.0\n        #: Origin X position, in window range\n        self.ox = None\n        #: Origin Y position, in window range\n        self.oy = None\n        #: Origin Z position, in window range\n        self.oz = None\n        #: Previous X position, in window range\n        self.px = None\n        #: Previous Y position, in window range\n        self.py = None\n        #: Previous Z position, in window range\n        self.pz = None\n        #: Delta between self.x and self.px, in window range\n        self.dx = None\n        #: Delta between self.y and self.py, in window range\n        self.dy = None\n        #: Delta between self.z and self.pz, in window range\n        self.dz = None\n        #: Position (X, Y), in window range\n        self.pos = (0.0, 0.0)\n\n        #: Initial time of the touch creation\n        self.time_start = time()\n\n        #: Time of the last update\n        self.time_update = self.time_start\n\n        #: Time of the end event (last touch usage)\n        self.time_end = -1\n\n        #: Indicate if the touch is a double tap or not\n        self.is_double_tap = False\n\n        #: Indicate if the touch is a triple tap or not\n        #:\n        #: .. versionadded:: 1.7.0\n        self.is_triple_tap = False\n\n        #: If the touch is a :attr:`is_double_tap`, this is the time\n        #: between the previous tap and the current touch.\n        self.double_tap_time = 0\n\n        #: If the touch is a :attr:`is_triple_tap`, this is the time\n        #: between the first tap and the current touch.\n        #:\n        #: .. versionadded:: 1.7.0\n        self.triple_tap_time = 0\n\n        #: User data dictionary. Use this dictionary to save your own data on\n        #: the touch.\n        self.ud = EnhancedDictionary()\n\n        self.depack(args)\n\n    def depack(self, args):\n        '''Depack `args` into attributes of the class'''\n        # set initial position and last position\n        if self.osx is None:\n            self.psx = self.osx = self.sx\n            self.psy = self.osy = self.sy\n            self.psz = self.osz = self.sz\n        # update the delta\n        self.dsx = self.sx - self.psx\n        self.dsy = self.sy - self.psy\n        self.dsz = self.sz - self.psz\n\n    def grab(self, class_instance, exclusive=False):\n        '''Grab this motion event. You can grab a touch if you absolutly\n        want to receive on_touch_move() and on_touch_up(), even if the\n        touch is not dispatched by your parent::\n\n            def on_touch_down(self, touch):\n                touch.grab(self)\n\n            def on_touch_move(self, touch):\n                if touch.grab_current is self:\n                    # I received my grabbed touch\n                else:\n                    # it's a normal touch\n\n            def on_touch_up(self, touch):\n                if touch.grab_current is self:\n                    # I receive my grabbed touch, I must ungrab it!\n                    touch.ungrab(self)\n                else:\n                    # it's a normal touch\n                    pass\n        '''\n        if not self.is_touch:\n            raise Exception('Grab works only for Touch MotionEvents.')\n        if self.grab_exclusive_class is not None:\n            raise Exception('Cannot grab the touch, touch is exclusive')\n        class_instance = weakref.ref(class_instance.__self__)\n        if exclusive:\n            self.grab_exclusive_class = class_instance\n        self.grab_list.append(class_instance)\n\n    def ungrab(self, class_instance):\n        '''Ungrab a previously grabbed touch\n        '''\n        class_instance = weakref.ref(class_instance.__self__)\n        if self.grab_exclusive_class == class_instance:\n            self.grab_exclusive_class = None\n        if class_instance in self.grab_list:\n            self.grab_list.remove(class_instance)\n\n    def move(self, args):\n        '''Move the touch to another position\n        '''\n        self.px = self.x\n        self.py = self.y\n        self.pz = self.z\n        self.psx = self.sx\n        self.psy = self.sy\n        self.psz = self.sz\n        self.time_update = time()\n        self.depack(args)\n\n    def scale_for_screen(self, w, h, p=None, rotation=0,\n                         smode='None', kheight=0):\n        '''Scale position for the screen\n        '''\n        sx, sy = self.sx, self.sy\n        if rotation == 0:\n            self.x = sx * float(w)\n            self.y = sy * float(h)\n        elif rotation == 90:\n            sx, sy = sy, 1 - sx\n            self.x = sx * float(h)\n            self.y = sy * float(w)\n        elif rotation == 180:\n            sx, sy = 1 - sx, 1 - sy\n            self.x = sx * float(w)\n            self.y = sy * float(h)\n        elif rotation == 270:\n            sx, sy = 1 - sy, sx\n            self.x = sx * float(h)\n            self.y = sy * float(w)\n\n        if p:\n            self.z = self.sz * float(p)\n\n        if smode:\n            if smode == 'pan':\n                self.y -= kheight\n            elif smode == 'scale':\n                self.y += (kheight * (\n                    (self.y - kheight) / (h - kheight))) - kheight\n\n        if self.ox is None:\n            self.px = self.ox = self.x\n            self.py = self.oy = self.y\n            self.pz = self.oz = self.z\n\n        self.dx = self.x - self.px\n        self.dy = self.y - self.py\n        self.dz = self.z - self.pz\n\n        # cache position\n        self.pos = self.x, self.y\n\n    def push(self, attrs=None):\n        '''Push attribute values in `attrs` onto the stack\n        '''\n        if attrs is None:\n            attrs = self.push_attrs\n        values = [getattr(self, x) for x in attrs]\n        self.push_attrs_stack.append((attrs, values))\n\n    def pop(self):\n        '''Pop attributes values from the stack\n        '''\n        attrs, values = self.push_attrs_stack.pop()\n        for i in range(len(attrs)):\n            setattr(self, attrs[i], values[i])\n\n    def apply_transform_2d(self, transform):\n        '''Apply a transformation on x, y, z, px, py, pz,\n        ox, oy, oz, dx, dy, dz\n        '''\n        self.x, self.y = self.pos = transform(self.x, self.y)\n        self.px, self.py = transform(self.px, self.py)\n        self.ox, self.oy = transform(self.ox, self.oy)\n        self.dx = self.x - self.px\n        self.dy = self.y - self.py\n\n    def copy_to(self, to):\n        '''Copy some attribute to another touch object.'''\n        for attr in self.__attrs__:\n            to.__setattr__(attr, copy(self.__getattribute__(attr)))\n\n    def distance(self, other_touch):\n        '''Return the distance between the current touch and another touch.\n        '''\n        return Vector(self.pos).distance(other_touch.pos)\n\n    def update_time_end(self):\n        self.time_end = time()\n\n    # facilities\n    @property\n    def dpos(self):\n        '''Return delta between last position and current position, in the\n        screen coordinate system (self.dx, self.dy)'''\n        return self.dx, self.dy\n\n    @property\n    def opos(self):\n        '''Return the initial position of the touch in the screen\n        coordinate system (self.ox, self.oy)'''\n        return self.ox, self.oy\n\n    @property\n    def ppos(self):\n        '''Return the previous position of the touch in the screen\n        coordinate system (self.px, self.py)'''\n        return self.px, self.py\n\n    @property\n    def spos(self):\n        '''Return the position in the 0-1 coordinate system\n        (self.sx, self.sy)'''\n        return self.sx, self.sy\n\n    def __str__(self):\n        basename = str(self.__class__)\n        classname = basename.split('.')[-1].replace('>', '').replace('\\'', '')\n        return '<%s spos=%s pos=%s>' % (classname, self.spos, self.pos)\n\n    def __repr__(self):\n        out = []\n        for x in dir(self):\n            v = getattr(self, x)\n            if x[0] == '_':\n                continue\n            if isroutine(v):\n                continue\n            out.append('%s=\"%s\"' % (x, v))\n        return '<%s %s>' % (\n            self.__class__.__name__,\n            ' '.join(out))\n\n    @property\n    def is_mouse_scrolling(self, *args):\n        '''Returns True if the touch is a mousewheel scrolling\n\n        .. versionadded:: 1.6.0\n        '''\n        return 'button' in self.profile and 'scroll' in self.button\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/postproc/__init__.py",
    "content": "'''\nInput Postprocessing\n====================\n\n'''\n\n__all__ = ('kivy_postproc_modules', )\n\nimport os\nfrom kivy.input.postproc.doubletap import InputPostprocDoubleTap\nfrom kivy.input.postproc.tripletap import InputPostprocTripleTap\nfrom kivy.input.postproc.ignorelist import InputPostprocIgnoreList\nfrom kivy.input.postproc.retaintouch import InputPostprocRetainTouch\nfrom kivy.input.postproc.dejitter import InputPostprocDejitter\nfrom kivy.input.postproc.calibration import InputPostprocCalibration\n\n# Mapping of ID to module\nkivy_postproc_modules = {}\n\n# Don't go further if we generate documentation\nif 'KIVY_DOC' not in os.environ:\n    kivy_postproc_modules['calibration'] = InputPostprocCalibration()\n    kivy_postproc_modules['retaintouch'] = InputPostprocRetainTouch()\n    kivy_postproc_modules['ignorelist'] = InputPostprocIgnoreList()\n    kivy_postproc_modules['doubletap'] = InputPostprocDoubleTap()\n    kivy_postproc_modules['tripletap'] = InputPostprocTripleTap()\n    kivy_postproc_modules['dejitter'] = InputPostprocDejitter()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/postproc/calibration.py",
    "content": "'''\nCalibration\n===========\n\n.. versionadded:: 1.9.0\n\nRecalibrate input device to a specific range / offset.\n\nLet's say you have 3 1080p displays, the 2 firsts are multitouch. By default,\nboth will have mixed touch, the range will conflict with each others: the 0-1\nrange will goes to 0-5760 px (remember, 3 * 1920 = 5760.)\n\nTo fix it, you need to manually reference them. For example::\n\n    [input]\n    left = mtdev,/dev/input/event17\n    middle = mtdev,/dev/input/event15\n    # the right screen is just a display.\n\nThen, you can use the calibration postproc module::\n\n    [postproc:calibration]\n    left = xratio=0.3333\n    middle = xratio=0.3333,xoffset=0.3333\n\nNow, the touches from the left screen will be within 0-0.3333 range, and the\ntouches from the middle screen will be within 0.3333-0.6666 range.\n\n'''\n\n__all__ = ('InputPostprocCalibration', )\n\nfrom kivy.config import Config\nfrom kivy.logger import Logger\n\n\nclass InputPostprocCalibration(object):\n    '''Recalibrate the inputs.\n\n    The configuration must go within a section named `postproc:calibration`.\n    Within the section, you must have line like::\n\n        devicename = param=value,param=value\n\n    :Parameters:\n        `xratio`: float\n            Value to multiply X\n        `yratio`: float\n            Value to multiply Y\n        `xoffset`: float\n            Value to add to X\n        `yoffset`: float\n            Value to add to Y\n\n    '''\n\n    def __init__(self):\n        super(InputPostprocCalibration, self).__init__()\n        self.devices = {}\n        self.frame = 0\n        if not Config.has_section('postproc:calibration'):\n            return\n        default_params = {'xoffset': 0, 'yoffset': 0, 'xratio': 1, 'yratio': 1}\n        for device_key, params_str in Config.items('postproc:calibration'):\n            params = default_params.copy()\n            for param in params_str.split(','):\n                param = param.strip()\n                if not param:\n                    continue\n                key, value = param.split('=', 1)\n                if key not in ('xoffset', 'yoffset', 'xratio', 'yratio'):\n                    Logger.error(\n                        'Calibration: invalid key provided: {}'.format(key))\n                params[key] = float(value)\n            self.devices[device_key] = params\n\n    def process(self, events):\n        # avoid doing any processing if there is no device to calibrate at all.\n        if not self.devices:\n            return events\n\n        self.frame += 1\n        frame = self.frame\n        for etype, event in events:\n            if event.device not in self.devices:\n                continue\n            # some providers use the same event to update and end\n            if 'calibration:frame' not in event.ud:\n                event.ud['calibration:frame'] = frame\n            elif event.ud['calibration:frame'] == frame:\n                continue\n            params = self.devices[event.device]\n            event.sx = event.sx * params['xratio'] + params['xoffset']\n            event.sy = event.sy * params['yratio'] + params['yoffset']\n            event.ud['calibration:frame'] = frame\n        return events\n\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/postproc/dejitter.py",
    "content": "'''\nDejitter\n========\n\nPrevent blob jittering.\n\nA problem that is often faced (esp. in optical MT setups) is that of\njitterish BLOBs caused by bad camera characteristics. With this module\nyou can get rid of that jitter. You just define a threshold\n`jitter_distance` in your config, and all touch movements that move\nthe touch by less than the jitter distance are considered 'bad'\nmovements caused by jitter and will be discarded.\n'''\n\n__all__ = ('InputPostprocDejitter', )\n\nfrom kivy.config import Config\n\n\nclass InputPostprocDejitter(object):\n    '''\n    Get rid of jitterish BLOBs.\n    Example::\n\n        [postproc]\n        jitter_distance = 0.004\n        jitter_ignore_devices = mouse,mactouch\n\n    :Configuration:\n        `jitter_distance`: float\n            A float in range 0-1.\n        `jitter_ignore_devices`: string\n            A comma-seperated list of device identifiers that\n            should not be processed by dejitter (because they're\n            very precise already).\n    '''\n\n    def __init__(self):\n        self.jitterdist = Config.getfloat('postproc', 'jitter_distance')\n        ignore_devices = Config.get('postproc', 'jitter_ignore_devices')\n        self.ignore_devices = ignore_devices.split(',')\n        self.last_touches = {}\n\n    def taxicab_distance(self, p, q):\n        # Get the taxicab/manhattan/citiblock distance for efficiency reasons\n        return abs(p[0] - q[0]) + abs(p[1] - q[1])\n\n    def process(self, events):\n        if not self.jitterdist:\n            return events\n        processed = []\n        for etype, touch in events:\n            if not touch.is_touch:\n                continue\n            if touch.device in self.ignore_devices:\n                processed.append((etype, touch))\n                continue\n            if etype == 'begin':\n                self.last_touches[touch.id] = touch.spos\n            if etype == 'end':\n                del self.last_touches[touch.id]\n            if etype != 'update':\n                processed.append((etype, touch))\n                continue\n            # Check whether the touch moved more than the jitter distance\n            last_spos = self.last_touches[touch.id]\n            dist = self.taxicab_distance(last_spos, touch.spos)\n            if dist > self.jitterdist:\n                # Only if the touch has moved more than the jitter dist we take\n                # it into account and dispatch it. Otherwise suppress it.\n                self.last_touches[touch.id] = touch.spos\n                processed.append((etype, touch))\n        return processed\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/postproc/doubletap.py",
    "content": "'''\nDouble Tap\n==========\n\nSearch touch for a double tap\n'''\n\n__all__ = ('InputPostprocDoubleTap', )\n\nfrom time import time\nfrom kivy.config import Config\nfrom kivy.vector import Vector\n\n\nclass InputPostprocDoubleTap(object):\n    '''\n    InputPostProcDoubleTap is a post-processor to check if\n    a touch is a double tap or not.\n    Double tap can be configured in the Kivy config file::\n\n        [postproc]\n        double_tap_time = 250\n        double_tap_distance = 20\n\n    Distance parameter is in the range 0-1000 and time is in milliseconds.\n    '''\n\n    def __init__(self):\n        dist = Config.getint('postproc', 'double_tap_distance')\n        self.double_tap_distance = dist / 1000.0\n        tap_time = Config.getint('postproc', 'double_tap_time')\n        self.double_tap_time = tap_time / 1000.0\n        self.touches = {}\n\n    def find_double_tap(self, ref):\n        '''Find a double tap touch within self.touches.\n        The touch must be not a previous double tap and the distance must be\n        within the specified threshold. Additionally, the touch profiles\n        must be the same kind of touch.\n        '''\n        ref_button = None\n        if 'button' in ref.profile:\n            ref_button = ref.button\n\n        for touchid in self.touches:\n            if ref.uid == touchid:\n                continue\n            etype, touch = self.touches[touchid]\n            if etype != 'end':\n                continue\n            if touch.is_double_tap:\n                continue\n            distance = Vector.distance(\n                Vector(ref.sx, ref.sy),\n                Vector(touch.osx, touch.osy))\n            if distance > self.double_tap_distance:\n                continue\n            if touch.is_mouse_scrolling or ref.is_mouse_scrolling:\n                continue\n            touch_button = None\n            if 'button' in touch.profile:\n                touch_button = touch.button\n            if touch_button != ref_button:\n                continue\n            touch.double_tap_distance = distance\n            return touch\n        return None\n\n    def process(self, events):\n        if self.double_tap_distance == 0 or self.double_tap_time == 0:\n            return events\n        # first, check if a touch down have a double tap\n        for etype, touch in events:\n            if not touch.is_touch:\n                continue\n            if etype == 'begin':\n                double_tap = self.find_double_tap(touch)\n                if double_tap:\n                    touch.is_double_tap = True\n                    tap_time = touch.time_start - double_tap.time_start\n                    touch.double_tap_time = tap_time\n                    distance = double_tap.double_tap_distance\n                    touch.double_tap_distance = distance\n\n            # add the touch internaly\n            self.touches[touch.uid] = (etype, touch)\n\n        # second, check if up-touch is timeout for double tap\n        time_current = time()\n        to_delete = []\n        for touchid in self.touches.keys():\n            etype, touch = self.touches[touchid]\n            if etype != 'end':\n                continue\n            if time_current - touch.time_start < self.double_tap_time:\n                continue\n            to_delete.append(touchid)\n\n        for touchid in to_delete:\n            del self.touches[touchid]\n\n        return events\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/postproc/ignorelist.py",
    "content": "'''\nIgnore list\n===========\n\nIgnore touch on some areas of the screen\n'''\n\n__all__ = ('InputPostprocIgnoreList', )\n\nfrom kivy.config import Config\nfrom kivy.utils import strtotuple\n\n\nclass InputPostprocIgnoreList(object):\n    '''\n    InputPostprocIgnoreList is a post-processor which removes touches in the\n    Ignore list. The Ignore list can be configured in the Kivy config file::\n\n        [postproc]\n        # Format: [(xmin, ymin, xmax, ymax), ...]\n        ignore = [(0.1, 0.1, 0.15, 0.15)]\n\n    The Ignore list coordinates are in the range 0-1, not in screen pixels.\n    '''\n\n    def __init__(self):\n        self.ignore_list = strtotuple(Config.get('postproc', 'ignore'))\n\n    def collide_ignore(self, touch):\n        x, y = touch.sx, touch.sy\n        for l in self.ignore_list:\n            xmin, ymin, xmax, ymax = l\n            if x > xmin and x < xmax and y > ymin and y < ymax:\n                return True\n\n    def process(self, events):\n        if not len(self.ignore_list):\n            return events\n        for etype, touch in events:\n            if not touch.is_touch:\n                continue\n            if etype != 'begin':\n                continue\n            if self.collide_ignore(touch):\n                touch.ud.__pp_ignore__ = True\n        return [(etype, touch) for etype, touch in events\n                if not '__pp_ignore__' in touch.ud]\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/postproc/retaintouch.py",
    "content": "'''\nRetain Touch\n============\n\nReuse touch to counter lost finger behavior\n'''\n\n__all__ = ('InputPostprocRetainTouch', )\n\nfrom kivy.config import Config\nfrom kivy.vector import Vector\nimport time\n\n\nclass InputPostprocRetainTouch(object):\n    '''\n    InputPostprocRetainTouch is a post-processor to delay the 'up' event of a\n    touch, to reuse it under certains conditions. This module is designed to\n    prevent lost finger touches on some hardware/setups.\n\n    Retain touch can be configured in the Kivy config file::\n\n        [postproc]\n            retain_time = 100\n            retain_distance = 50\n\n    The distance parameter is in the range 0-1000 and time is in milliseconds.\n    '''\n\n    def __init__(self):\n        self.timeout = Config.getint('postproc', 'retain_time') / 1000.0\n        self.distance = Config.getint('postproc', 'retain_distance') / 1000.0\n        self._available = []\n        self._links = {}\n\n    def process(self, events):\n        # check if module is disabled\n        if self.timeout == 0:\n            return events\n\n        d = time.time()\n        for etype, touch in events[:]:\n            if not touch.is_touch:\n                continue\n            if etype == 'end':\n                events.remove((etype, touch))\n                if touch.uid in self._links:\n                    selection = self._links[touch.uid]\n                    selection.ud.__pp_retain_time__ = d\n                    self._available.append(selection)\n                    del self._links[touch.uid]\n                else:\n                    touch.ud.__pp_retain_time__ = d\n                    self._available.append(touch)\n            elif etype == 'update':\n                if touch.uid in self._links:\n                    selection = self._links[touch.uid]\n                    selection.x = touch.x\n                    selection.y = touch.y\n                    selection.sx = touch.sx\n                    selection.sy = touch.sy\n                    events.remove((etype, touch))\n                    events.append((etype, selection))\n                else:\n                    pass\n            elif etype == 'begin':\n                # new touch, found the nearest one\n                selection = None\n                selection_distance = 99999\n                for touch2 in self._available:\n                    touch_distance = Vector(touch2.spos).distance(touch.spos)\n                    if touch_distance > self.distance:\n                        continue\n                    if touch2.__class__ != touch.__class__:\n                        continue\n                    if touch_distance < selection_distance:\n                        # eligible for continuation\n                        selection_distance = touch_distance\n                        selection = touch2\n                if selection is None:\n                    continue\n\n                self._links[touch.uid] = selection\n                self._available.remove(selection)\n                events.remove((etype, touch))\n\n        for touch in self._available[:]:\n            t = touch.ud.__pp_retain_time__\n            if d - t > self.timeout:\n                self._available.remove(touch)\n                events.append(('end', touch))\n\n        return events\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/postproc/tripletap.py",
    "content": "'''\nTriple Tap\n==========\n\n.. versionadded:: 1.7.0\n\nSearch touch for a triple tap\n'''\n\n__all__ = ('InputPostprocTripleTap', )\n\nfrom time import time\nfrom kivy.config import Config\nfrom kivy.vector import Vector\nfrom kivy.clock import Clock\n\n\nclass InputPostprocTripleTap(object):\n    '''\n    InputPostProcTripleTap is a post-processor to check if\n    a touch is a triple tap or not.\n    Triple tap can be configured in the Kivy config file::\n\n        [postproc]\n        triple_tap_time = 250\n        triple_tap_distance = 20\n\n    The distance parameter is in the range 0-1000 and time is in milliseconds.\n    '''\n\n    def __init__(self):\n        dist = Config.getint('postproc', 'triple_tap_distance')\n        self.triple_tap_distance = dist / 1000.0\n        time = Config.getint('postproc', 'triple_tap_time')\n        self.triple_tap_time = time / 1000.0\n        self.touches = {}\n\n    def find_triple_tap(self, ref):\n        '''Find a triple tap touch within *self.touches*.\n        The touch must be not be a previous triple tap and the distance\n        must be be within the bounds specified. Additionally, the touch profile\n        must be the same kind of touch.\n        '''\n        ref_button = None\n        if 'button' in ref.profile:\n            ref_button = ref.button\n\n        for touchid in self.touches:\n            if ref.uid == touchid:\n                continue\n            etype, touch = self.touches[touchid]\n            if not touch.is_double_tap:\n                continue\n            if etype != 'end':\n                continue\n            if touch.is_triple_tap:\n                continue\n            distance = Vector.distance(\n                Vector(ref.sx, ref.sy),\n                Vector(touch.osx, touch.osy))\n            if distance > self.triple_tap_distance:\n                continue\n            if touch.is_mouse_scrolling or ref.is_mouse_scrolling:\n                continue\n            touch_button = None\n            if 'button' in touch.profile:\n                touch_button = touch.button\n            if touch_button != ref_button:\n                continue\n            touch.triple_tap_distance = distance\n            return touch\n        return None\n\n    def process(self, events):\n        if self.triple_tap_distance == 0 or self.triple_tap_time == 0:\n            return events\n        # first, check if a touch down have a triple tap\n        for etype, touch in events:\n            if not touch.is_touch:\n                continue\n            if etype == 'begin':\n                triple_tap = self.find_triple_tap(touch)\n                if triple_tap:\n                    touch.is_double_tap = False\n                    touch.is_triple_tap = True\n                    tap_time = touch.time_start - triple_tap.time_start\n                    touch.triple_tap_time = tap_time\n                    distance = triple_tap.triple_tap_distance\n                    touch.triple_tap_distance = distance\n\n            # add the touch internaly\n            self.touches[touch.uid] = (etype, touch)\n\n        # second, check if up-touch is timeout for triple tap\n        time_current = time()\n        to_delete = []\n        for touchid in self.touches.keys():\n            etype, touch = self.touches[touchid]\n            if etype != 'end':\n                continue\n            if time_current - touch.time_start < self.triple_tap_time:\n                continue\n            to_delete.append(touchid)\n\n        for touchid in to_delete:\n            del self.touches[touchid]\n\n        return events\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/provider.py",
    "content": "'''\nMotion Event Provider\n=====================\n\nAbstract class for the implemention of a\n:class:`~kivy.input.motionevent.MotionEvent`\nprovider. The implementation must support the\n:meth:`~MotionEventProvider.start`, :meth:`~MotionEventProvider.stop` and\n:meth:`~MotionEventProvider.update` methods.\n'''\n\n__all__ = ('MotionEventProvider', )\n\n\nclass MotionEventProvider(object):\n    '''Base class for a provider.\n    '''\n\n    def __init__(self, device, args):\n        self.device = device\n        if self.__class__ == MotionEventProvider:\n            raise NotImplementedError('class MotionEventProvider is abstract')\n\n    def start(self):\n        '''Start the provider. This method is automatically called when the\n        application is started and if the configuration uses the current\n        provider.\n        '''\n        pass\n\n    def stop(self):\n        '''Stop the provider.\n        '''\n        pass\n\n    def update(self, dispatch_fn):\n        '''Update the provider and dispatch all the new touch events though the\n        `dispatch_fn` argument.\n        '''\n        pass\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/providers/__init__.py",
    "content": "# pylint: disable=W0611\n'''\nProviders\n=========\n\n'''\n\nimport os\n\nfrom kivy.utils import platform as core_platform\nfrom kivy.logger import Logger\n\nimport kivy.input.providers.tuio\nimport kivy.input.providers.mouse\n\nplatform = core_platform\n\nif platform == 'win' or 'KIVY_DOC' in os.environ:\n    try:\n        import kivy.input.providers.wm_touch\n        import kivy.input.providers.wm_pen\n    except:\n        err = 'Input: WM_Touch/WM_Pen not supported by your version of Windows'\n        Logger.warning(err)\n\nif platform == 'macosx' or 'KIVY_DOC' in os.environ:\n    try:\n        import kivy.input.providers.mactouch\n    except:\n        err = 'Input: MacMultitouchSupport is not supported by your system'\n        Logger.exception(err)\n\nif platform == 'linux' or 'KIVY_DOC' in os.environ:\n    try:\n        import kivy.input.providers.probesysfs\n    except:\n        err = 'Input: ProbeSysfs is not supported by your version of linux'\n        Logger.exception(err)\n    try:\n        import kivy.input.providers.mtdev\n    except:\n        err = 'Input: MTDev is not supported by your version of linux'\n        Logger.exception(err)\n    try:\n        import kivy.input.providers.hidinput\n    except:\n        err = 'Input: HIDInput is not supported by your version of linux'\n        Logger.exception(err)\n    try:\n        import kivy.input.providers.linuxwacom\n    except:\n        err = 'Input: LinuxWacom is not supported by your version of linux'\n        Logger.exception(err)\n\nif platform == 'android' or 'KIVY_DOC' in os.environ:\n    try:\n        import kivy.input.providers.androidjoystick\n    except:\n        err = 'Input: AndroidJoystick is not supported by your version ' \\\n              'of linux'\n        Logger.exception(err)\n\ntry:\n    import kivy.input.providers.leapfinger  # NOQA\nexcept:\n    err = 'Input: LeapFinger is not available on your system'\n    Logger.exception(err)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/providers/androidjoystick.py",
    "content": "# pylint: disable=W0611\n'''\nAndroid Joystick Input Provider\n===============================\n\nThis module is based on the PyGame JoyStick Input Provider. For more\ninformation, please refer to\n`<http://www.pygame.org/docs/ref/joystick.html>`_\n\n\n'''\n__all__ = ('AndroidMotionEventProvider', )\n\nimport os\n\ntry:\n    import android  # NOQA\nexcept ImportError:\n    if 'KIVY_DOC' not in os.environ:\n        raise Exception('android lib not found.')\n\nfrom kivy.logger import Logger\nfrom kivy.input.provider import MotionEventProvider\nfrom kivy.input.factory import MotionEventFactory\nfrom kivy.input.shape import ShapeRect\nfrom kivy.input.motionevent import MotionEvent\nimport pygame.joystick\n\n\nclass AndroidMotionEvent(MotionEvent):\n\n    def depack(self, args):\n        self.is_touch = True\n        self.profile = ['pos', 'pressure', 'shape']\n        self.sx, self.sy, self.pressure, radius = args\n        self.shape = ShapeRect()\n        self.shape.width = radius\n        self.shape.height = radius\n        super(AndroidMotionEvent, self).depack(args)\n\n\nclass AndroidMotionEventProvider(MotionEventProvider):\n\n    def __init__(self, device, args):\n        super(AndroidMotionEventProvider, self).__init__(device, args)\n        self.joysticks = []\n        self.touches = {}\n        self.uid = 0\n        self.window = None\n\n    def create_joystick(self, index):\n        Logger.info('Android: create joystick <%d>' % index)\n        js = pygame.joystick.Joystick(index)\n        js.init()\n        if js.get_numbuttons() == 0:\n            Logger.info('Android: discard joystick <%d> cause no button' %\n                        index)\n            return\n        self.joysticks.append(js)\n\n    def start(self):\n        pygame.joystick.init()\n        Logger.info('Android: found %d joystick' % pygame.joystick.get_count())\n        for i in range(pygame.joystick.get_count()):\n            self.create_joystick(i)\n\n    def stop(self):\n        self.joysticks = []\n\n    def update(self, dispatch_fn):\n        if not self.window:\n            from kivy.core.window import Window\n            self.window = Window\n        w, h = self.window.system_size\n        touches = self.touches\n        for joy in self.joysticks:\n            jid = joy.get_id()\n            pressed = joy.get_button(0)\n            if pressed or jid in touches:\n                x = joy.get_axis(0) * 32768. / w\n                y = 1. - (joy.get_axis(1) * 32768. / h)\n\n                # python for android do * 1000.\n                pressure = joy.get_axis(2) / 1000.\n                radius = joy.get_axis(3) / 1000.\n\n                # new touche ?\n                if pressed and jid not in touches:\n                    self.uid += 1\n                    touch = AndroidMotionEvent(self.device, self.uid,\n                                            [x, y, pressure, radius])\n                    touches[jid] = touch\n                    dispatch_fn('begin', touch)\n                # update touch\n                elif pressed:\n                    touch = touches[jid]\n                    # avoid same touch position\n                    if (touch.sx == x and touch.sy == y\n                        and touch.pressure == pressure):\n                        continue\n                    touch.move([x, y, pressure, radius])\n                    dispatch_fn('update', touch)\n                # disapear\n                elif not pressed and jid in touches:\n                    touch = touches[jid]\n                    touch.move([x, y, pressure, radius])\n                    touch.update_time_end()\n                    dispatch_fn('end', touch)\n                    touches.pop(jid)\n\nMotionEventFactory.register('android', AndroidMotionEventProvider)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/providers/hidinput.py",
    "content": "# coding utf-8\n'''\nNative support for HID input from the linux kernel\n==================================================\n\nSupport starts from 2.6.32-ubuntu, or 2.6.34.\n\nTo configure HIDInput, add this to your configuration::\n\n    [input]\n    # devicename = hidinput,/dev/input/eventXX\n    # example with Stantum MTP4.3\" screen\n    stantum = hidinput,/dev/input/event2\n\n.. note::\n    You must have read access to the input event.\n\nYou can use a custom range for the X, Y and pressure values.\nFor some drivers, the range reported is invalid.\nTo fix that, you can add these options to the argument line:\n\n* invert_x : 1 to invert X axis\n* invert_y : 1 to invert Y axis\n* min_position_x : X minimum\n* max_position_x : X maximum\n* min_position_y : Y minimum\n* max_position_y : Y maximum\n* min_pressure : pressure minimum\n* max_pressure : pressure maximum\n* rotation : rotate the input coordinate (0, 90, 180, 270)\n\nFor example, on the Asus T101M, the touchscreen reports a range from 0-4095 for\nthe X and Y values, but the real values are in a range from 0-32768. To correct\nthis, you can add the following to the configuration::\n\n    [input]\n    t101m = hidinput,/dev/input/event7,max_position_x=32768,\\\nmax_position_y=32768\n\n.. versionadded:: 1.9.1\n\n    `rotation` configuration token added.\n\n'''\n\n__all__ = ('HIDInputMotionEventProvider', 'HIDMotionEvent')\n\nimport os\nfrom kivy.input.motionevent import MotionEvent\nfrom kivy.input.shape import ShapeRect\n# late imports\nWindow = None\nKeyboard = None\n\n\nclass HIDMotionEvent(MotionEvent):\n\n    def depack(self, args):\n        self.is_touch = True\n        self.sx = args['x']\n        self.sy = args['y']\n        self.profile = ['pos']\n        if 'size_w' in args and 'size_h' in args:\n            self.shape = ShapeRect()\n            self.shape.width = args['size_w']\n            self.shape.height = args['size_h']\n            self.profile.append('shape')\n        if 'pressure' in args:\n            self.pressure = args['pressure']\n            self.profile.append('pressure')\n        super(HIDMotionEvent, self).depack(args)\n\n    def __str__(self):\n        return '<HIDMotionEvent id=%d pos=(%f, %f) device=%s>' \\\n            % (self.id, self.sx, self.sy, self.device)\n\nif 'KIVY_DOC' in os.environ:\n    # documentation hack\n    HIDInputMotionEventProvider = None\n\nelse:\n    import threading\n    import collections\n    import struct\n    import fcntl\n    from kivy.input.provider import MotionEventProvider\n    from kivy.input.factory import MotionEventFactory\n    from kivy.logger import Logger\n\n    #\n    # This part is taken from linux-source-2.6.32/include/linux/input.h\n    #\n\n    # Event types\n    EV_SYN = 0x00\n    EV_KEY = 0x01\n    EV_REL = 0x02\n    EV_ABS = 0x03\n    EV_MSC = 0x04\n    EV_SW = 0x05\n    EV_LED = 0x11\n    EV_SND = 0x12\n    EV_REP = 0x14\n    EV_FF = 0x15\n    EV_PWR = 0x16\n    EV_FF_STATUS = 0x17\n    EV_MAX = 0x1f\n    EV_CNT = (EV_MAX + 1)\n\n    KEY_MAX = 0x2ff\n\n    # Synchronization events\n    SYN_REPORT = 0\n    SYN_CONFIG = 1\n    SYN_MT_REPORT = 2\n\n    # Misc events\n    MSC_SERIAL = 0x00\n    MSC_PULSELED = 0x01\n    MSC_GESTURE = 0x02\n    MSC_RAW = 0x03\n    MSC_SCAN = 0x04\n    MSC_MAX = 0x07\n    MSC_CNT = (MSC_MAX + 1)\n\n    ABS_X = 0x00\n    ABS_Y = 0x01\n    ABS_PRESSURE = 0x18\n    ABS_MT_TOUCH_MAJOR = 0x30  # Major axis of touching ellipse\n    ABS_MT_TOUCH_MINOR = 0x31  # Minor axis (omit if circular)\n    ABS_MT_WIDTH_MAJOR = 0x32  # Major axis of approaching ellipse\n    ABS_MT_WIDTH_MINOR = 0x33  # Minor axis (omit if circular)\n    ABS_MT_ORIENTATION = 0x34  # Ellipse orientation\n    ABS_MT_POSITION_X = 0x35   # Center X ellipse position\n    ABS_MT_POSITION_Y = 0x36   # Center Y ellipse position\n    ABS_MT_TOOL_TYPE = 0x37    # Type of touching device\n    ABS_MT_BLOB_ID = 0x38      # Group a set of packets as a blob\n    ABS_MT_TRACKING_ID = 0x39  # Unique ID of initiated contact\n    ABS_MT_PRESSURE = 0x3a     # Pressure on contact area\n\n    # some ioctl base (with 0 value)\n    EVIOCGNAME = 2147501318\n    EVIOCGBIT = 2147501344\n    EVIOCGABS = 2149074240\n\n    keyboard_keys = {\n        0x29: ('`', '~'),\n        0x02: ('1', '!'),\n        0x03: ('2', '@'),\n        0x04: ('3', '#'),\n        0x05: ('4', '$'),\n        0x06: ('5', '%'),\n        0x07: ('6', '^'),\n        0x08: ('7', '&'),\n        0x09: ('8', '*'),\n        0x0a: ('9', '('),\n        0x0b: ('0', ')'),\n        0x0c: ('-', '_'),\n        0x0d: ('=', '+'),\n        0x0e: ('backspace', ),\n        0x0f: ('tab', ),\n        0x10: ('q', 'Q'),\n        0x11: ('w', 'W'),\n        0x12: ('e', 'E'),\n        0x13: ('r', 'R'),\n        0x14: ('t', 'T'),\n        0x15: ('y', 'Y'),\n        0x16: ('u', 'U'),\n        0x17: ('i', 'I'),\n        0x18: ('o', 'O'),\n        0x19: ('p', 'P'),\n        0x1a: ('[', '{'),\n        0x1b: (']', '}'),\n        0x2b: ('\\\\', '|'),\n        0x3a: ('capslock', ),\n        0x1e: ('a', 'A'),\n        0x1f: ('s', 'S'),\n        0x20: ('d', 'D'),\n        0x21: ('f', 'F'),\n        0x22: ('g', 'G'),\n        0x23: ('h', 'H'),\n        0x24: ('j', 'J'),\n        0x25: ('k', 'K'),\n        0x26: ('l', 'L'),\n        0x27: (';', ':'),\n        0x28: (\"'\", '\"'),\n        0xff: ('non-US-1', ),\n        0x1c: ('enter', ),\n        0x2a: ('shift', ),\n        0x2c: ('z', 'Z'),\n        0x2d: ('x', 'X'),\n        0x2e: ('c', 'C'),\n        0x2f: ('v', 'V'),\n        0x30: ('b', 'B'),\n        0x31: ('n', 'N'),\n        0x32: ('m', 'M'),\n        0x33: (',', '<'),\n        0x34: ('.', '>'),\n        0x35: ('/', '?'),\n        0x36: ('shift', ),\n        0x56: ('pipe', ),\n        0x1d: ('ctrl', ),\n        0x7D: ('super', ),\n        0x38: ('alt', ),\n        0x39: ('spacebar', ),\n        0x64: ('alt-gr', ),\n        0x7e: ('super', ),\n        0x7f: ('compose', ),\n        0x61: ('ctrl', ),\n        0x45: ('numlock', ),\n        0x47: ('numpad7', 'home'),\n        0x4b: ('numpad4', 'left'),\n        0x4f: ('numpad1', 'end'),\n        0x48: ('numpad8', 'up'),\n        0x4c: ('numpad5', ),\n        0x50: ('numpad2', 'down'),\n        0x52: ('numpad0', 'insert'),\n        0x37: ('numpadmul', ),\n        0x62: ('numpaddivide', ),\n        0x49: ('numpad9', 'pageup'),\n        0x4d: ('numpad6', 'right'),\n        0x51: ('numpad3', 'pagedown'),\n        0x53: ('numpaddecimal', 'delete'),\n        0x4a: ('numpadsubstract', ),\n        0x4e: ('numpadadd', ),\n        0x60: ('numpadenter', ),\n        0x01: ('escape', ),\n        0x3b: ('f1', ),\n        0x3c: ('f2', ),\n        0x3d: ('f3', ),\n        0x3e: ('f4', ),\n        0x3f: ('f5', ),\n        0x40: ('f6', ),\n        0x41: ('f7', ),\n        0x42: ('f8', ),\n        0x43: ('f9', ),\n        0x44: ('f10', ),\n        0x57: ('f11', ),\n        0x58: ('f12', ),\n        0x54: ('Alt+SysRq', ),\n        0x46: ('Screenlock', ),\n        0x67: ('up', ),\n        0x6c: ('down', ),\n        0x69: ('left', ),\n        0x6a: ('right', ),\n        0x6e: ('insert', ),\n        0x6f: ('delete', ),\n        0x66: ('home', ),\n        0x6b: ('end', ),\n        0x68: ('pageup', ),\n        0x6d: ('pagedown', ),\n        0x63: ('print', ),\n        0x77: ('pause', ),\n\n\n        # TODO combinations\n        # e0-37    PrtScr\n        # e0-46    Ctrl+Break\n        # e0-5b    LWin (USB: LGUI)\n        # e0-5c    RWin (USB: RGUI)\n        # e0-5d    Menu\n        # e0-5f    Sleep\n        # e0-5e    Power\n        # e0-63    Wake\n        # e0-38    RAlt\n        # e0-1d    RCtrl\n        # e0-52    Insert\n        # e0-53    Delete\n        # e0-47    Home\n        # e0-4f    End\n        # e0-49    PgUp\n        # e0-51    PgDn\n        # e0-4b    Left\n        # e0-48    Up\n        # e0-50    Down\n        # e0-4d    Right\n        # e0-35    KP-/\n        # e0-1c    KP-Enter\n        # e1-1d-45 77      Pause\n    }\n\n    keys_str = {\n        'spacebar': ' ',\n        'tab': '\t',\n        'shift': '',\n        'alt': '',\n        'ctrl': '',\n        'escape': '',\n        'numpad1': '1',\n        'numpad2': '2',\n        'numpad3': '3',\n        'numpad4': '4',\n        'numpad5': '5',\n        'numpad6': '6',\n        'numpad7': '7',\n        'numpad8': '8',\n        'numpad9': '9',\n        'numpad0': '0',\n        'numpadmul': '*',\n        'numpaddivide': '/',\n        'numpadadd': '+',\n        'numpadsubstract': '-',\n    }\n\n    # sizeof(struct input_event)\n    struct_input_event_sz = struct.calcsize('LLHHi')\n    struct_input_absinfo_sz = struct.calcsize('iiiiii')\n    sz_l = struct.calcsize('Q')\n\n    class HIDInputMotionEventProvider(MotionEventProvider):\n\n        options = ('min_position_x', 'max_position_x',\n                   'min_position_y', 'max_position_y',\n                   'min_pressure', 'max_pressure',\n                   'invert_x', 'invert_y', 'rotation')\n\n        def __init__(self, device, args):\n            super(HIDInputMotionEventProvider, self).__init__(device, args)\n            global Window, Keyboard\n\n            if Window is None:\n                from kivy.core.window import Window\n            if Keyboard is None:\n                from kivy.core.window import Keyboard\n\n            self.input_fn = None\n            self.default_ranges = dict()\n\n            # split arguments\n            args = args.split(',')\n            if not args:\n                Logger.error('HIDInput: Filename missing in configuration')\n                Logger.error('HIDInput: Use /dev/input/event0 for example')\n                return None\n\n            # read filename\n            self.input_fn = args[0]\n            Logger.info('HIDInput: Read event from <%s>' % self.input_fn)\n\n            # read parameters\n            for arg in args[1:]:\n                if arg == '':\n                    continue\n                arg = arg.split('=')\n\n                # ensure it's a key = value\n                if len(arg) != 2:\n                    Logger.error('HIDInput: invalid parameter '\n                                 '%s, not in key=value format.' % arg)\n                    continue\n\n                # ensure the key exist\n                key, value = arg\n                if key not in HIDInputMotionEventProvider.options:\n                    Logger.error('HIDInput: unknown %s option' % key)\n                    continue\n\n                # ensure the value\n                try:\n                    self.default_ranges[key] = int(value)\n                except ValueError:\n                    err = 'HIDInput: invalid value \"%s\" for \"%s\"' % (\n                        key, value)\n                    Logger.error(err)\n                    continue\n\n                # all good!\n                Logger.info('HIDInput: Set custom %s to %d' % (\n                    key, int(value)))\n\n            if 'rotation' not in self.default_ranges:\n                self.default_ranges['rotation'] = 0\n            elif self.default_ranges['rotation'] not in (0, 90, 180, 270):\n                Logger.error('HIDInput: invalid rotation value ({})'.format(\n                    self.default_ranges['rotation']))\n                self.default_ranges['rotation'] = 0\n\n        def start(self):\n            if self.input_fn is None:\n                return\n            self.uid = 0\n            self.queue = collections.deque()\n            self.thread = threading.Thread(\n                target=self._thread_run,\n                kwargs=dict(\n                    queue=self.queue,\n                    input_fn=self.input_fn,\n                    device=self.device,\n                    default_ranges=self.default_ranges))\n            self.thread.daemon = True\n            self.thread.start()\n\n        def _thread_run(self, **kwargs):\n            input_fn = kwargs.get('input_fn')\n            queue = kwargs.get('queue')\n            device = kwargs.get('device')\n            drs = kwargs.get('default_ranges').get\n            touches = {}\n            touches_sent = []\n            point = {}\n            l_points = []\n\n            # prepare some vars to get limit of some component\n            range_min_position_x = 0\n            range_max_position_x = 2048\n            range_min_position_y = 0\n            range_max_position_y = 2048\n            range_min_pressure = 0\n            range_max_pressure = 255\n            range_min_abs_x = 0\n            range_max_abs_x = 255\n            range_min_abs_y = 0\n            range_max_abs_y = 255\n            range_min_abs_pressure = 0\n            range_max_abs_pressure = 255\n            invert_x = int(bool(drs('invert_x', 0)))\n            invert_y = int(bool(drs('invert_y', 1)))\n            rotation = drs('rotation', 0)\n\n            def assign_coord(point, value, invert, coords):\n                cx, cy = coords\n                if invert:\n                    value = 1. - value\n                if rotation == 0:\n                    point[cx] = value\n                elif rotation == 90:\n                    point[cy] = value\n                elif rotation == 180:\n                    point[cx] = 1. - value\n                elif rotation == 270:\n                    point[cy] = 1. - value\n\n            def assign_rel_coord(point, value, invert, coords):\n                cx, cy = coords\n                if invert:\n                    value = -1 * value\n                if rotation == 0:\n                    point[cx] += value\n                elif rotation == 90:\n                    point[cy] += value\n                elif rotation == 180:\n                    point[cx] += -value\n                elif rotation == 270:\n                    point[cy] += -value\n\n            def process_as_multitouch(tv_sec, tv_usec, ev_type,\n                                      ev_code, ev_value):\n                # sync event\n                if ev_type == EV_SYN:\n                    if ev_code == SYN_MT_REPORT:\n                        if 'id' not in point:\n                            return\n                        l_points.append(point.copy())\n                    elif ev_code == SYN_REPORT:\n                        process(l_points)\n                        del l_points[:]\n\n                elif ev_type == EV_MSC and ev_code in (MSC_RAW, MSC_SCAN):\n                    pass\n\n                else:\n                    # compute multitouch track\n                    if ev_code == ABS_MT_TRACKING_ID:\n                        point.clear()\n                        point['id'] = ev_value\n                    elif ev_code == ABS_MT_POSITION_X:\n                        val = normalize(ev_value,\n                                        range_min_position_x,\n                                        range_max_position_x)\n                        assign_coord(point, val, invert_x, 'xy')\n                    elif ev_code == ABS_MT_POSITION_Y:\n                        val = 1. - normalize(ev_value,\n                                             range_min_position_y,\n                                             range_max_position_y)\n                        assign_coord(point, val, invert_y, 'yx')\n                    elif ev_code == ABS_MT_ORIENTATION:\n                        point['orientation'] = ev_value\n                    elif ev_code == ABS_MT_BLOB_ID:\n                        point['blobid'] = ev_value\n                    elif ev_code == ABS_MT_PRESSURE:\n                        point['pressure'] = normalize(ev_value,\n                                                      range_min_pressure,\n                                                      range_max_pressure)\n                    elif ev_code == ABS_MT_TOUCH_MAJOR:\n                        point['size_w'] = ev_value\n                    elif ev_code == ABS_MT_TOUCH_MINOR:\n                        point['size_h'] = ev_value\n\n            def process_as_mouse_or_keyboard(\n                tv_sec, tv_usec, ev_type, ev_code, ev_value):\n\n                if ev_type == EV_SYN:\n                    if ev_code == SYN_REPORT:\n                        process([point])\n                elif ev_type == EV_REL:\n                    if ev_code == 0:\n                        assign_rel_coord(point,\n                            min(1., max(-1., ev_value / 1000.)),\n                            invert_x, 'xy')\n                    elif ev_code == 1:\n                        assign_rel_coord(point,\n                            min(1., max(-1., ev_value / 1000.)),\n                            invert_y, 'yx')\n                elif ev_code == ABS_X:\n                    val = normalize(ev_value,\n                                    range_min_abs_x,\n                                    range_max_abs_x)\n                    assign_coord(point, val, invert_x, 'xy')\n                elif ev_code == ABS_Y:\n                    val = 1. - normalize(ev_value,\n                                         range_min_abs_y,\n                                         range_max_abs_y)\n                    assign_coord(point, val, invert_y, 'yx')\n                elif ev_code == ABS_PRESSURE:\n                    point['pressure'] = normalize(ev_value,\n                                                  range_min_abs_pressure,\n                                                  range_max_abs_pressure)\n                elif ev_type == EV_KEY:\n                    buttons = {\n                        272: 'left',\n                        273: 'right',\n                        274: 'middle',\n                        275: 'side',\n                        276: 'extra',\n                        277: 'forward',\n                        278: 'back',\n                        279: 'task',\n                        330: 'touch',\n                        320: 'pen'}\n\n                    if ev_code in buttons.keys():\n                        if ev_value:\n                            if 'button' not in point:\n                                point['button'] = buttons[ev_code]\n                                point['id'] += 1\n                                if '_avoid' in point:\n                                    del point['_avoid']\n                        elif 'button' in point:\n                            if point['button'] == buttons[ev_code]:\n                                del point['button']\n                                point['id'] += 1\n                                point['_avoid'] = True\n                    else:\n                        if ev_value == 1:\n                            l = keyboard_keys[ev_code][-1\n                                if 'shift' in Window._modifiers else 0]\n                            if l == 'shift' or l == 'alt':\n                                Window._modifiers.append(l)\n                            Window.dispatch(\n                                'on_key_down',\n                                Keyboard.keycodes[l.lower()],\n                                ev_code, keys_str.get(l, l),\n                                Window._modifiers)\n                        if ev_value == 0:\n                            l = keyboard_keys[ev_code][-1\n                                if 'shift' in Window._modifiers else 0]\n                            Window.dispatch(\n                                'on_key_up',\n                                Keyboard.keycodes[l.lower()],\n                                ev_code,\n                                keys_str.get(l, l),\n                                Window._modifiers)\n                            if l == 'shift':\n                                Window._modifiers.remove('shift')\n                        # if ev_value == 2:\n                        #     Window.dispatch('on_key_down', ev_code)\n\n            def process(points):\n                if not is_multitouch:\n                    Window.mouse_pos = (\n                        points[0]['x'] * Window.width,\n                        points[0]['y'] * Window.height)\n\n                actives = [args['id']\n                           for args in points\n                           if 'id' in args and not '_avoid' in args]\n                for args in points:\n                    tid = args['id']\n                    try:\n                        touch = touches[tid]\n                        if touch.sx == args['x'] and touch.sy == args['y']:\n                            continue\n                        touch.move(args)\n                        if tid not in touches_sent:\n                            queue.append(('begin', touch))\n                            touches_sent.append(tid)\n                        queue.append(('update', touch))\n                    except KeyError:\n                        if '_avoid' not in args:\n                            touch = HIDMotionEvent(device, tid, args)\n                            touches[touch.id] = touch\n                            if tid not in touches_sent:\n                                queue.append(('begin', touch))\n                                touches_sent.append(tid)\n\n                for tid in list(touches.keys())[:]:\n                    if tid not in actives:\n                        touch = touches[tid]\n                        if tid in touches_sent:\n                            touch.update_time_end()\n                            queue.append(('end', touch))\n                            touches_sent.remove(tid)\n                        del touches[tid]\n\n            def normalize(value, vmin, vmax):\n                return (value - vmin) / float(vmax - vmin)\n\n            # open the input\n            fd = open(input_fn, 'rb')\n\n            # get the controler name (EVIOCGNAME)\n            device_name = str(fcntl.ioctl(fd, EVIOCGNAME + (256 << 16),\n                                      \" \" * 256)).split('\\x00')[0]\n            Logger.info('HIDMotionEvent: using <%s>' % device_name)\n\n            # get abs infos\n            bit = fcntl.ioctl(fd, EVIOCGBIT + (EV_MAX << 16), ' ' * sz_l)\n            bit, = struct.unpack('Q', bit)\n            is_multitouch = False\n            for x in range(EV_MAX):\n                # preserve this, we may want other things than EV_ABS\n                if x != EV_ABS:\n                    continue\n                # EV_ABS available for this device ?\n                if (bit & (1 << x)) == 0:\n                    continue\n                # ask abs info keys to the devices\n                sbit = fcntl.ioctl(fd, EVIOCGBIT + x + (KEY_MAX << 16),\n                                   ' ' * sz_l)\n                sbit, = struct.unpack('Q', sbit)\n                for y in range(KEY_MAX):\n                    if (sbit & (1 << y)) == 0:\n                        continue\n                    absinfo = fcntl.ioctl(fd, EVIOCGABS + y +\n                                          (struct_input_absinfo_sz << 16),\n                                          ' ' * struct_input_absinfo_sz)\n                    abs_value, abs_min, abs_max, abs_fuzz, \\\n                        abs_flat, abs_res = struct.unpack('iiiiii', absinfo)\n                    if y == ABS_MT_POSITION_X:\n                        is_multitouch = True\n                        range_min_position_x = drs('min_position_x', abs_min)\n                        range_max_position_x = drs('max_position_x', abs_max)\n                        Logger.info('HIDMotionEvent: ' +\n                                    '<%s> range position X is %d - %d' % (\n                                        device_name, abs_min, abs_max))\n                    elif y == ABS_MT_POSITION_Y:\n                        is_multitouch = True\n                        range_min_position_y = drs('min_position_y', abs_min)\n                        range_max_position_y = drs('max_position_y', abs_max)\n                        Logger.info('HIDMotionEvent: ' +\n                                    '<%s> range position Y is %d - %d' % (\n                                        device_name, abs_min, abs_max))\n                    elif y == ABS_MT_PRESSURE:\n                        range_min_pressure = drs('min_pressure', abs_min)\n                        range_max_pressure = drs('max_pressure', abs_max)\n                        Logger.info('HIDMotionEvent: ' +\n                                    '<%s> range pressure is %d - %d' % (\n                                        device_name, abs_min, abs_max))\n                    elif y == ABS_X:\n                        range_min_abs_x = drs('min_abs_x', abs_min)\n                        range_max_abs_x = drs('max_abs_x', abs_max)\n                        Logger.info('HIDMotionEvent: ' +\n                                    '<%s> range ABS X position is %d - %d' % (\n                                        device_name, abs_min, abs_max))\n                    elif y == ABS_Y:\n                        range_min_abs_y = drs('min_abs_y', abs_min)\n                        range_max_abs_y = drs('max_abs_y', abs_max)\n                        Logger.info('HIDMotionEvent: ' +\n                                    '<%s> range ABS Y position is %d - %d' % (\n                                        device_name, abs_min, abs_max))\n                    elif y == ABS_PRESSURE:\n                        range_min_abs_pressure = drs(\n                            'min_abs_pressure', abs_min)\n                        range_max_abs_pressure = drs(\n                            'max_abs_pressure', abs_max)\n                        Logger.info('HIDMotionEvent: ' +\n                                    '<%s> range ABS pressure is %d - %d' % (\n                                        device_name, abs_min, abs_max))\n\n            # init the point\n            if not is_multitouch:\n                point = {'x': .5, 'y': .5, 'id': 0, '_avoid': True}\n\n            # read until the end\n            while fd:\n\n                data = fd.read(struct_input_event_sz)\n                if len(data) < struct_input_event_sz:\n                    break\n\n                # extract each event\n                for i in range(int(len(data) / struct_input_event_sz)):\n                    ev = data[i * struct_input_event_sz:]\n\n                    # extract timeval + event infos\n                    infos = struct.unpack('LLHHi', ev[:struct_input_event_sz])\n\n                    if is_multitouch:\n                        process_as_multitouch(*infos)\n                    else:\n                        process_as_mouse_or_keyboard(*infos)\n\n        def update(self, dispatch_fn):\n            # dispatch all event from threads\n            try:\n                while True:\n                    event_type, touch = self.queue.popleft()\n                    dispatch_fn(event_type, touch)\n            except:\n                pass\n\n    MotionEventFactory.register('hidinput', HIDInputMotionEventProvider)\n\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/providers/leapfinger.py",
    "content": "'''\nLeap Motion - finger only\n=========================\n'''\n\n__all__ = ('LeapFingerEventProvider', 'LeapFingerEvent')\n\nimport os\nfrom collections import deque\nfrom kivy.logger import Logger\nfrom kivy.input.provider import MotionEventProvider\nfrom kivy.input.factory import MotionEventFactory\nfrom kivy.input.motionevent import MotionEvent\n\n_LEAP_QUEUE = deque()\n\nLeap = InteractionBox = None\n\n\ndef normalize(value, a, b):\n    return (value - a) / float(b - a)\n\n\nclass LeapFingerEvent(MotionEvent):\n\n    def depack(self, args):\n        super(LeapFingerEvent, self).depack(args)\n        if args[0] is None:\n            return\n        self.profile = ('pos', 'pos3d', )\n        x, y, z = args\n        self.sx = normalize(x, -150, 150)\n        self.sy = normalize(y, 40, 460)\n        self.sz = normalize(z, -350, 350)\n        self.z = z\n        self.is_touch = True\n\n\nclass LeapFingerEventProvider(MotionEventProvider):\n\n    __handlers__ = {}\n\n    def start(self):\n        # don't do the import at start, or teh error will be always displayed\n        # for user who don't have Leap\n        global Leap, InteractionBox\n        import Leap\n        from Leap import InteractionBox\n\n        class LeapMotionListener(Leap.Listener):\n\n            def on_init(self, controller):\n                Logger.info('leapmotion: Initialized')\n\n            def on_connect(self, controller):\n                Logger.info('leapmotion: Connected')\n\n            def on_disconnect(self, controller):\n                Logger.info('leapmotion: Disconnected')\n\n            def on_frame(self, controller):\n                frame = controller.frame()\n                _LEAP_QUEUE.append(frame)\n\n            def on_exit(self, controller):\n                pass\n\n        self.uid = 0\n        self.touches = {}\n        self.listener = LeapMotionListener()\n        self.controller = Leap.Controller(self.listener)\n\n    def update(self, dispatch_fn):\n        try:\n            while True:\n                frame = _LEAP_QUEUE.popleft()\n                events = self.process_frame(frame)\n                for ev in events:\n                    dispatch_fn(*ev)\n        except IndexError:\n            pass\n\n    def process_frame(self, frame):\n        events = []\n        touches = self.touches\n        available_uid = []\n        for hand in frame.hands:\n            for finger in hand.fingers:\n                #print hand.id(), finger.id(), finger.tip()\n                uid = '{0}:{1}'.format(hand.id, finger.id)\n                available_uid.append(uid)\n                position = finger.tip_position\n                args = (position.x, position.y, position.z)\n                if uid not in touches:\n                    touch = LeapFingerEvent(self.device, uid, args)\n                    events.append(('begin', touch))\n                    touches[uid] = touch\n                else:\n                    touch = touches[uid]\n                    touch.move(args)\n                    events.append(('update', touch))\n        for key in touches.keys()[:]:\n            if key not in available_uid:\n                events.append(('end', touches[key]))\n                del touches[key]\n        return events\n\n\n# registers\nMotionEventFactory.register('leapfinger', LeapFingerEventProvider)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/providers/linuxwacom.py",
    "content": "'''\nNative support of Wacom tablet from linuxwacom driver\n=====================================================\n\nTo configure LinuxWacom, add this to your configuration::\n\n    [input]\n    pen = linuxwacom,/dev/input/event2,mode=pen\n    finger = linuxwacom,/dev/input/event3,mode=touch\n\n.. note::\n    You must have read access to the input event.\n\nYou can use a custom range for the X, Y and pressure values.\nOn some drivers, the range reported is invalid.\nTo fix that, you can add these options to the argument line:\n\n* invert_x : 1 to invert X axis\n* invert_y : 1 to invert Y axis\n* min_position_x : X minimum\n* max_position_x : X maximum\n* min_position_y : Y minimum\n* max_position_y : Y maximum\n* min_pressure : pressure minimum\n* max_pressure : pressure maximum\n'''\n\n__all__ = ('LinuxWacomMotionEventProvider', 'LinuxWacomMotionEvent')\n\nimport os\nfrom kivy.input.motionevent import MotionEvent\nfrom kivy.input.shape import ShapeRect\n\n\nclass LinuxWacomMotionEvent(MotionEvent):\n\n    def depack(self, args):\n        self.is_touch = True\n        self.sx = args['x']\n        self.sy = args['y']\n        self.profile = ['pos']\n        if 'size_w' in args and 'size_h' in args:\n            self.shape = ShapeRect()\n            self.shape.width = args['size_w']\n            self.shape.height = args['size_h']\n            self.profile.append('shape')\n        if 'pressure' in args:\n            self.pressure = args['pressure']\n            self.profile.append('pressure')\n        super(LinuxWacomMotionEvent, self).depack(args)\n\n    def __str__(self):\n        return '<LinuxWacomMotionEvent id=%d pos=(%f, %f) device=%s>' \\\n            % (self.id, self.sx, self.sy, self.device)\n\nif 'KIVY_DOC' in os.environ:\n    # documentation hack\n    LinuxWacomMotionEventProvider = None\n\nelse:\n    import threading\n    import collections\n    import struct\n    import fcntl\n    from kivy.input.provider import MotionEventProvider\n    from kivy.input.factory import MotionEventFactory\n    from kivy.logger import Logger\n\n    #\n    # This part is taken from linux-source-2.6.32/include/linux/input.h\n    #\n\n    # Event types\n    EV_SYN = 0x00\n    EV_KEY = 0x01\n    EV_REL = 0x02\n    EV_ABS = 0x03\n    EV_MSC = 0x04\n    EV_SW = 0x05\n    EV_LED = 0x11\n    EV_SND = 0x12\n    EV_REP = 0x14\n    EV_FF = 0x15\n    EV_PWR = 0x16\n    EV_FF_STATUS = 0x17\n    EV_MAX = 0x1f\n    EV_CNT = (EV_MAX + 1)\n\n    KEY_MAX = 0x2ff\n\n    # Synchronization events\n    SYN_REPORT = 0\n    SYN_CONFIG = 1\n    SYN_MT_REPORT = 2\n\n    # Misc events\n    MSC_SERIAL = 0x00\n    MSC_PULSELED = 0x01\n    MSC_GESTURE = 0x02\n    MSC_RAW = 0x03\n    MSC_SCAN = 0x04\n    MSC_MAX = 0x07\n    MSC_CNT = (MSC_MAX + 1)\n\n    ABS_X = 0x00\n    ABS_Y = 0x01\n    ABS_PRESSURE = 0x18\n    ABS_MISC = 0x28  # if 0, it's touch up\n    ABS_MT_TOUCH_MAJOR = 0x30  # Major axis of touching ellipse\n    ABS_MT_TOUCH_MINOR = 0x31  # Minor axis (omit if circular)\n    ABS_MT_WIDTH_MAJOR = 0x32  # Major axis of approaching ellipse\n    ABS_MT_WIDTH_MINOR = 0x33  # Minor axis (omit if circular)\n    ABS_MT_ORIENTATION = 0x34  # Ellipse orientation\n    ABS_MT_POSITION_X = 0x35   # Center X ellipse position\n    ABS_MT_POSITION_Y = 0x36   # Center Y ellipse position\n    ABS_MT_TOOL_TYPE = 0x37    # Type of touching device\n    ABS_MT_BLOB_ID = 0x38      # Group a set of packets as a blob\n    ABS_MT_TRACKING_ID = 0x39  # Unique ID of initiated contact\n    ABS_MT_PRESSURE = 0x3a     # Pressure on contact area\n\n    # some ioctl base (with 0 value)\n    EVIOCGNAME = 2147501318\n    EVIOCGBIT = 2147501344\n    EVIOCGABS = 2149074240\n\n    # sizeof(struct input_event)\n    struct_input_event_sz = struct.calcsize('LLHHi')\n    struct_input_absinfo_sz = struct.calcsize('iiiiii')\n    sz_l = struct.calcsize('Q')\n\n    class LinuxWacomMotionEventProvider(MotionEventProvider):\n\n        options = ('min_position_x', 'max_position_x',\n                   'min_position_y', 'max_position_y',\n                   'min_pressure', 'max_pressure',\n                   'invert_x', 'invert_y')\n\n        def __init__(self, device, args):\n            super(LinuxWacomMotionEventProvider, self).__init__(device, args)\n            self.input_fn = None\n            self.default_ranges = dict()\n            self.mode = 'touch'\n\n            # split arguments\n            args = args.split(',')\n            if not args:\n                Logger.error('LinuxWacom: No filename given in config')\n                Logger.error('LinuxWacom: Use /dev/input/event0 for example')\n                return None\n\n            # read filename\n            self.input_fn = args[0]\n            Logger.info('LinuxWacom: Read event from <%s>' % self.input_fn)\n\n            # read parameters\n            for arg in args[1:]:\n                if arg == '':\n                    continue\n                arg = arg.split('=')\n\n                # ensure it's a key = value\n                if len(arg) != 2:\n                    err = 'LinuxWacom: Bad parameter' \\\n                        '%s: Not in key=value format.' % arg\n                    Logger.error(err)\n                    continue\n\n                # ensure the key exist\n                key, value = arg\n                if key == 'mode':\n                    self.mode = value\n                    continue\n\n                if key not in LinuxWacomMotionEventProvider.options:\n                    Logger.error('LinuxWacom: unknown %s option' % key)\n                    continue\n\n                # ensure the value\n                try:\n                    self.default_ranges[key] = int(value)\n                except ValueError:\n                    err = 'LinuxWacom: value %s invalid for %s' % (key, value)\n                    Logger.error(err)\n                    continue\n\n                # all good!\n                msg = 'LinuxWacom: Set custom %s to %d' % (key, int(value))\n                Logger.info(msg)\n            Logger.info('LinuxWacom: mode is <%s>' % self.mode)\n\n        def start(self):\n            if self.input_fn is None:\n                return\n            self.uid = 0\n            self.queue = collections.deque()\n            self.thread = threading.Thread(\n                target=self._thread_run,\n                kwargs=dict(\n                    queue=self.queue,\n                    input_fn=self.input_fn,\n                    device=self.device,\n                    default_ranges=self.default_ranges))\n            self.thread.daemon = True\n            self.thread.start()\n\n        def _thread_run(self, **kwargs):\n            input_fn = kwargs.get('input_fn')\n            queue = kwargs.get('queue')\n            device = kwargs.get('device')\n            drs = kwargs.get('default_ranges').get\n            touches = {}\n            touches_sent = []\n            l_points = {}\n\n            # prepare some vars to get limit of some component\n            range_min_position_x = 0\n            range_max_position_x = 2048\n            range_min_position_y = 0\n            range_max_position_y = 2048\n            range_min_pressure = 0\n            range_max_pressure = 255\n            invert_x = int(bool(drs('invert_x', 0)))\n            invert_y = int(bool(drs('invert_y', 0)))\n            reset_touch = False\n\n            def process(points):\n                actives = list(points.keys())\n                for args in points.values():\n                    tid = args['id']\n                    try:\n                        touch = touches[tid]\n                    except KeyError:\n                        touch = LinuxWacomMotionEvent(device, tid, args)\n                        touches[touch.id] = touch\n                    if touch.sx == args['x'] \\\n                            and touch.sy == args['y'] \\\n                            and tid in touches_sent:\n                        continue\n                    touch.move(args)\n                    if tid not in touches_sent:\n                        queue.append(('begin', touch))\n                        touches_sent.append(tid)\n                    queue.append(('update', touch))\n\n                for tid in list(touches.keys())[:]:\n                    if tid not in actives:\n                        touch = touches[tid]\n                        if tid in touches_sent:\n                            touch.update_time_end()\n                            queue.append(('end', touch))\n                            touches_sent.remove(tid)\n                        del touches[tid]\n\n            def normalize(value, vmin, vmax):\n                return (value - vmin) / float(vmax - vmin)\n\n            # open the input\n            try:\n                fd = open(input_fn, 'rb')\n            except IOError:\n                Logger.exception('Unable to open %s' % input_fn)\n                return\n\n            # get the controler name (EVIOCGNAME)\n            device_name = fcntl.ioctl(fd, EVIOCGNAME + (256 << 16),\n                                      \" \" * 256).split('\\x00')[0]\n            Logger.info('LinuxWacom: using <%s>' % device_name)\n\n            # get abs infos\n            bit = fcntl.ioctl(fd, EVIOCGBIT + (EV_MAX << 16), ' ' * sz_l)\n            bit, = struct.unpack('Q', bit)\n            for x in range(EV_MAX):\n                # preserve this, we may want other things than EV_ABS\n                if x != EV_ABS:\n                    continue\n                # EV_ABS available for this device ?\n                if (bit & (1 << x)) == 0:\n                    continue\n                # ask abs info keys to the devices\n                sbit = fcntl.ioctl(fd, EVIOCGBIT + x + (KEY_MAX << 16),\n                                   ' ' * sz_l)\n                sbit, = struct.unpack('Q', sbit)\n                for y in range(KEY_MAX):\n                    if (sbit & (1 << y)) == 0:\n                        continue\n                    absinfo = fcntl.ioctl(fd, EVIOCGABS + y +\n                                          (struct_input_absinfo_sz << 16),\n                                          ' ' * struct_input_absinfo_sz)\n                    abs_value, abs_min, abs_max, abs_fuzz, \\\n                        abs_flat, abs_res = struct.unpack('iiiiii', absinfo)\n                    if y == ABS_X:\n                        range_min_position_x = drs('min_position_x', abs_min)\n                        range_max_position_x = drs('max_position_x', abs_max)\n                        Logger.info('LinuxWacom: ' +\n                                    '<%s> range position X is %d - %d' % (\n                                        device_name, abs_min, abs_max))\n                    elif y == ABS_Y:\n                        range_min_position_y = drs('min_position_y', abs_min)\n                        range_max_position_y = drs('max_position_y', abs_max)\n                        Logger.info('LinuxWacom: ' +\n                                    '<%s> range position Y is %d - %d' % (\n                                        device_name, abs_min, abs_max))\n                    elif y == ABS_PRESSURE:\n                        range_min_pressure = drs('min_pressure', abs_min)\n                        range_max_pressure = drs('max_pressure', abs_max)\n                        Logger.info('LinuxWacom: ' +\n                                    '<%s> range pressure is %d - %d' % (\n                                        device_name, abs_min, abs_max))\n\n            # read until the end\n            changed = False\n            touch_id = 0\n            touch_x = 0\n            touch_y = 0\n            touch_pressure = 0\n            while fd:\n\n                data = fd.read(struct_input_event_sz)\n                if len(data) < struct_input_event_sz:\n                    break\n\n                # extract each event\n                for i in range(len(data) / struct_input_event_sz):\n                    ev = data[i * struct_input_event_sz:]\n\n                    # extract timeval + event infos\n                    tv_sec, tv_usec, ev_type, ev_code, ev_value = \\\n                        struct.unpack('LLHHi', ev[:struct_input_event_sz])\n\n                    if ev_type == EV_SYN and ev_code == SYN_REPORT:\n                        if touch_id in l_points:\n                            p = l_points[touch_id]\n                        else:\n                            p = dict()\n                            l_points[touch_id] = p\n                        p['id'] = touch_id\n                        if reset_touch is False:\n                            p['x'] = touch_x\n                            p['y'] = touch_y\n                            p['pressure'] = touch_pressure\n                        if self.mode == 'pen' \\\n                                and touch_pressure == 0 \\\n                                and not reset_touch:\n                            del l_points[touch_id]\n                        if changed:\n                            if not 'x' in p:\n                                reset_touch = False\n                                continue\n                            process(l_points)\n                            changed = False\n                        if reset_touch:\n                            l_points.clear()\n                            reset_touch = False\n                            process(l_points)\n                    elif ev_type == EV_MSC and ev_code == MSC_SERIAL:\n                        touch_id = ev_value\n                    elif ev_type == EV_ABS and ev_code == ABS_X:\n                        val = normalize(ev_value,\n                                        range_min_position_x,\n                                        range_max_position_x)\n                        if invert_x:\n                            val = 1. - val\n                        touch_x = val\n                        changed = True\n                    elif ev_type == EV_ABS and ev_code == ABS_Y:\n                        val = 1. - normalize(ev_value,\n                                             range_min_position_y,\n                                             range_max_position_y)\n                        if invert_y:\n                            val = 1. - val\n                        touch_y = val\n                        changed = True\n                    elif ev_type == EV_ABS and ev_code == ABS_PRESSURE:\n                        touch_pressure = normalize(ev_value,\n                                                   range_min_pressure,\n                                                   range_max_pressure)\n                        changed = True\n                    elif ev_type == EV_ABS and ev_code == ABS_MISC:\n                        if ev_value == 0:\n                            reset_touch = True\n\n        def update(self, dispatch_fn):\n            # dispatch all event from threads\n            try:\n                while True:\n                    event_type, touch = self.queue.popleft()\n                    dispatch_fn(event_type, touch)\n            except:\n                pass\n\n    MotionEventFactory.register('linuxwacom', LinuxWacomMotionEventProvider)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/providers/mactouch.py",
    "content": "'''\nNative support of MultitouchSupport framework for MacBook (MaxOSX platform)\n===========================================================================\n'''\n\n__all__ = ('MacMotionEventProvider', )\n\nimport ctypes\nimport threading\nimport collections\nimport os\nfrom kivy.input.provider import MotionEventProvider\nfrom kivy.input.factory import MotionEventFactory\nfrom kivy.input.motionevent import MotionEvent\nfrom kivy.input.shape import ShapeRect\n\nif 'KIVY_DOC' not in os.environ:\n    CFArrayRef = ctypes.c_void_p\n    CFMutableArrayRef = ctypes.c_void_p\n    CFIndex = ctypes.c_long\n\n    dll = '/System/Library/PrivateFrameworks/' + \\\n        'MultitouchSupport.framework/MultitouchSupport'\n    MultitouchSupport = ctypes.CDLL(dll)\n\n    CFArrayGetCount = MultitouchSupport.CFArrayGetCount\n    CFArrayGetCount.argtypes = [CFArrayRef]\n    CFArrayGetCount.restype = CFIndex\n\n    CFArrayGetValueAtIndex = MultitouchSupport.CFArrayGetValueAtIndex\n    CFArrayGetValueAtIndex.argtypes = [CFArrayRef, CFIndex]\n    CFArrayGetValueAtIndex.restype = ctypes.c_void_p\n\n    MTDeviceCreateList = MultitouchSupport.MTDeviceCreateList\n    MTDeviceCreateList.argtypes = []\n    MTDeviceCreateList.restype = CFMutableArrayRef\n\n    class MTPoint(ctypes.Structure):\n        _fields_ = [('x', ctypes.c_float),\n                    ('y', ctypes.c_float)]\n\n    class MTVector(ctypes.Structure):\n        _fields_ = [('position', MTPoint),\n                    ('velocity', MTPoint)]\n\n    class MTData(ctypes.Structure):\n        _fields_ = [\n            ('frame', ctypes.c_int),\n            ('timestamp', ctypes.c_double),\n            ('identifier', ctypes.c_int),\n            # Current state (of unknown meaning).\n            ('state', ctypes.c_int),\n            ('unknown1', ctypes.c_int),\n            ('unknown2', ctypes.c_int),\n            # Normalized position and vector of the touch (0 to 1)\n            ('normalized', MTVector),\n            # The area of the touch.\n            ('size', ctypes.c_float),\n            ('unknown3', ctypes.c_int),\n            # The following three define the ellipsoid of a finger.\n            ('angle', ctypes.c_float),\n            ('major_axis', ctypes.c_float),\n            ('minor_axis', ctypes.c_float),\n            ('unknown4', MTVector),\n            ('unknown5_1', ctypes.c_int),\n            ('unknown5_2', ctypes.c_int),\n            ('unknown6', ctypes.c_float), ]\n\n    MTDataRef = ctypes.POINTER(MTData)\n\n    MTContactCallbackFunction = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int,\n                                                 MTDataRef, ctypes.c_int,\n                                                 ctypes.c_double, ctypes.c_int)\n\n    MTDeviceRef = ctypes.c_void_p\n\n    MTRegisterContactFrameCallback = \\\n        MultitouchSupport.MTRegisterContactFrameCallback\n    MTRegisterContactFrameCallback.argtypes = \\\n        [MTDeviceRef, MTContactCallbackFunction]\n    MTRegisterContactFrameCallback.restype = None\n\n    MTDeviceStart = MultitouchSupport.MTDeviceStart\n    MTDeviceStart.argtypes = [MTDeviceRef, ctypes.c_int]\n    MTDeviceStart.restype = None\n\nelse:\n    MTContactCallbackFunction = lambda x: None\n\n\nclass MacMotionEvent(MotionEvent):\n    '''MotionEvent representing a contact point on the touchpad. Supports pos\n    and shape profiles.\n    '''\n\n    def depack(self, args):\n        self.is_touch = True\n        self.shape = ShapeRect()\n        self.sx, self.sy = args[0], args[1]\n        self.shape.width = args[2]\n        self.shape.height = args[2]\n        self.profile = ('pos', 'shape')\n        super(MacMotionEvent, self).depack(args)\n\n    def __str__(self):\n        return '<MacMotionEvent id=%d pos=(%f, %f) device=%s>' \\\n            % (self.id, self.sx, self.sy, self.device)\n\n_instance = None\n\n\nclass MacMotionEventProvider(MotionEventProvider):\n\n    def __init__(self, *largs, **kwargs):\n        global _instance\n        if _instance is not None:\n            raise Exception('Only one MacMotionEvent provider is allowed.')\n        _instance = self\n        super(MacMotionEventProvider, self).__init__(*largs, **kwargs)\n\n    def start(self):\n        # global uid\n        self.uid = 0\n        # touches will be per devices\n        self.touches = {}\n        # lock needed to access on uid\n        self.lock = threading.Lock()\n        # event queue to dispatch in main thread\n        self.queue = collections.deque()\n\n        # ok, listing devices, and attach !\n        devices = MultitouchSupport.MTDeviceCreateList()\n        num_devices = CFArrayGetCount(devices)\n        for i in range(num_devices):\n            device = CFArrayGetValueAtIndex(devices, i)\n            # create touch dict for this device\n            data_id = str(device)\n            self.touches[data_id] = {}\n            # start !\n            MTRegisterContactFrameCallback(device, self._mts_callback)\n            MTDeviceStart(device, 0)\n\n    def update(self, dispatch_fn):\n        # dispatch all event from threads\n        try:\n            while True:\n                event_type, touch = self.queue.popleft()\n                dispatch_fn(event_type, touch)\n        except:\n            pass\n\n    def stop(self):\n        # i don't known how to stop it...\n        pass\n\n    @MTContactCallbackFunction\n    def _mts_callback(device, data_ptr, n_fingers, timestamp, frame):\n        global _instance\n        devid = str(device)\n\n        # XXX create live touch, we get one case that\n        # the device announced by macosx don't match the device\n        # in _mts_callback....\n        if not devid in _instance.touches:\n            _instance.touches[devid] = {}\n\n        touches = _instance.touches[devid]\n        actives = []\n\n        for i in range(n_fingers):\n            # get pointer on data\n            data = data_ptr[i]\n\n            # add this touch as an active touch\n            actives.append(data.identifier)\n\n            # extract identifier\n            data_id = data.identifier\n\n            # prepare argument position\n            norm_pos = data.normalized.position\n            args = (norm_pos.x, norm_pos.y, data.size)\n\n            if not data_id in touches:\n                # increment uid\n                _instance.lock.acquire()\n                _instance.uid += 1\n                # create a touch\n                touch = MacMotionEvent(_instance.device, _instance.uid, args)\n                _instance.lock.release()\n                # create event\n                _instance.queue.append(('begin', touch))\n                # store touch\n                touches[data_id] = touch\n            else:\n                touch = touches[data_id]\n                # check if he really moved\n                if data.normalized.position.x == touch.sx and \\\n                   data.normalized.position.y == touch.sy:\n                    continue\n                touch.move(args)\n                _instance.queue.append(('update', touch))\n\n        # delete old touchs\n        for tid in list(touches.keys())[:]:\n            if tid not in actives:\n                touch = touches[tid]\n                touch.update_time_end()\n                _instance.queue.append(('end', touch))\n                del touches[tid]\n\n        return 0\n\nMotionEventFactory.register('mactouch', MacMotionEventProvider)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/providers/mouse.py",
    "content": "'''\nMouse provider implementation\n=============================\n\nOn linux systems, the mouse provider can be annoying when used with another\nmultitouch provider (hidinput or mtdev). The Mouse can conflict with them: a\nsingle touch can generate one event from the mouse provider and another\nfrom the multitouch provider.\n\nTo avoid this behavior, you can activate the \"disable_on_activity\" token in\nthe mouse configuration. Then, if there are any touches activated by another\nprovider, the mouse event will be discarded. Add this to your configuration::\n\n    [input]\n    mouse = mouse,disable_on_activity\n\nUsing multitouch interaction with the mouse\n-------------------------------------------\n\n.. versionadded:: 1.3.0\n\nBy default, the middle and right mouse buttons, as well as a combination of\nctrl + left mouse button are used for multitouch emulation.\nIf you want to use them for other purposes, you can disable this behavior by\nactivating the \"disable_multitouch\" token::\n\n   [input]\n   mouse = mouse,disable_multitouch\n\n.. versionchanged:: 1.9.0\n\nYou can now selectively control whether a click initiated as described above\nwill emulate multi-touch. If the touch has been initiated in the above manner\n(e.g. right mouse button), multitouch_sim will be added to touch's profile,\nand property `multitouch_sim` to the touch. By default `multitouch_sim` is\nTrue and multitouch will be emulated for that touch. However, if\n`multitouch_on_demand` is added to the config::\n\n   [input]\n   mouse = mouse,multitouch_on_demand\n\nthen `multitouch_sim` defaults to `False`. In that case, if before mouse\nrelease (e.g. in on_touch_down/move) `multitouch_sim`\nis set to True, the touch will simulate multi-touch. For example::\n\n    if 'multitouch_sim' in touch.profile:\n        touch.multitouch_sim = True\n\nFollowing is a list of the supported profiles for :class:`MouseMotionEvent`.\n\n=================== ==========================================================\nProfile name        Description\n------------------- ----------------------------------------------------------\nbutton              Mouse button (left, right, middle, scrollup, scrolldown)\n                    Use property `button`\npos                 2D position. Use properties `x`, `y` or `pos``\nmultitouch_sim      If multitouch is simulated. Use property `multitouch_sim`.\n                    See documatation above.\n=================== ==========================================================\n\n'''\n\n__all__ = ('MouseMotionEventProvider', )\n\nfrom kivy.base import EventLoop\nfrom collections import deque\nfrom kivy.logger import Logger\nfrom kivy.input.provider import MotionEventProvider\nfrom kivy.input.factory import MotionEventFactory\nfrom kivy.input.motionevent import MotionEvent\n\n# late binding\nColor = Ellipse = None\n\n\nclass MouseMotionEvent(MotionEvent):\n\n    def depack(self, args):\n        profile = self.profile\n        # don't overwrite previous profile\n        if not profile:\n            profile.extend(('pos', 'button'))\n        self.is_touch = True\n        self.sx, self.sy = args[:2]\n        if len(args) >= 3:\n            self.button = args[2]\n        if len(args) == 4:\n            self.multitouch_sim = args[3]\n            profile.append('multitouch_sim')\n        super(MouseMotionEvent, self).depack(args)\n\n    #\n    # Create automatically touch on the surface.\n    #\n    def update_graphics(self, win, create=False):\n        global Color, Ellipse\n        de = self.ud.get('_drawelement', None)\n        if de is None and create:\n            if Color is None:\n                from kivy.graphics import Color, Ellipse\n            with win.canvas.after:\n                de = (\n                    Color(.8, .2, .2, .7),\n                    Ellipse(size=(20, 20), segments=15))\n            self.ud._drawelement = de\n        if de is not None:\n            self.push()\n            self.scale_for_screen(\n                win.system_size[0],\n                win.system_size[1],\n                rotation=win.rotation)\n            de[1].pos = self.x - 10, self.y - 10\n            self.pop()\n\n    def clear_graphics(self, win):\n        de = self.ud.pop('_drawelement', None)\n        if de is not None:\n            win.canvas.after.remove(de[0])\n            win.canvas.after.remove(de[1])\n\n\nclass MouseMotionEventProvider(MotionEventProvider):\n    __handlers__ = {}\n\n    def __init__(self, device, args):\n        super(MouseMotionEventProvider, self).__init__(device, args)\n        self.waiting_event = deque()\n        self.touches = {}\n        self.counter = 0\n        self.current_drag = None\n        self.alt_touch = None\n        self.disable_on_activity = False\n        self.disable_multitouch = False\n        self.multitouch_on_demenad = False\n\n        # split arguments\n        args = args.split(',')\n        for arg in args:\n            arg = arg.strip()\n            if arg == '':\n                continue\n            elif arg == 'disable_on_activity':\n                self.disable_on_activity = True\n            elif arg == 'disable_multitouch':\n                self.disable_multitouch = True\n            elif arg == 'multitouch_on_demand':\n                self.multitouch_on_demenad = True\n            else:\n                Logger.error('Mouse: unknown parameter <%s>' % arg)\n\n    def start(self):\n        '''Start the mouse provider'''\n        if not EventLoop.window:\n            return\n        EventLoop.window.bind(\n            on_mouse_move=self.on_mouse_motion,\n            on_mouse_down=self.on_mouse_press,\n            on_mouse_up=self.on_mouse_release)\n\n    def stop(self):\n        '''Stop the mouse provider'''\n        if not EventLoop.window:\n            return\n        EventLoop.window.unbind(\n            on_mouse_move=self.on_mouse_motion,\n            on_mouse_down=self.on_mouse_press,\n            on_mouse_up=self.on_mouse_release)\n\n    def test_activity(self):\n        if not self.disable_on_activity:\n            return False\n        # trying to get if we currently have other touch than us\n        # discard touches generated from kinetic\n        touches = EventLoop.touches\n        for touch in touches:\n            # discard all kinetic touch\n            if touch.__class__.__name__ == 'KineticMotionEvent':\n                continue\n            # not our instance, stop mouse\n            if touch.__class__ != MouseMotionEvent:\n                return True\n        return False\n\n    def find_touch(self, x, y):\n        factor = 10. / EventLoop.window.system_size[0]\n        for t in self.touches.values():\n            if abs(x - t.sx) < factor and abs(y - t.sy) < factor:\n                return t\n        return False\n\n    def create_touch(self, rx, ry, is_double_tap, do_graphics, button):\n        self.counter += 1\n        id = 'mouse' + str(self.counter)\n        args = [rx, ry, button]\n        if do_graphics:\n            args += [not self.multitouch_on_demenad]\n        self.current_drag = cur = MouseMotionEvent(self.device, id=id,\n                                                   args=args)\n        cur.is_double_tap = is_double_tap\n        self.touches[id] = cur\n        if do_graphics:\n            cur.update_graphics(EventLoop.window, True)\n        self.waiting_event.append(('begin', cur))\n        return cur\n\n    def remove_touch(self, cur):\n        if cur.id not in self.touches:\n            return\n        del self.touches[cur.id]\n        cur.update_time_end()\n        self.waiting_event.append(('end', cur))\n        cur.clear_graphics(EventLoop.window)\n\n    def on_mouse_motion(self, win, x, y, modifiers):\n        width, height = EventLoop.window.system_size\n        rx = x / float(width)\n        ry = 1. - y / float(height)\n        if self.current_drag:\n            cur = self.current_drag\n            cur.move([rx, ry])\n            cur.update_graphics(win)\n            self.waiting_event.append(('update', cur))\n        elif self.alt_touch is not None and 'alt' not in modifiers:\n            # alt just released ?\n            is_double_tap = 'shift' in modifiers\n            cur = self.create_touch(rx, ry, is_double_tap, True)\n        return True\n\n    def on_mouse_press(self, win, x, y, button, modifiers):\n        if self.test_activity():\n            return\n        width, height = EventLoop.window.system_size\n        rx = x / float(width)\n        ry = 1. - y / float(height)\n        new_me = self.find_touch(rx, ry)\n        if new_me:\n            self.current_drag = new_me\n        else:\n            is_double_tap = 'shift' in modifiers\n            do_graphics = (not self.disable_multitouch) and (\n                button != 'left' or 'ctrl' in modifiers)\n            cur = self.create_touch(rx, ry, is_double_tap, do_graphics, button)\n            if 'alt' in modifiers:\n                self.alt_touch = cur\n                self.current_drag = None\n        return True\n\n    def on_mouse_release(self, win, x, y, button, modifiers):\n        # special case, if button is all, then remove all the current mouses.\n        if button == 'all':\n            for cur in list(self.touches.values())[:]:\n                self.remove_touch(cur)\n            self.current_drag = None\n\n        cur = self.current_drag\n        if (cur and (self.disable_multitouch or 'multitouch_sim' not in\n                     cur.profile or not cur.multitouch_sim)) or\\\n            (button in ('left', 'scrollup', 'scrolldown', 'scrollleft',\n                        'scrollright') and cur and not ('ctrl' in modifiers)):\n            self.remove_touch(cur)\n            self.current_drag = None\n        if self.alt_touch:\n            self.remove_touch(self.alt_touch)\n            self.alt_touch = None\n        return True\n\n    def update(self, dispatch_fn):\n        '''Update the mouse provider (pop event from the queue)'''\n        try:\n            while True:\n                event = self.waiting_event.popleft()\n                dispatch_fn(*event)\n        except IndexError:\n            pass\n\n# registers\nMotionEventFactory.register('mouse', MouseMotionEventProvider)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/providers/mtdev.py",
    "content": "'''\nNative support for Multitouch devices on Linux, using libmtdev.\n===============================================================\n\nThe Mtdev project is a part of the Ubuntu Maverick multitouch architecture.\nYou can read more on http://wiki.ubuntu.com/Multitouch\n\nTo configure MTDev, it's preferable to use probesysfs providers.\nCheck :py:class:`~kivy.input.providers.probesysfs` for more information.\n\nOtherwise, add this to your configuration::\n\n    [input]\n    # devicename = hidinput,/dev/input/eventXX\n    acert230h = mtdev,/dev/input/event2\n\n.. note::\n    You must have read access to the input event.\n\nYou can use a custom range for the X, Y and pressure values.\nOn some drivers, the range reported is invalid.\nTo fix that, you can add these options to the argument line:\n\n* invert_x : 1 to invert X axis\n* invert_y : 1 to invert Y axis\n* min_position_x : X minimum\n* max_position_x : X maximum\n* min_position_y : Y minimum\n* max_position_y : Y maximum\n* min_pressure : pressure minimum\n* max_pressure : pressure maximum\n* min_touch_major : width shape minimum\n* max_touch_major : width shape maximum\n* min_touch_minor : width shape minimum\n* max_touch_minor : height shape maximum\n'''\n\n__all__ = ('MTDMotionEventProvider', 'MTDMotionEvent')\n\nimport os\nfrom kivy.input.motionevent import MotionEvent\nfrom kivy.input.shape import ShapeRect\n\n\nclass MTDMotionEvent(MotionEvent):\n\n    def depack(self, args):\n        self.is_touch = True\n        self.sx = args['x']\n        self.sy = args['y']\n        self.profile = ['pos']\n        if 'size_w' in args and 'size_h' in args:\n            self.shape = ShapeRect()\n            self.shape.width = args['size_w']\n            self.shape.height = args['size_h']\n            self.profile.append('shape')\n        if 'pressure' in args:\n            self.pressure = args['pressure']\n            self.profile.append('pressure')\n        super(MTDMotionEvent, self).depack(args)\n\n    def __str__(self):\n        i, sx, sy, d = (self.id, self.sx, self.sy, self.device)\n        return '<MTDMotionEvent id=%d pos=(%f, %f) device=%s>' % (i, sx, sy, d)\n\nif 'KIVY_DOC' in os.environ:\n\n    # documentation hack\n    MTDMotionEventProvider = None\n\nelse:\n    import threading\n    import collections\n    from kivy.lib.mtdev import Device, \\\n        MTDEV_TYPE_EV_ABS, MTDEV_CODE_SLOT, MTDEV_CODE_POSITION_X, \\\n        MTDEV_CODE_POSITION_Y, MTDEV_CODE_PRESSURE, \\\n        MTDEV_CODE_TOUCH_MAJOR, MTDEV_CODE_TOUCH_MINOR, \\\n        MTDEV_CODE_TRACKING_ID, MTDEV_ABS_POSITION_X, \\\n        MTDEV_ABS_POSITION_Y, MTDEV_ABS_TOUCH_MINOR, \\\n        MTDEV_ABS_TOUCH_MAJOR\n    from kivy.input.provider import MotionEventProvider\n    from kivy.input.factory import MotionEventFactory\n    from kivy.logger import Logger\n\n    class MTDMotionEventProvider(MotionEventProvider):\n\n        options = ('min_position_x', 'max_position_x',\n                   'min_position_y', 'max_position_y',\n                   'min_pressure', 'max_pressure',\n                   'min_touch_major', 'max_touch_major',\n                   'min_touch_minor', 'min_touch_major',\n                   'invert_x', 'invert_y')\n\n        def __init__(self, device, args):\n            super(MTDMotionEventProvider, self).__init__(device, args)\n            self._device = None\n            self.input_fn = None\n            self.default_ranges = dict()\n\n            # split arguments\n            args = args.split(',')\n            if not args:\n                Logger.error('MTD: No filename pass to MTD configuration')\n                Logger.error('MTD: Use /dev/input/event0 for example')\n                return None\n\n            # read filename\n            self.input_fn = args[0]\n            Logger.info('MTD: Read event from <%s>' % self.input_fn)\n\n            # read parameters\n            for arg in args[1:]:\n                if arg == '':\n                    continue\n                arg = arg.split('=')\n\n                # ensure it's a key = value\n                if len(arg) != 2:\n                    err = 'MTD: Bad parameter %s: Not in key=value format' %\\\n                        arg\n                    Logger.error()\n                    continue\n\n                # ensure the key exist\n                key, value = arg\n                if key not in MTDMotionEventProvider.options:\n                    Logger.error('MTD: unknown %s option' % key)\n                    continue\n\n                # ensure the value\n                try:\n                    self.default_ranges[key] = int(value)\n                except ValueError:\n                    err = 'MTD: invalid value %s for option %s' % (key, value)\n                    Logger.error(err)\n                    continue\n\n                # all good!\n                Logger.info('MTD: Set custom %s to %d' % (key, int(value)))\n\n        def start(self):\n            if self.input_fn is None:\n                return\n            self.uid = 0\n            self.queue = collections.deque()\n            self.thread = threading.Thread(\n                target=self._thread_run,\n                kwargs=dict(\n                    queue=self.queue,\n                    input_fn=self.input_fn,\n                    device=self.device,\n                    default_ranges=self.default_ranges))\n            self.thread.daemon = True\n            self.thread.start()\n\n        def _thread_run(self, **kwargs):\n            input_fn = kwargs.get('input_fn')\n            queue = kwargs.get('queue')\n            device = kwargs.get('device')\n            drs = kwargs.get('default_ranges').get\n            touches = {}\n            touches_sent = []\n            point = {}\n            l_points = {}\n\n            def process(points):\n                for args in points:\n                    # this can happen if we have a touch going on already at the\n                    # start of the app\n                    if 'id' not in args:\n                        continue\n                    tid = args['id']\n                    try:\n                        touch = touches[tid]\n                    except KeyError:\n                        touch = MTDMotionEvent(device, tid, args)\n                        touches[touch.id] = touch\n                    touch.move(args)\n                    action = 'update'\n                    if tid not in touches_sent:\n                        action = 'begin'\n                        touches_sent.append(tid)\n                    if 'delete' in args:\n                        action = 'end'\n                        del args['delete']\n                        del touches[touch.id]\n                        touches_sent.remove(tid)\n                        touch.update_time_end()\n                    queue.append((action, touch))\n\n            def normalize(value, vmin, vmax):\n                return (value - vmin) / float(vmax - vmin)\n\n            # open mtdev device\n            _fn = input_fn\n            _slot = 0\n            _device = Device(_fn)\n            _changes = set()\n\n            # prepare some vars to get limit of some component\n            ab = _device.get_abs(MTDEV_ABS_POSITION_X)\n            range_min_position_x = drs('min_position_x', ab.minimum)\n            range_max_position_x = drs('max_position_x', ab.maximum)\n            Logger.info('MTD: <%s> range position X is %d - %d' %\n                        (_fn, range_min_position_x, range_max_position_x))\n\n            ab = _device.get_abs(MTDEV_ABS_POSITION_Y)\n            range_min_position_y = drs('min_position_y', ab.minimum)\n            range_max_position_y = drs('max_position_y', ab.maximum)\n            Logger.info('MTD: <%s> range position Y is %d - %d' %\n                        (_fn, range_min_position_y, range_max_position_y))\n\n            ab = _device.get_abs(MTDEV_ABS_TOUCH_MAJOR)\n            range_min_major = drs('min_touch_major', ab.minimum)\n            range_max_major = drs('max_touch_major', ab.maximum)\n            Logger.info('MTD: <%s> range touch major is %d - %d' %\n                        (_fn, range_min_major, range_max_major))\n\n            ab = _device.get_abs(MTDEV_ABS_TOUCH_MINOR)\n            range_min_minor = drs('min_touch_minor', ab.minimum)\n            range_max_minor = drs('max_touch_minor', ab.maximum)\n            Logger.info('MTD: <%s> range touch minor is %d - %d' %\n                        (_fn, range_min_minor, range_max_minor))\n\n            range_min_pressure = drs('min_pressure', 0)\n            range_max_pressure = drs('max_pressure', 255)\n            Logger.info('MTD: <%s> range pressure is %d - %d' %\n                        (_fn, range_min_pressure, range_max_pressure))\n\n            invert_x = int(bool(drs('invert_x', 0)))\n            invert_y = int(bool(drs('invert_y', 0)))\n            Logger.info('MTD: <%s> axes invertion: X is %d, Y is %d' %\n                        (_fn, invert_x, invert_y))\n\n            while _device:\n                # idle as much as we can.\n                while _device.idle(1000):\n                    continue\n\n                # got data, read all without redoing idle\n                while True:\n                    data = _device.get()\n                    if data is None:\n                        break\n\n                    # set the working slot\n                    if data.type == MTDEV_TYPE_EV_ABS and \\\n                       data.code == MTDEV_CODE_SLOT:\n                        _slot = data.value\n                        continue\n\n                    # fill the slot\n                    if not _slot in l_points:\n                        l_points[_slot] = dict()\n                    point = l_points[_slot]\n                    ev_value = data.value\n                    ev_code = data.code\n                    if ev_code == MTDEV_CODE_POSITION_X:\n                        val = normalize(ev_value,\n                                        range_min_position_x,\n                                        range_max_position_x)\n                        if invert_x:\n                            val = 1. - val\n                        point['x'] = val\n                    elif ev_code == MTDEV_CODE_POSITION_Y:\n                        val = 1. - normalize(ev_value,\n                                             range_min_position_y,\n                                             range_max_position_y)\n                        if invert_y:\n                            val = 1. - val\n                        point['y'] = val\n                    elif ev_code == MTDEV_CODE_PRESSURE:\n                        point['pressure'] = normalize(ev_value,\n                                                      range_min_pressure,\n                                                      range_max_pressure)\n                    elif ev_code == MTDEV_CODE_TOUCH_MAJOR:\n                        point['size_w'] = normalize(ev_value,\n                                                    range_min_major,\n                                                    range_max_major)\n                    elif ev_code == MTDEV_CODE_TOUCH_MINOR:\n                        point['size_h'] = normalize(ev_value,\n                                                    range_min_minor,\n                                                    range_max_minor)\n                    elif ev_code == MTDEV_CODE_TRACKING_ID:\n                        if ev_value == -1:\n                            point['delete'] = True\n                            # force process of changes here, as the slot can be\n                            # reused.\n                            _changes.add(_slot)\n                            process([l_points[x] for x in _changes])\n                            _changes.clear()\n                            continue\n                        else:\n                            point['id'] = ev_value\n                    else:\n                        # unrecognized command, ignore.\n                        continue\n                    _changes.add(_slot)\n\n                # push all changes\n                if _changes:\n                    process([l_points[x] for x in _changes])\n                    _changes.clear()\n\n        def update(self, dispatch_fn):\n            # dispatch all event from threads\n            try:\n                while True:\n                    event_type, touch = self.queue.popleft()\n                    dispatch_fn(event_type, touch)\n            except:\n                pass\n\n    MotionEventFactory.register('mtdev', MTDMotionEventProvider)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/providers/probesysfs.py",
    "content": "'''\nAuto Create Input Provider Config Entry for Available MT Hardware (linux only).\n===============================================================================\n\nThanks to Marc Tardif for the probing code, taken from scan-for-mt-device.\n\nThe device discovery is done by this provider. However, the reading of\ninput can be performed by other providers like: hidinput, mtdev and\nlinuxwacom. mtdev is used prior to other providers. For more\ninformation about mtdev, check :py:class:`~kivy.input.providers.mtdev`.\n\nHere is an example of auto creation::\n\n    [input]\n    # using mtdev\n    device_%(name)s = probesysfs,provider=mtdev\n    # using hidinput\n    device_%(name)s = probesysfs,provider=hidinput\n    # using mtdev with a match on name\n    device_%(name)s = probesysfs,provider=mtdev,match=acer\n\n    # using hidinput with custom parameters to hidinput (all on one line)\n    %(name)s = probesysfs,\n        provider=hidinput,param=min_pressure=1,param=max_pressure=99\n\n    # you can also match your wacom touchscreen\n    touch = probesysfs,match=E3 Finger,provider=linuxwacom,\n        select_all=1,param=mode=touch\n    # and your wacom pen\n    pen = probesysfs,match=E3 Pen,provider=linuxwacom,\n        select_all=1,param=mode=pen\n\nBy default, ProbeSysfs module will enumerate hardware from the /sys/class/input\ndevice, and configure hardware with ABS_MT_POSITION_X capability. But for\nexample, the wacom screen doesn't support this capability. You can prevent this\nbehavior by putting select_all=1 in your config line.\n'''\n\n__all__ = ('ProbeSysfsHardwareProbe', )\n\nimport os\nfrom os.path import sep\n\nif 'KIVY_DOC' in os.environ:\n\n    ProbeSysfsHardwareProbe = None\n\nelse:\n    from re import match, IGNORECASE\n    from glob import glob\n    from subprocess import Popen, PIPE\n    from kivy.logger import Logger\n    from kivy.input.provider import MotionEventProvider\n    from kivy.input.factory import MotionEventFactory\n    from kivy.config import _is_rpi\n\n    # See linux/input.h\n    ABS_MT_POSITION_X = 0x35\n\n    _cache_input = None\n\n    class Input(object):\n\n        def __init__(self, path):\n            self.path = path\n\n        @property\n        def device(self):\n            base = os.path.basename(self.path)\n            return os.path.join(\"/dev\", \"input\", base)\n\n        @property\n        def name(self):\n            path = os.path.join(self.path, \"device\", \"name\")\n            return read_line(path)\n\n        def get_capabilities(self):\n            path = os.path.join(self.path, \"device\", \"capabilities\", \"abs\")\n            line = read_line(path)\n            capabilities = []\n            long_bit = getconf(\"LONG_BIT\")\n            for i, word in enumerate(line.split(\" \")):\n                word = int(word, 16)\n                subcapabilities = [bool(word & 1 << i)\n                                   for i in range(long_bit)]\n                capabilities[:0] = subcapabilities\n\n            return capabilities\n\n        def has_capability(self, capability):\n            capabilities = self.get_capabilities()\n            return len(capabilities) > capability and capabilities[capability]\n\n    def getconf(var):\n        output = Popen([\"getconf\", var], stdout=PIPE).communicate()[0]\n        return int(output)\n\n    def get_inputs(path):\n        global _cache_input\n        if _cache_input is None:\n            event_glob = os.path.join(path, \"event*\")\n            _cache_input = [Input(x) for x in glob(event_glob)]\n        return _cache_input\n\n    def read_line(path):\n        f = open(path)\n        try:\n            return f.readline().strip()\n        finally:\n            f.close()\n\n    class ProbeSysfsHardwareProbe(MotionEventProvider):\n\n        def __new__(self, device, args):\n            # hack to not return an instance of this provider.\n            # :)\n            instance = super(ProbeSysfsHardwareProbe, self).__new__(self)\n            instance.__init__(device, args)\n\n        def __init__(self, device, args):\n            super(ProbeSysfsHardwareProbe, self).__init__(device, args)\n            self.provider = 'mtdev'\n            self.match = None\n            self.input_path = '/sys/class/input'\n            self.select_all = True if _is_rpi else False\n            self.use_regex = False\n            self.args = []\n\n            args = args.split(',')\n            for arg in args:\n                if arg == '':\n                    continue\n                arg = arg.split('=', 1)\n                # ensure it's a key = value\n                if len(arg) != 2:\n                    Logger.error('ProbeSysfs: invalid parameters %s, not'\n                                 ' key=value format' % arg)\n                    continue\n\n                key, value = arg\n                if key == 'match':\n                    self.match = value\n                elif key == 'provider':\n                    self.provider = value\n                elif key == 'use_regex':\n                    self.use_regex = bool(value)\n                elif key == 'select_all':\n                    self.select_all = bool(value)\n                elif key == 'param':\n                    self.args.append(value)\n                else:\n                    Logger.error('ProbeSysfs: unknown %s option' % key)\n                    continue\n\n            self.probe()\n\n        def probe(self):\n            inputs = get_inputs(self.input_path)\n            Logger.debug('ProbeSysfs: using probsysfs!')\n            if not self.select_all:\n                inputs = [x for x in inputs if\n                          x.has_capability(ABS_MT_POSITION_X)]\n            for device in inputs:\n                Logger.debug('ProbeSysfs: found device: %s at %s' % (\n                    device.name, device.device))\n\n                # must ignore ?\n                if self.match:\n                    if self.use_regex:\n                        if not match(self.match, device.name, IGNORECASE):\n                            Logger.debug('ProbeSysfs: device not match the'\n                                         ' rule in config, ignoring.')\n                            continue\n                    else:\n                        if self.match not in device.name:\n                            continue\n\n                Logger.info('ProbeSysfs: device match: %s' % device.device)\n\n                d = device.device\n                devicename = self.device % dict(name=d.split(sep)[-1])\n\n                provider = MotionEventFactory.get(self.provider)\n                if provider is None:\n                    Logger.info('ProbeSysfs: unable to found provider %s' %\n                                self.provider)\n                    Logger.info('ProbeSysfs: fallback on hidinput')\n                    provider = MotionEventFactory.get('hidinput')\n                if provider is None:\n                    Logger.critical('ProbeSysfs: no input provider found'\n                                    ' to handle this device !')\n                    continue\n\n                instance = provider(devicename, '%s,%s' % (\n                    device.device, ','.join(self.args)))\n                if instance:\n                    from kivy.base import EventLoop\n                    EventLoop.add_input_provider(instance)\n\n    MotionEventFactory.register('probesysfs', ProbeSysfsHardwareProbe)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/providers/tuio.py",
    "content": "'''\nTUIO Input Provider\n===================\n\nTUIO is the de facto standard network protocol for the transmission of\ntouch and fiducial information between a server and a client. To learn\nmore about TUIO (which is itself based on the OSC protocol), please\nrefer to http://tuio.org -- The specification should be of special\ninterest.\n\nConfigure a TUIO provider in the config.ini\n-------------------------------------------\n\nThe TUIO provider can be configured in the configuration file in the\n``[input]`` section::\n\n    [input]\n    # name = tuio,<ip>:<port>\n    multitouchtable = tuio,192.168.0.1:3333\n\nConfigure a TUIO provider in the App\n------------------------------------\n\nYou must add the provider before your application is run, like this::\n\n    from kivy.app import App\n    from kivy.config import Config\n\n    class TestApp(App):\n        def build(self):\n            Config.set('input', 'multitouchscreen1', 'tuio,0.0.0.0:3333')\n            # You can also add a second TUIO listener\n            # Config.set('input', 'source2', 'tuio,0.0.0.0:3334')\n            # Then do the usual things\n            # ...\n            return\n'''\n\n__all__ = ('TuioMotionEventProvider', 'Tuio2dCurMotionEvent',\n           'Tuio2dObjMotionEvent')\n\nfrom kivy.lib import osc\nfrom collections import deque\nfrom kivy.input.provider import MotionEventProvider\nfrom kivy.input.factory import MotionEventFactory\nfrom kivy.input.motionevent import MotionEvent\nfrom kivy.input.shape import ShapeRect\nfrom kivy.logger import Logger\n\n\nclass TuioMotionEventProvider(MotionEventProvider):\n    '''The TUIO provider listens to a socket and handles some of the incoming\n    OSC messages:\n\n        * /tuio/2Dcur\n        * /tuio/2Dobj\n\n    You can easily extend the provider to handle new TUIO paths like so::\n\n        # Create a class to handle the new TUIO type/path\n        # Replace NEWPATH with the pathname you want to handle\n        class TuioNEWPATHMotionEvent(MotionEvent):\n            def __init__(self, id, args):\n                super(TuioNEWPATHMotionEvent, self).__init__(id, args)\n\n            def depack(self, args):\n                # In this method, implement 'unpacking' for the received\n                # arguments. you basically translate from TUIO args to Kivy\n                # MotionEvent variables. If all you receive are x and y\n                # values, you can do it like this:\n                if len(args) == 2:\n                    self.sx, self.sy = args\n                    self.profile = ('pos', )\n                self.sy = 1 - self.sy\n                super(TuioNEWPATHMotionEvent, self).depack(args)\n\n        # Register it with the TUIO MotionEvent provider.\n        # You obviously need to replace the PATH placeholders appropriately.\n        TuioMotionEventProvider.register('/tuio/PATH', TuioNEWPATHMotionEvent)\n\n    .. note::\n\n        The class name is of no technical importance. Your class will be\n        associated with the path that you pass to the ``register()``\n        function. To keep things simple, you should name your class after the\n        path that it handles, though.\n    '''\n\n    __handlers__ = {}\n\n    def __init__(self, device, args):\n        super(TuioMotionEventProvider, self).__init__(device, args)\n        args = args.split(',')\n        if len(args) <= 0:\n            Logger.error('Tuio: Invalid configuration for TUIO provider')\n            Logger.error('Tuio: Format must be ip:port (eg. 127.0.0.1:3333)')\n            err = 'Tuio: Current configuration is <%s>' % (str(','.join(args)))\n            Logger.error(err)\n            return None\n        ipport = args[0].split(':')\n        if len(ipport) != 2:\n            Logger.error('Tuio: Invalid configuration for TUIO provider')\n            Logger.error('Tuio: Format must be ip:port (eg. 127.0.0.1:3333)')\n            err = 'Tuio: Current configuration is <%s>' % (str(','.join(args)))\n            Logger.error(err)\n            return None\n        self.ip, self.port = args[0].split(':')\n        self.port = int(self.port)\n        self.handlers = {}\n        self.oscid = None\n        self.tuio_event_q = deque()\n        self.touches = {}\n\n    @staticmethod\n    def register(oscpath, classname):\n        '''Register a new path to handle in TUIO provider'''\n        TuioMotionEventProvider.__handlers__[oscpath] = classname\n\n    @staticmethod\n    def unregister(oscpath, classname):\n        '''Unregister a path to stop handling it in the TUIO provider'''\n        if oscpath in TuioMotionEventProvider.__handlers__:\n            del TuioMotionEventProvider.__handlers__[oscpath]\n\n    @staticmethod\n    def create(oscpath, **kwargs):\n        '''Create a touch event from a TUIO path'''\n        if oscpath not in TuioMotionEventProvider.__handlers__:\n            raise Exception('Unknown %s touch path' % oscpath)\n        return TuioMotionEventProvider.__handlers__[oscpath](**kwargs)\n\n    def start(self):\n        '''Start the TUIO provider'''\n        self.oscid = osc.listen(self.ip, self.port)\n        for oscpath in TuioMotionEventProvider.__handlers__:\n            self.touches[oscpath] = {}\n            osc.bind(self.oscid, self._osc_tuio_cb, oscpath)\n\n    def stop(self):\n        '''Stop the TUIO provider'''\n        osc.dontListen(self.oscid)\n\n    def update(self, dispatch_fn):\n        '''Update the TUIO provider (pop events from the queue)'''\n\n        # deque osc queue\n        osc.readQueue(self.oscid)\n\n        # read the Queue with event\n        while True:\n            try:\n                value = self.tuio_event_q.pop()\n            except IndexError:\n                # queue is empty, we're done for now\n                return\n            self._update(dispatch_fn, value)\n\n    def _osc_tuio_cb(self, *incoming):\n        message = incoming[0]\n        oscpath, types, args = message[0], message[1], message[2:]\n        self.tuio_event_q.appendleft([oscpath, args, types])\n\n    def _update(self, dispatch_fn, value):\n        oscpath, args, types = value\n        command = args[0]\n\n        # verify commands\n        if command not in ['alive', 'set']:\n            return\n\n        # move or create a new touch\n        if command == 'set':\n            id = args[1]\n            if id not in self.touches[oscpath]:\n                # new touch\n                touch = TuioMotionEventProvider.__handlers__[oscpath](\n                    self.device, id, args[2:])\n                self.touches[oscpath][id] = touch\n                dispatch_fn('begin', touch)\n            else:\n                # update a current touch\n                touch = self.touches[oscpath][id]\n                touch.move(args[2:])\n                dispatch_fn('update', touch)\n\n        # alive event, check for deleted touch\n        if command == 'alive':\n            alives = args[1:]\n            to_delete = []\n            for id in self.touches[oscpath]:\n                if not id in alives:\n                    # touch up\n                    touch = self.touches[oscpath][id]\n                    if not touch in to_delete:\n                        to_delete.append(touch)\n\n            for touch in to_delete:\n                dispatch_fn('end', touch)\n                del self.touches[oscpath][touch.id]\n\n\nclass TuioMotionEvent(MotionEvent):\n    '''Abstraction for TUIO touches/fiducials.\n\n    Depending on the tracking software you use (e.g. Movid, CCV, etc.) and its\n    TUIO implementation, the TuioMotionEvent object can support multiple\n    profiles such as:\n\n        * Fiducial ID: profile name 'markerid', attribute ``.fid``\n        * Position: profile name 'pos', attributes ``.x``, ``.y``\n        * Angle: profile name 'angle', attribute ``.a``\n        * Velocity vector: profile name 'mov', attributes ``.X``, ``.Y``\n        * Rotation velocity: profile name 'rot', attribute ``.A``\n        * Motion acceleration: profile name 'motacc', attribute ``.m``\n        * Rotation acceleration: profile name 'rotacc', attribute ``.r``\n    '''\n    __attrs__ = ('a', 'b', 'c', 'X', 'Y', 'Z', 'A', 'B', 'C', 'm', 'r')\n\n    def __init__(self, device, id, args):\n        super(TuioMotionEvent, self).__init__(device, id, args)\n        # Default argument for TUIO touches\n        self.a = 0.0\n        self.b = 0.0\n        self.c = 0.0\n        self.X = 0.0\n        self.Y = 0.0\n        self.Z = 0.0\n        self.A = 0.0\n        self.B = 0.0\n        self.C = 0.0\n        self.m = 0.0\n        self.r = 0.0\n\n    angle = property(lambda self: self.a)\n    mot_accel = property(lambda self: self.m)\n    rot_accel = property(lambda self: self.r)\n    xmot = property(lambda self: self.X)\n    ymot = property(lambda self: self.Y)\n    zmot = property(lambda self: self.Z)\n\n\nclass Tuio2dCurMotionEvent(TuioMotionEvent):\n    '''A 2dCur TUIO touch.'''\n\n    def __init__(self, device, id, args):\n        super(Tuio2dCurMotionEvent, self).__init__(device, id, args)\n\n    def depack(self, args):\n        self.is_touch = True\n        if len(args) < 5:\n            self.sx, self.sy = list(map(float, args[0:2]))\n            self.profile = ('pos', )\n        elif len(args) == 5:\n            self.sx, self.sy, self.X, self.Y, self.m = list(map(float,\n                                                                args[0:5]))\n            self.Y = -self.Y\n            self.profile = ('pos', 'mov', 'motacc')\n        else:\n            self.sx, self.sy, self.X, self.Y = list(map(float, args[0:4]))\n            self.m, width, height = list(map(float, args[4:7]))\n            self.Y = -self.Y\n            self.profile = ('pos', 'mov', 'motacc', 'shape')\n            if self.shape is None:\n                self.shape = ShapeRect()\n            self.shape.width = width\n            self.shape.height = height\n        self.sy = 1 - self.sy\n        super(Tuio2dCurMotionEvent, self).depack(args)\n\n\nclass Tuio2dObjMotionEvent(TuioMotionEvent):\n    '''A 2dObj TUIO object.\n    '''\n\n    def __init__(self, device, id, args):\n        super(Tuio2dObjMotionEvent, self).__init__(device, id, args)\n\n    def depack(self, args):\n        self.is_touch = True\n        if len(args) < 5:\n            self.sx, self.sy = args[0:2]\n            self.profile = ('pos', )\n        elif len(args) == 9:\n            self.fid, self.sx, self.sy, self.a, self.X, self.Y = args[:6]\n            self.A, self.m, self.r = args[6:9]\n            self.Y = -self.Y\n            self.profile = ('markerid', 'pos', 'angle', 'mov', 'rot',\n                            'motacc', 'rotacc')\n        else:\n            self.fid, self.sx, self.sy, self.a, self.X, self.Y = args[:6]\n            self.A, self.m, self.r, width, height = args[6:11]\n            self.Y = -self.Y\n            self.profile = ('markerid', 'pos', 'angle', 'mov', 'rot', 'rotacc',\n                            'acc', 'shape')\n            if self.shape is None:\n                self.shape = ShapeRect()\n                self.shape.width = width\n                self.shape.height = height\n        self.sy = 1 - self.sy\n        super(Tuio2dObjMotionEvent, self).depack(args)\n\n\nclass Tuio2dBlbMotionEvent(TuioMotionEvent):\n    '''A 2dBlb TUIO object.\n    # FIXME 3d shape are not supported\n    /tuio/2Dobj set s i x y a       X Y A m r\n    /tuio/2Dblb set s   x y a w h f X Y A m r\n    '''\n\n    def __init__(self, device, id, args):\n        super(Tuio2dBlbMotionEvent, self).__init__(device, id, args)\n\n    def depack(self, args):\n        self.is_touch = True\n        self.sx, self.sy, self.a, self.X, self.Y, sw, sh, sd, \\\n            self.A, self.m, self.r = args\n        self.Y = -self.Y\n        self.profile = ('pos', 'angle', 'mov', 'rot', 'rotacc',\n                        'acc', 'shape')\n        if self.shape is None:\n            self.shape = ShapeRect()\n            self.shape.width = sw\n            self.shape.height = sh\n        self.sy = 1 - self.sy\n        super(Tuio2dBlbMotionEvent, self).depack(args)\n\n\n# registers\nTuioMotionEventProvider.register('/tuio/2Dcur', Tuio2dCurMotionEvent)\nTuioMotionEventProvider.register('/tuio/2Dobj', Tuio2dObjMotionEvent)\nTuioMotionEventProvider.register('/tuio/2Dblb', Tuio2dBlbMotionEvent)\nMotionEventFactory.register('tuio', TuioMotionEventProvider)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/providers/wm_common.py",
    "content": "'''\nCommon definitions for a Windows provider\n=========================================\n\nThis file provides common definitions for constants used by WM_Touch / WM_Pen.\n'''\n\nWM_MOUSEFIRST = 512\nWM_MOUSEMOVE = 512\nWM_LBUTTONDOWN = 513\nWM_LBUTTONUP = 514\nWM_LBUTTONDBLCLK = 515\nWM_RBUTTONDOWN = 516\nWM_RBUTTONUP = 517\nWM_RBUTTONDBLCLK = 518\nWM_MBUTTONDOWN = 519\nWM_MBUTTONUP = 520\nWM_MBUTTONDBLCLK = 521\nWM_MOUSEWHEEL = 522\nWM_MOUSELAST = 522\n\nWM_TOUCH = 576\nTOUCHEVENTF_MOVE = 1\nTOUCHEVENTF_DOWN = 2\nTOUCHEVENTF_UP = 4\n\nPEN_OR_TOUCH_SIGNATURE = 0xFF515700\nPEN_OR_TOUCH_MASK = 0xFFFFFF00\nPEN_EVENT_TOUCH_MASK = 0x80\n\nSM_CYCAPTION = 4\n\nWM_TABLET_QUERYSYSTEMGESTURE = 0x000002CC\nTABLET_DISABLE_PRESSANDHOLD = 0x00000001\nTABLET_DISABLE_PENTAPFEEDBACK = 0x00000008\nTABLET_DISABLE_PENBARRELFEEDBACK = 0x00000010\nTABLET_DISABLE_TOUCHUIFORCEON = 0x00000100\nTABLET_DISABLE_TOUCHUIFORCEOFF = 0x00000200\nTABLET_DISABLE_TOUCHSWITCH = 0x00008000\nTABLET_DISABLE_FLICKS = 0x00010000\nTABLET_ENABLE_FLICKSONCONTEXT = 0x00020000\nTABLET_ENABLE_FLICKLEARNINGMODE = 0x00040000\nTABLET_DISABLE_SMOOTHSCROLLING = 0x00080000\nTABLET_DISABLE_FLICKFALLBACKKEYS = 0x00100000\nGWL_WNDPROC = -4\n\n\nQUERYSYSTEMGESTURE_WNDPROC = (\n    TABLET_DISABLE_PRESSANDHOLD |\n    TABLET_DISABLE_PENTAPFEEDBACK |\n    TABLET_DISABLE_PENBARRELFEEDBACK |\n    TABLET_DISABLE_SMOOTHSCROLLING |\n    TABLET_DISABLE_FLICKFALLBACKKEYS |\n    TABLET_DISABLE_TOUCHSWITCH |\n    TABLET_DISABLE_FLICKS)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/providers/wm_pen.py",
    "content": "'''\nSupport for WM_PEN messages (Windows platform)\n==============================================\n'''\n\n__all__ = ('WM_PenProvider', 'WM_Pen')\n\nimport os\nfrom kivy.input.providers.wm_common import (\n    PEN_OR_TOUCH_SIGNATURE, PEN_OR_TOUCH_MASK, GWL_WNDPROC,\n    WM_MOUSEMOVE, WM_LBUTTONUP, WM_LBUTTONDOWN,\n    WM_TABLET_QUERYSYSTEMGESTURE, QUERYSYSTEMGESTURE_WNDPROC,\n    PEN_EVENT_TOUCH_MASK)\nfrom kivy.input.motionevent import MotionEvent\n\n\nclass WM_Pen(MotionEvent):\n    '''MotionEvent representing the WM_Pen event. Supports the pos profile.'''\n\n    def depack(self, args):\n        self.is_touch = True\n        self.sx, self.sy = args[0], args[1]\n        super(WM_Pen, self).depack(args)\n\n    def __str__(self):\n        i, u, s, d = (self.id, self.uid, str(self.spos), self.device)\n        return '<WMPen id:%d uid:%d pos:%s device:%s>' % (i, u, s, d)\nif 'KIVY_DOC' in os.environ:\n    # documentation hack\n    WM_PenProvider = None\n\nelse:\n    from collections import deque\n    from ctypes.wintypes import (ULONG, UINT, WPARAM, LPARAM,\n                                 HANDLE, BOOL)\n    from ctypes import (Structure, windll, byref, c_int16,\n                        c_int, WINFUNCTYPE, POINTER)\n    from kivy.input.provider import MotionEventProvider\n    from kivy.input.factory import MotionEventFactory\n\n    LRESULT = LPARAM\n    WNDPROC = WINFUNCTYPE(LRESULT, HANDLE, UINT, WPARAM, LPARAM)\n\n    class RECT(Structure):\n        _fields_ = [\n            ('left', ULONG),\n            ('top', ULONG),\n            ('right', ULONG),\n            ('bottom', ULONG)]\n\n        x = property(lambda self: self.left)\n        y = property(lambda self: self.top)\n        w = property(lambda self: self.right - self.left)\n        h = property(lambda self: self.bottom - self.top)\n    win_rect = RECT()\n\n    try:\n        windll.user32.SetWindowLongPtrW.restype = WNDPROC\n        windll.user32.SetWindowLongPtrW.argtypes = [HANDLE, c_int, WNDPROC]\n        SetWindowLong_wrapper = windll.user32.SetWindowLongPtrW\n    except AttributeError:\n        windll.user32.SetWindowLongW.restype = WNDPROC\n        windll.user32.SetWindowLongW.argtypes = [HANDLE, c_int, WNDPROC]\n        SetWindowLong_wrapper = windll.user32.SetWindowLongW\n\n    windll.user32.GetMessageExtraInfo.restype = LPARAM\n    windll.user32.GetMessageExtraInfo.argtypes = []\n    windll.user32.GetClientRect.restype = BOOL\n    windll.user32.GetClientRect.argtypes = [HANDLE, POINTER(RECT)]\n    windll.user32.CallWindowProcW.restype = LRESULT\n    windll.user32.CallWindowProcW.argtypes = [WNDPROC, HANDLE, UINT, WPARAM,\n                                              LPARAM]\n    windll.user32.GetActiveWindow.restype = HANDLE\n    windll.user32.GetActiveWindow.argtypes = []\n\n    class WM_PenProvider(MotionEventProvider):\n\n        def _is_pen_message(self, msg):\n            info = windll.user32.GetMessageExtraInfo()\n            # It's a touch or a pen\n            if (info & PEN_OR_TOUCH_MASK) == PEN_OR_TOUCH_SIGNATURE:\n                if not info & PEN_EVENT_TOUCH_MASK:\n                    return True\n\n        def _pen_handler(self, msg, wParam, lParam):\n            if msg not in (WM_LBUTTONDOWN, WM_MOUSEMOVE, WM_LBUTTONUP):\n                return\n\n            windll.user32.GetClientRect(self.hwnd, byref(win_rect))\n            x = c_int16(lParam & 0xffff).value / float(win_rect.w)\n            y = c_int16(lParam >> 16).value / float(win_rect.h)\n            y = abs(1.0 - y)\n\n            if msg == WM_LBUTTONDOWN:\n                self.pen_events.appendleft(('begin', x, y))\n                self.pen_status = True\n\n            if msg == WM_MOUSEMOVE and self.pen_status:\n                self.pen_events.appendleft(('update', x, y))\n\n            if msg == WM_LBUTTONUP:\n                self.pen_events.appendleft(('end', x, y))\n                self.pen_status = False\n\n        def _pen_wndProc(self, hwnd, msg, wParam, lParam):\n            if msg == WM_TABLET_QUERYSYSTEMGESTURE:\n                return QUERYSYSTEMGESTURE_WNDPROC\n            if self._is_pen_message(msg):\n                self._pen_handler(msg, wParam, lParam)\n                return 1\n            else:\n                return windll.user32.CallWindowProcW(self.old_windProc,\n                                                     hwnd, msg, wParam, lParam)\n\n        def start(self):\n            self.uid = 0\n            self.pen = None\n            self.pen_status = None\n            self.pen_events = deque()\n\n            self.hwnd = windll.user32.GetActiveWindow()\n\n            # inject our own wndProc to handle messages\n            # before window manager does\n            self.new_windProc = WNDPROC(self._pen_wndProc)\n            self.old_windProc = SetWindowLong_wrapper(\n                self.hwnd, GWL_WNDPROC, self.new_windProc)\n\n        def update(self, dispatch_fn):\n            while True:\n\n                try:\n                    etype, x, y = self.pen_events.pop()\n                except:\n                    break\n\n                if etype == 'begin':\n                    self.uid += 1\n                    self.pen = WM_Pen(self.device, self.uid, [x, y])\n                elif etype == 'update':\n                    self.pen.move([x, y])\n                elif etype == 'end':\n                    self.pen.update_time_end()\n\n                dispatch_fn(etype, self.pen)\n\n        def stop(self):\n            self.pen = None\n            SetWindowLong_wrapper(self.hwnd, GWL_WNDPROC, self.old_windProc)\n\n    MotionEventFactory.register('wm_pen', WM_PenProvider)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/providers/wm_touch.py",
    "content": "'''\nSupport for WM_TOUCH messages (Windows platform)\n================================================\n'''\n\n__all__ = ('WM_MotionEventProvider', 'WM_MotionEvent')\n\nimport os\nfrom kivy.input.providers.wm_common import (\n    WM_TABLET_QUERYSYSTEMGESTURE,\n    GWL_WNDPROC, QUERYSYSTEMGESTURE_WNDPROC, WM_TOUCH, WM_MOUSEMOVE,\n    WM_MOUSELAST, PEN_OR_TOUCH_MASK, PEN_OR_TOUCH_SIGNATURE,\n    PEN_EVENT_TOUCH_MASK, TOUCHEVENTF_UP, TOUCHEVENTF_DOWN,\n    TOUCHEVENTF_MOVE, SM_CYCAPTION)\nfrom kivy.input.motionevent import MotionEvent\nfrom kivy.input.shape import ShapeRect\n\n\nclass WM_MotionEvent(MotionEvent):\n    '''MotionEvent representing the WM_MotionEvent event.\n       Supports pos, shape and size profiles.\n    '''\n    __attrs__ = ('size', )\n\n    def depack(self, args):\n        self.is_touch = True\n        self.shape = ShapeRect()\n        self.sx, self.sy = args[0], args[1]\n        self.shape.width = args[2][0]\n        self.shape.height = args[2][1]\n        self.size = self.shape.width * self.shape.height\n        self.profile = ('pos', 'shape', 'size')\n\n        super(WM_MotionEvent, self).depack(args)\n\n    def __str__(self):\n        args = (self.id, self.uid, str(self.spos), self.device)\n        return '<WMMotionEvent id:%d uid:%d pos:%s device:%s>' % args\n\nif 'KIVY_DOC' in os.environ:\n    # documentation hack\n    WM_MotionEventProvider = None\n\nelse:\n    from ctypes.wintypes import (ULONG, HANDLE, DWORD, LONG, UINT,\n                                 WPARAM, LPARAM, BOOL)\n    from ctypes import (windll, WINFUNCTYPE, POINTER,\n                        c_int, Structure, sizeof, byref)\n    from collections import deque\n    from kivy.input.provider import MotionEventProvider\n    from kivy.input.factory import MotionEventFactory\n\n    # check availability of RegisterTouchWindow\n    if not hasattr(windll.user32, 'RegisterTouchWindow'):\n        raise Exception('Unsupported Window version')\n\n    LRESULT = LPARAM\n    WNDPROC = WINFUNCTYPE(LRESULT, HANDLE, UINT, WPARAM, LPARAM)\n\n    class TOUCHINPUT(Structure):\n        _fields_ = [\n            ('x', LONG),\n            ('y', LONG),\n            ('pSource', HANDLE),\n            ('id', DWORD),\n            ('flags', DWORD),\n            ('mask', DWORD),\n            ('time', DWORD),\n            ('extraInfo', POINTER(ULONG)),\n            ('size_x', DWORD),\n            ('size_y', DWORD)]\n\n        def size(self):\n            return (self.size_x, self.size_y)\n\n        def screen_x(self):\n            return self.x / 100.0\n\n        def screen_y(self):\n            return self.y / 100.0\n\n        def _event_type(self):\n            if self.flags & TOUCHEVENTF_MOVE:\n                return 'update'\n            if self.flags & TOUCHEVENTF_DOWN:\n                return 'begin'\n            if self.flags & TOUCHEVENTF_UP:\n                return 'end'\n        event_type = property(_event_type)\n\n    class RECT(Structure):\n        _fields_ = [\n            ('left', LONG),\n            ('top', LONG),\n            ('right', LONG),\n            ('bottom', LONG)]\n\n        x = property(lambda self: self.left)\n        y = property(lambda self: self.top)\n        w = property(lambda self: self.right - self.left)\n        h = property(lambda self: self.bottom - self.top)\n\n    try:\n        windll.user32.SetWindowLongPtrW.restype = WNDPROC\n        windll.user32.SetWindowLongPtrW.argtypes = [HANDLE, c_int, WNDPROC]\n        SetWindowLong_wrapper = windll.user32.SetWindowLongPtrW\n    except AttributeError:\n        windll.user32.SetWindowLongW.restype = WNDPROC\n        windll.user32.SetWindowLongW.argtypes = [HANDLE, c_int, WNDPROC]\n        SetWindowLong_wrapper = windll.user32.SetWindowLongW\n\n    windll.user32.GetMessageExtraInfo.restype = LPARAM\n    windll.user32.GetMessageExtraInfo.argtypes = []\n    windll.user32.GetClientRect.restype = BOOL\n    windll.user32.GetClientRect.argtypes = [HANDLE, POINTER(RECT)]\n    windll.user32.GetWindowRect.restype = BOOL\n    windll.user32.GetWindowRect.argtypes = [HANDLE, POINTER(RECT)]\n    windll.user32.CallWindowProcW.restype = LRESULT\n    windll.user32.CallWindowProcW.argtypes = [WNDPROC, HANDLE, UINT, WPARAM,\n                                              LPARAM]\n    windll.user32.GetActiveWindow.restype = HANDLE\n    windll.user32.GetActiveWindow.argtypes = []\n    windll.user32.RegisterTouchWindow.restype = BOOL\n    windll.user32.RegisterTouchWindow.argtypes = [HANDLE, ULONG]\n    windll.user32.UnregisterTouchWindow.restype = BOOL\n    windll.user32.UnregisterTouchWindow.argtypes = [HANDLE]\n    windll.user32.GetTouchInputInfo.restype = BOOL\n    windll.user32.GetTouchInputInfo.argtypes = [HANDLE, UINT,\n                                                POINTER(TOUCHINPUT), c_int]\n    windll.user32.GetSystemMetrics.restype = c_int\n    windll.user32.GetSystemMetrics.argtypes = [c_int]\n\n    class WM_MotionEventProvider(MotionEventProvider):\n\n        def start(self):\n            self.touch_events = deque()\n            self.touches = {}\n            self.uid = 0\n\n            # get window handle, and register to recive WM_TOUCH messages\n            self.hwnd = windll.user32.GetActiveWindow()\n            windll.user32.RegisterTouchWindow(self.hwnd, 1)\n\n            # inject our own wndProc to handle messages\n            # before window manager does\n            self.new_windProc = WNDPROC(self._touch_wndProc)\n            self.old_windProc = SetWindowLong_wrapper(\n                self.hwnd, GWL_WNDPROC, self.new_windProc)\n\n            self.caption_size = windll.user32.GetSystemMetrics(SM_CYCAPTION)\n\n        def update(self, dispatch_fn):\n            win_rect = RECT()\n            windll.user32.GetWindowRect(self.hwnd, byref(win_rect))\n            caption = self.caption_size\n\n            while True:\n                try:\n                    t = self.touch_events.pop()\n                except:\n                    break\n\n                # adjust x,y to window coordinates (0.0 to 1.0)\n                x = (t.screen_x() - win_rect.x) / float(win_rect.w)\n                y = 1.0 - (t.screen_y() - win_rect.y - caption\n                           ) / float(win_rect.h)\n\n                # actually dispatch input\n                if t.event_type == 'begin':\n                    self.uid += 1\n                    self.touches[t.id] = WM_MotionEvent(\n                        self.device, self.uid, [x, y, t.size()])\n                    dispatch_fn('begin', self.touches[t.id])\n\n                if t.event_type == 'update' and t.id in self.touches:\n                    self.touches[t.id].move([x, y, t.size()])\n                    dispatch_fn('update', self.touches[t.id])\n\n                if t.event_type == 'end' and t.id in self.touches:\n                    touch = self.touches[t.id]\n                    touch.move([x, y, t.size()])\n                    touch.update_time_end()\n                    dispatch_fn('end', touch)\n                    del self.touches[t.id]\n\n        def stop(self):\n            windll.user32.UnregisterTouchWindow(self.hwnd)\n            self.new_windProc = SetWindowLong_wrapper(\n                self.hwnd, GWL_WNDPROC, self.old_windProc)\n\n        # we inject this wndProc into our main window, to process\n        # WM_TOUCH and mouse messages before the window manager does\n        def _touch_wndProc(self, hwnd, msg, wParam, lParam):\n            done = False\n            if msg == WM_TABLET_QUERYSYSTEMGESTURE:\n                return QUERYSYSTEMGESTURE_WNDPROC\n\n            if msg == WM_TOUCH:\n                done = self._touch_handler(msg, wParam, lParam)\n\n            if msg >= WM_MOUSEMOVE and msg <= WM_MOUSELAST:\n                done = self._mouse_handler(msg, wParam, lParam)\n\n            if not done:\n                return windll.user32.CallWindowProcW(self.old_windProc,\n                                                     hwnd, msg, wParam,\n                                                     lParam)\n            return 1\n\n        # this on pushes WM_TOUCH messages onto our event stack\n        def _touch_handler(self, msg, wParam, lParam):\n            touches = (TOUCHINPUT * wParam)()\n            windll.user32.GetTouchInputInfo(HANDLE(lParam),\n                                            wParam,\n                                            touches,\n                                            sizeof(TOUCHINPUT))\n            for i in range(wParam):\n                self.touch_events.appendleft(touches[i])\n            return True\n\n        # filter fake mouse events, because touch and stylus\n        # also make mouse events\n        def _mouse_handler(self, msg, wparam, lParam):\n            info = windll.user32.GetMessageExtraInfo()\n            # its a touch or a pen\n            if (info & PEN_OR_TOUCH_MASK) == PEN_OR_TOUCH_SIGNATURE:\n                if info & PEN_EVENT_TOUCH_MASK:\n                    return True\n\n    MotionEventFactory.register('wm_touch', WM_MotionEventProvider)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/recorder.py",
    "content": "'''\nInput recorder\n==============\n\n.. versionadded:: 1.1.0\n\n.. warning::\n\n    This part of Kivy is still experimental and this API is subject to\n    change in a future version.\n\nThis is a class that can record and replay some input events. This can\nbe used for test cases, screen savers etc.\n\nOnce activated, the recorder will listen for any input event and save its\nproperties in a file with the delta time. Later, you can play the input\nfile: it will generate fake touch events with the saved properties and\ndispatch it to the event loop.\n\nBy default, only the position is saved ('pos' profile and 'sx', 'sy',\nattributes). Change it only if you understand how input handling works.\n\nRecording events\n----------------\n\nThe best way is to use the \"recorder\" module. Check the :doc:`api-kivy.modules`\ndocumentation to see how to activate a module.\n\nOnce activated, you can press F8 to start the recording. By default,\nevents will be written to `<currentpath>/recorder.kvi`. When you want to\nstop recording, press F8 again.\n\nYou can replay the file by pressing F7.\n\nCheck the :doc:`api-kivy.modules.recorder` module for more information.\n\nManual play\n-----------\n\nYou can manually open a recorder file, and play it by doing::\n\n    from kivy.input.recorder import Recorder\n\n    rec = Recorder(filename='myrecorder.kvi')\n    rec.play = True\n\nIf you want to loop over that file, you can do::\n\n\n    from kivy.input.recorder import Recorder\n\n    def recorder_loop(instance, value):\n        if value is False:\n            instance.play = True\n\n    rec = Recorder(filename='myrecorder.kvi')\n    rec.bind(play=recorder_loop)\n    rec.play = True\n\nRecording more attributes\n-------------------------\n\nYou can extend the attributes to save on one condition: attributes values must\nbe simple values, not instances of complex classes.\n\nLet's say you want to save the angle and pressure of the touch, if available::\n\n    from kivy.input.recorder import Recorder\n\n    rec = Recorder(filename='myrecorder.kvi',\n        record_attrs=['is_touch', 'sx', 'sy', 'angle', 'pressure'],\n        record_profile_mask=['pos', 'angle', 'pressure'])\n    rec.record = True\n\nOr with modules variables::\n\n    $ python main.py -m recorder,attrs=is_touch:sx:sy:angle:pressure,\\\n            profile_mask=pos:angle:pressure\n\nKnown limitations\n-----------------\n\n  - Unable to save attributes with instances of complex classes.\n  - Values that represent time will not be adjusted.\n  - Can replay only complete records. If a begin/update/end event is missing,\n    this could lead to ghost touches.\n  - Stopping the replay before the end can lead to ghost touches.\n\n'''\n\n__all__ = ('Recorder', )\n\nfrom os.path import exists\nfrom time import time\nfrom kivy.event import EventDispatcher\nfrom kivy.properties import ObjectProperty, BooleanProperty, StringProperty, \\\n    NumericProperty, ListProperty\nfrom kivy.input.motionevent import MotionEvent\nfrom kivy.base import EventLoop\nfrom kivy.logger import Logger\nfrom ast import literal_eval\nfrom functools import partial\n\n\nclass RecorderMotionEvent(MotionEvent):\n\n    def depack(self, args):\n        for key, value in list(args.items()):\n            setattr(self, key, value)\n        super(RecorderMotionEvent, self).depack(args)\n\n\nclass Recorder(EventDispatcher):\n    '''Recorder class. Please check module documentation for more information.\n    '''\n\n    window = ObjectProperty(None)\n    '''Window instance to attach the recorder. If None, it will use the\n    default instance.\n\n    :attr:`window` is a :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    counter = NumericProperty(0)\n    '''Number of events recorded in the last session.\n\n    :attr:`counter` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 0, read-only.\n    '''\n\n    play = BooleanProperty(False)\n    '''Boolean to start/stop the replay of the current file (if it exists).\n\n    :attr:`play` is a :class:`~kivy.properties.BooleanProperty` and defaults to\n    False.\n    '''\n\n    record = BooleanProperty(False)\n    '''Boolean to start/stop the recording of input events.\n\n    :attr:`record` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    filename = StringProperty('recorder.kvi')\n    '''Filename to save the output of the recorder.\n\n    :attr:`filename` is a :class:`~kivy.properties.StringProperty` and defaults\n    to 'recorder.kvi'.\n    '''\n\n    record_attrs = ListProperty(['is_touch', 'sx', 'sy'])\n    '''Attributes to record from the motion event.\n\n    :attr:`record_attrs` is a :class:`~kivy.properties.ListProperty` and\n    defaults to ['is_touch', 'sx', 'sy'].\n    '''\n\n    record_profile_mask = ListProperty(['pos'])\n    '''Profile to save in the fake motion event when replayed.\n\n    :attr:`record_profile_mask` is a :class:`~kivy.properties.ListProperty` and\n    defaults to ['pos'].\n    '''\n\n    # internals\n    record_fd = ObjectProperty(None)\n    record_time = NumericProperty(0.)\n\n    def __init__(self, **kwargs):\n        super(Recorder, self).__init__(**kwargs)\n        if self.window is None:\n            # manually set the current window\n            from kivy.core.window import Window\n            self.window = Window\n        self.window.bind(\n            on_motion=self.on_motion,\n            on_key_up=partial(self.on_keyboard, 'keyup'),\n            on_key_down=partial(self.on_keyboard, 'keydown'),\n            on_keyboard=partial(self.on_keyboard, 'keyboard'))\n\n    def on_motion(self, window, etype, motionevent):\n        if not self.record:\n            return\n\n        args = dict((arg, getattr(motionevent, arg))\n                    for arg in self.record_attrs if hasattr(motionevent, arg))\n\n        args['profile'] = [x for x in motionevent.profile if x in\n                           self.record_profile_mask]\n        self.record_fd.write('%r\\n' % (\n            (time() - self.record_time, etype, motionevent.uid, args), ))\n        self.counter += 1\n\n    def on_keyboard(self, etype, window, key, *args, **kwargs):\n        if not self.record:\n            return\n        self.record_fd.write('%r\\n' % (\n            (time() - self.record_time, etype, 0, {\n                'key': key,\n                'scancode': kwargs.get('scancode'),\n                'codepoint': kwargs.get('codepoint', kwargs.get('unicode')),\n                'modifier': kwargs.get('modifier'),\n                'is_touch': False}), ))\n        self.counter += 1\n\n    def release(self):\n        self.window.unbind(\n            on_motion=self.on_motion,\n            on_key_up=self.on_keyboard,\n            on_key_down=self.on_keyboard)\n\n    def on_record(self, instance, value):\n        if value:\n            # generate a record filename\n            self.counter = 0\n            self.record_time = time()\n            self.record_fd = open(self.filename, 'w')\n            self.record_fd.write('#RECORDER1.0\\n')\n            Logger.info('Recorder: Recording inputs to %r' % self.filename)\n        else:\n            self.record_fd.close()\n            Logger.info('Recorder: Recorded %d events in %r' % (self.counter,\n                                                                self.filename))\n\n    # needed for acting as an input provider\n    def stop(self):\n        pass\n\n    def start(self):\n        pass\n\n    def on_play(self, instance, value):\n        if not value:\n            Logger.info('Recorder: Stop playing %r' % self.filename)\n            EventLoop.remove_input_provider(self)\n            return\n        if not exists(self.filename):\n            Logger.error('Recorder: Unable to found %r file, play aborted.' % (\n                self.filename))\n            return\n\n        with open(self.filename, 'r') as fd:\n            data = fd.read().splitlines()\n\n        if len(data) < 2:\n            Logger.error('Recorder: Unable to play %r, file truncated.' % (\n                self.filename))\n            return\n\n        if data[0] != '#RECORDER1.0':\n            Logger.error('Recorder: Unable to play %r, invalid header.' % (\n                self.filename))\n            return\n\n        # decompile data\n        self.play_data = [literal_eval(x) for x in data[1:]]\n        self.play_time = time()\n        self.play_me = {}\n        Logger.info('Recorder: Start playing %d events from %r' %\n                    (len(self.play_data), self.filename))\n        EventLoop.add_input_provider(self)\n\n    def update(self, dispatch_fn):\n        if not self.play_data:\n            Logger.info('Recorder: Playing finished.')\n            self.play = False\n\n        dt = time() - self.play_time\n        while self.play_data:\n            event = self.play_data[0]\n            assert(len(event) == 4)\n            if event[0] > dt:\n                return\n\n            me = None\n            etype, uid, args = event[1:]\n            if etype == 'begin':\n                me = RecorderMotionEvent('recorder', uid, args)\n                self.play_me[uid] = me\n            elif etype == 'update':\n                me = self.play_me[uid]\n                me.depack(args)\n            elif etype == 'end':\n                me = self.play_me.pop(uid)\n                me.depack(args)\n            elif etype == 'keydown':\n                self.window.dispatch(\n                    'on_key_down',\n                    args['key'],\n                    args['scancode'],\n                    args['codepoint'],\n                    args['modifier'])\n            elif etype == 'keyup':\n                self.window.dispatch(\n                    'on_key_up',\n                    args['key'],\n                    args['scancode'],\n                    args['codepoint'],\n                    args['modifier'])\n            elif etype == 'keyboard':\n                self.window.dispatch(\n                    'on_keyboard',\n                    args['key'],\n                    args['scancode'],\n                    args['codepoint'],\n                    args['modifier'])\n\n            if me:\n                dispatch_fn(etype, me)\n\n            self.play_data.pop(0)\n\n\ndef start(win, ctx):\n    ctx.recorder = Recorder(window=win)\n\n\ndef stop(win, ctx):\n    if hasattr(ctx, 'recorder'):\n        ctx.recorder.release()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/input/shape.py",
    "content": "'''\nMotion Event Shape\n==================\n\nRepresent the shape of the :class:`~kivy.input.motionevent.MotionEvent`\n'''\n\n__all__ = ('Shape', 'ShapeRect')\n\n\nclass Shape(object):\n    '''Abstract class for all implementations of a shape'''\n    pass\n\n\nclass ShapeRect(Shape):\n    '''Class for the representation of a rectangle.'''\n    __slots__ = ('width', 'height')\n\n    def __init__(self):\n        super(ShapeRect, self).__init__()\n\n        #: Width fo the rect\n        self.width = 0\n\n        #: Height of the rect\n        self.height = 0\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/interactive.py",
    "content": "'''\nInteractive launcher\n====================\n\n.. versionadded:: 1.3.0\n\nThe :class:`InteractiveLauncher` provides a user-friendly python shell\ninterface to an :class:`App` so that it can be prototyped and debugged\ninteractively.\n\n.. note::\n\n    The Kivy API intends for some functions to only be run once or before the\n    main EventLoop has started. Methods that can normally be called during the\n    course of an application will work as intended, but specifically overriding\n    methods such as :meth:`on_touch` dynamically leads to trouble.\n\nCreating an InteractiveLauncher\n-------------------------------\n\nTake your existing subclass of :class:`App` (this can be production code) and\npass an instance to the :class:`InteractiveLauncher` constructor.::\n\n    from kivy.interactive import InteractiveLauncher\n    from kivy.app import App\n    from kivy.uix.button import Button\n\n    class MyApp(App):\n        def build(self):\n            return Button(test='Hello Shell')\n\n    launcher = InteractiveLauncher(MyApp())\n    launcher.run()\n\nAfter pressing *enter*, the script will return. This allows the interpreter to\ncontinue running. Inspection or modification of the :class:`App` can be done\nsafely through the InteractiveLauncher instance or the provided\n:class:`SafeMembrane` class instances.\n\n.. note::\n\n    If you want to test this example, start Python without any file to have\n    already an interpreter, and copy/paste all the lines. You'll still have the\n    interpreter at the end + the kivy application running.\n\nInteractive Development\n-----------------------\n\nIPython provides a fast way to learn the Kivy API. The :class:`App` instance\nand all of it's attributes, including methods and the entire widget tree,\ncan be quickly listed by using the '.' operator and pressing 'tab'. Try this\ncode in an Ipython shell.::\n\n    from kivy.interactive import InteractiveLauncher\n    from kivy.app import App\n    from kivy.uix.widget import Widget\n    from kivy.graphics import Color, Ellipse\n\n    class MyPaintWidget(Widget):\n        def on_touch_down(self, touch):\n            with self.canvas:\n                Color(1, 1, 0)\n                d = 30.\n                Ellipse(pos=(touch.x - d/2, touch.y - d/2), size=(d, d))\n\n\n    class TestApp(App):\n        def build(self):\n            return Widget()\n\n\n    i = InteractiveLauncher(TestApp())\n    i.run()\n    i.       # press 'tab' to list attributes of the app\n    i.root.  # press 'tab' to list attributes of the root widget\n\n    # App is boring. Attach a new widget!\n    i.root.add_widget(MyPaintWidget())\n\n    i.safeIn()\n    # The application is now blocked.\n    # Click on the screen several times.\n    i.safeOut()\n    # The clicks will show up now\n\n    # Erase artwork and start over\n    i.root.canvas.clear()\n\n.. note::\n\n    All of the proxies used in the module store their referent in the\n    :attr:`_ref` attribute, which can be accessed directly if needed, such as\n    for getting doc strings. :func:`help` and :func:`type` will access the\n    proxy, not its referent.\n\nDirectly Pausing the Application\n--------------------------------\n\nBoth the :class:`InteractiveLauncher` and :class:`SafeMembrane` hold internal\nreferences to the :class:`EventLoop`'s 'safe' and 'confirmed'\n:class:`threading.Event` objects. You can use their safing methods to control\nthe application manually.\n\n:meth:`SafeMembrane.safeIn` will cause the application to pause and\n:meth:`SafeMembrane.safeOut` will allow a paused application\nto continue running. This is potentially useful for scripting actions into\nfunctions that need the screen to update etc.\n\n.. note::\n\n    The pausing is implemented via the\n    :class:`Clocks' <kivy.clock.Clock>`\n    :meth:`~kivy.clock.ClockBase.schedule_once` method\n    and occurs before the start of each frame.\n\nAdding Attributes Dynamically\n-----------------------------\n\n.. note::\n\n    This module uses threading and object proxies to encapsulate the running\n    :class:`App`. Deadlocks and memory corruption can occur if making direct\n    references inside the thread without going through the provided proxy(s).\n\nThe :class:`InteractiveLauncher` can have attributes added to it exactly like a\nnormal object and if these were created from outside the membrane, they will\nnot be threadsafe because the external references to them in the python\ninterpreter do not go through InteractiveLauncher's membrane behavior,\ninherited from :class:`SafeMembrane`.\n\nTo threadsafe these external references, simply assign them to\n:class:`SafeMembrane` instances of themselves like so::\n\n    from kivy.interactive import SafeMembrane\n\n    interactiveLauncher.attribute = myNewObject\n    # myNewObject is unsafe\n    myNewObject = SafeMembrane(myNewObject)\n    # myNewObject is now safe. Call at will.\n    myNewObject.method()\n\nTODO\n====\n\nUnit tests, examples, and a better explanation of which methods are safe in a\nrunning application would be nice. All three would be excellent.\n\nCould be re-written with a context-manager style i.e.::\n\n    with safe:\n        foo()\n\nAny use cases besides compacting code?\n\n'''\n\n__all__ = ('SafeMembrane', 'InteractiveLauncher')\n\nfrom kivy.app import App\nfrom kivy.base import EventLoop\nfrom kivy.clock import Clock\nfrom threading import Thread, Event\n\n\ndef safeWait(dt):\n    EventLoop.confirmed.set()\n    EventLoop.safe.wait()\n    EventLoop.confirmed.clear()\n\n\ndef unwrap(ob):\n    while type(ob) == SafeMembrane:\n        ob = ob._ref\n    return ob\n\n\nclass SafeMembrane(object):\n    '''\n    This help is for a proxy object. Did you want help on the proxy's referent\n    instead? Try using help(<instance>._ref)\n\n    The SafeMembrane is a threadsafe proxy that also returns attributes as new\n    thread-safe objects\n    and makes thread-safe method calls, preventing thread-unsafe objects\n    from leaking into the user's environment.\n    '''\n\n    __slots__ = ('_ref', 'safe', 'confirmed')\n\n    def __init__(self, ob, *args, **kwargs):\n        self.confirmed = EventLoop.confirmed\n        self.safe = EventLoop.safe\n        self._ref = ob\n\n    def safeIn(self):\n        \"\"\"Provides a thread-safe entry point for interactive launching.\"\"\"\n        self.safe.clear()\n        Clock.schedule_once(safeWait, -1)\n        self.confirmed.wait()\n\n    def safeOut(self):\n        \"\"\"Provides a thread-safe exit point for interactive launching.\"\"\"\n        self.safe.set()\n\n    def isMethod(self, fn):\n        return type(fn) is type(self.isMethod)\n\n    # Everything from this point on is just a series of thread-safing proxy\n    # methods that make calls against _ref and threadsafe whenever data will be\n    # written to or if a method will be called. SafeMembrane instances should\n    # be unwrapped whenever passing them into the thread\n    #use type() to determine if an object is a SafeMembrane while debugging\n    def __repr__(self):\n        return self._ref.__repr__()\n\n    def __call__(self, *args, **kw):\n        self.safeIn()\n        args = list(map(unwrap, args))\n        for k in list(kw.keys()):\n            kw[k] = unwrap(kw[k])\n        r = self._ref(*args, **kw)\n        self.safeOut()\n        if r is not None:\n            return SafeMembrane(r)\n\n    def __getattribute__(self, attr, oga=object.__getattribute__):\n        if attr.startswith('__') or attr == '_ref':\n            subject = oga(self, '_ref')\n            if attr == '_ref':\n                return subject\n            return getattr(subject, attr)\n        return oga(self, attr)\n\n    def __getattr__(self, attr, oga=object.__getattribute__):\n        r = getattr(oga(self, '_ref'), attr)\n        return SafeMembrane(r)\n\n    def __setattr__(self, attr, val, osa=object.__setattr__):\n        if (attr == '_ref'\n                or hasattr(type(self), attr) and not attr.startswith('__')):\n            osa(self, attr, val)\n        else:\n            self.safeIn()\n            val = unwrap(val)\n            setattr(self._ref, attr, val)\n            self.safeOut()\n\n    def __delattr__(self, attr, oda=object.__delattr__):\n        self.safeIn()\n        delattr(self._ref, attr)\n        self.safeOut()\n\n    def __bool__(self):\n        return bool(self._ref)\n\n    def __getitem__(self, arg):\n        return SafeMembrane(self._ref[arg])\n\n    def __setitem__(self, arg, val):\n        self.safeIn()\n        val = unwrap(val)\n        self._ref[arg] = val\n        self.safeOut()\n\n    def __delitem__(self, arg):\n        self.safeIn()\n        del self._ref[arg]\n        self.safeOut()\n\n    def __getslice__(self, i, j):\n        return SafeMembrane(self._ref[i:j])\n\n    def __setslice__(self, i, j, val):\n        self.safeIn()\n        val = unwrap(val)\n        self._ref[i:j] = val\n        self.safeOut()\n\n    def __delslice__(self, i, j):\n        self.safeIn()\n        del self._ref[i:j]\n        self.safeOut()\n\n    def __enter__(self, *args, **kwargs):\n        self.safeIn()\n        self._ref.__enter__(*args, **kwargs)\n\n    def __exit__(self, *args, **kwargs):\n        self._ref.__exit__(*args, **kwargs)\n        self.safeOut()\n\n\nclass InteractiveLauncher(SafeMembrane):\n    '''\n    Proxy to an application instance that launches it in a thread and\n    then returns and acts as a proxy to the application in the thread.\n    '''\n\n    __slots__ = ('_ref', 'safe', 'confirmed', 'thread', 'app')\n\n    def __init__(self, app=None, *args, **kwargs):\n        if app is None:\n            app = App()\n        EventLoop.safe = Event()\n        self.safe = EventLoop.safe\n        self.safe.set()\n        EventLoop.confirmed = Event()\n        self.confirmed = EventLoop.confirmed\n        self.app = app\n\n        def startApp(app=app, *args, **kwargs):\n            app.run(*args, **kwargs)\n\n        self.thread = Thread(target=startApp, *args, **kwargs)\n\n    def run(self):\n        self.thread.start()\n        #Proxy behavior starts after this is set. Before this point, attaching\n        #widgets etc can only be done through the Launcher's app attribute\n        self._ref = self.app\n\n    def stop(self):\n        EventLoop.quit = True\n        self.thread.join()\n\n    #Act like the app instance even before _ref is set\n    def __repr__(self):\n        return self.app.__repr__()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/lang.py",
    "content": "'''Kivy Language\n=============\n\nThe Kivy language is a language dedicated to describing user interface and\ninteractions. You could compare this language to Qt's QML\n(http://qt.nokia.com), but we included new concepts such as rule definitions\n(which are somewhat akin to what you may know from CSS), templating and so on.\n\n.. versionchanged:: 1.7.0\n\n    The Builder doesn't execute canvas expressions in realtime anymore. It will\n    pack all the expressions that need to be executed first and execute them\n    after dispatching input, just before drawing the frame. If you want to\n    force the execution of canvas drawing, just call\n    :meth:`Builder.sync <BuilderBase.sync>`.\n\n    An experimental profiling tool for the kv lang is also included. You can\n    activate it by setting the environment variable `KIVY_PROFILE_LANG=1`.\n    It will then generate an html file named `builder_stats.html`.\n\nOverview\n--------\n\nThe language consists of several constructs that you can use:\n\n    Rules\n        A rule is similar to a CSS rule. A rule applies to specific widgets (or\n        classes thereof) in your widget tree and modifies them in a\n        certain way.\n        You can use rules to specify interactive behaviour or use them to add\n        graphical representations of the widgets they apply to.\n        You can target a specific class of widgets (similar to the CSS\n        concept of a *class*) by using the ``cls`` attribute (e.g.\n        ``cls=MyTestWidget``).\n\n    A Root Widget\n        You can use the language to create your entire user interface.\n        A kv file must contain only one root widget at most.\n\n    Dynamic Classes\n        *(introduced in version 1.7.0)*\n        Dynamic classes let you create new widgets and rules on-the-fly,\n        without any Python declaration.\n\n    Templates (deprecated)\n        *(introduced in version 1.0.5, deprecated from version 1.7.0)*\n        Templates were used to populate parts of an application, such as\n        styling the content of a list (e.g. icon on the left, text on the\n        right). They are now deprecated by dynamic classes.\n\n\nSyntax of a kv File\n-------------------\n\n.. highlight:: kv\n\nA Kivy language file must have ``.kv`` as filename extension.\n\nThe content of the file should always start with the Kivy header, where\n`version` must be replaced with the Kivy language version you're using.\nFor now, use 1.0::\n\n    #:kivy `1.0`\n\n    # content here\n\nThe `content` can contain rule definitions, a root widget, dynamic class\ndefinitions and templates::\n\n    # Syntax of a rule definition. Note that several Rules can share the same\n    # definition (as in CSS). Note the braces: they are part of the definition.\n    <Rule1,Rule2>:\n        # .. definitions ..\n\n    <Rule3>:\n        # .. definitions ..\n\n    # Syntax for creating a root widget\n    RootClassName:\n        # .. definitions ..\n\n    # Syntax for creating a dynamic class\n    <NewWidget@BaseClass>:\n        # .. definitions ..\n\n    # Syntax for create a template\n    [TemplateName@BaseClass1,BaseClass2]:\n        # .. definitions ..\n\nRegardless of whether it's a rule, root widget, dynamic class or\ntemplate you're defining, the definition should look like this::\n\n    # With the braces it's a rule. Without them, it's a root widget.\n    <ClassName>:\n        prop1: value1\n        prop2: value2\n\n        canvas:\n            CanvasInstruction1:\n                canvasprop1: value1\n            CanvasInstruction2:\n                canvasprop2: value2\n\n        AnotherClass:\n            prop3: value1\n\nHere `prop1` and `prop2` are the properties of `ClassName` and `prop3` is the\nproperty of `AnotherClass`. If the widget doesn't have a property with\nthe given name, an :class:`~kivy.properties.ObjectProperty` will be\nautomatically created and added to the widget.\n\n`AnotherClass` will be created and added as a child of the `ClassName`\ninstance.\n\n- The indentation is important and must be consistent. The spacing must be a\n  multiple of the number of spaces used on the first indented line. Spaces\n  are encouraged: mixing tabs and spaces is not recommended.\n- The value of a property must be given on a single line (for now at least).\n- The `canvas` property is special: you can put graphics instructions in it\n  to create a graphical representation of the current class.\n\n\nHere is a simple example of a kv file that contains a root widget::\n\n    #:kivy 1.0\n\n    Button:\n        text: 'Hello world'\n\n\n.. versionchanged:: 1.7.0\n\n    The indentation is not limited to 4 spaces anymore. The spacing must be a\n    multiple of the number of spaces used on the first indented line.\n\nBoth the :meth:`~BuilderBase.load_file` and the\n:meth:`~BuilderBase.load_string` methods\nreturn the root widget defined in your kv file/string. They will also add any\nclass and template definitions to the :class:`~kivy.factory.Factory` for later\nusage.\n\nValue Expressions, on_property Expressions, ids and Reserved Keywords\n---------------------------------------------------------------------\n\nWhen you specify a property's value, the value is evaluated as a Python\nexpression. This expression can be static or dynamic, which means that\nthe value can use the values of other properties using reserved keywords.\n\n    self\n        The keyword self references the \"current widget instance\"::\n\n            Button:\n                text: 'My state is %s' % self.state\n\n    root\n        This keyword is available only in rule definitions and represents the\n        root widget of the rule (the first instance of the rule)::\n\n            <MyWidget>:\n                custom: 'Hello world'\n                Button:\n                    text: root.custom\n\n    app\n        This keyword always refers to your app instance. It's equivalent\n        to a call to :meth:`kivy.app.App.get_running_app` in Python.::\n\n            Label:\n                text: app.name\n\n    args\n        This keyword is available in on_<action> callbacks. It refers to the\n        arguments passed to the callback.::\n\n            TextInput:\n                on_focus: self.insert_text(\"Focus\" if args[1] else \"No focus\")\n\nids\n~~~\n\nClass definitions may contain ids which can be used as a keywords:::\n\n    <MyWidget>:\n        Button:\n            id: btn1\n        Button:\n            text: 'The state of the other button is %s' % btn1.state\n\nPlease note that the `id` will not be available in the widget instance:\nit is used exclusively for external references. `id` is a weakref to the\nwidget, and not the widget itself. The widget itself can be accessed\nwith `id.__self__` (`btn1.__self__` in this case).\n\nWhen the kv file is processed, weakrefs to all the widgets tagged with ids are\nadded to the root widgets `ids` dictionary. In other words, following on from\nthe example above, the buttons state could also be accessed as follows:\n\n.. code-block:: python\n\n    widget = MyWidget()\n    state = widget.ids[\"btn1\"].state\n\n    # Or, as an alternative syntax,\n    state = widget.ids.btn1.state\n\nNote that the outermost widget applies the kv rules to all its inner widgets\nbefore any other rules are applied. This means if an inner widget contains ids,\nthese ids may not be available during the inner widget's `__init__` function.\n\nValid expressons\n~~~~~~~~~~~~~~~~\n\nThere are two places that accept python statments in a kv file:\nafter a property, which assigns to the property the result of the expression\n(such as the text of a button as shown above) and after a on_property, which\nexecutes the statement when the property is updated (such as on_state).\n\nIn the former case, the\n`expression <http://docs.python.org/2/reference/expressions.html>`_ can only\nspan a single line, cannot be extended to multiple lines using newline\nescaping, and must return a value. An example of a valid expression is\n``text: self.state and ('up' if self.state == 'normal' else 'down')``.\n\nIn the latter case, multiple single line statements are valid including\nmulti-line statements that escape their newline, as long as they don't\nadd an indentation level.\n\nExamples of valid statements are:\n\n.. code-block:: python\n\n    on_press: if self.state == 'normal': print('normal')\n    on_state:\n        if self.state == 'normal': print('normal')\n        else: print('down')\n        if self.state == 'normal': \\\\\n        print('multiline normal')\n        for i in range(10): print(i)\n        print([1,2,3,4,\n        5,6,7])\n\nAn example of a invalid statement:\n\n.. code-block:: python\n\n    on_state:\n        if self.state == 'normal':\n            print('normal')\n\nRelation Between Values and Properties\n--------------------------------------\n\nWhen you use the Kivy language, you might notice that we do some work\nbehind the scenes to automatically make things work properly. You should\nknow that :doc:`api-kivy.properties` implement the\n`Observer Design Pattern <http://en.wikipedia.org/wiki/Observer_pattern>`_.\nThat means that you can bind your own function to be\ncalled when the value of a property changes (i.e. you passively\n`observe` the property for potential changes).\n\nThe Kivy language detects properties in your `value` expression and will create\ncreate callbacks to automatically update the property via your expression when\nchanges occur.\n\nHere's a simple example that demonstrates this behaviour::\n\n    Button:\n        text: str(self.state)\n\nIn this example, the parser detects that `self.state` is a dynamic value (a\nproperty). The :attr:`~kivy.uix.button.Button.state` property of the button\ncan change at any moment (when the user touches it).\nWe now want this button to display its own state as text, even as the state\nchanges. To do this, we use the state property of the Button and use it in the\nvalue expression for the button's `text` property, which controls what text is\ndisplayed on the button (We also convert the state to a string representation).\nNow, whenever the button state changes, the text property will be updated\nautomatically.\n\nRemember: The value is a python expression! That means that you can do\nsomething more interesting like::\n\n    Button:\n        text: 'Plop world' if self.state == 'normal' else 'Release me!'\n\nThe Button text changes with the state of the button. By default, the button\ntext will be 'Plop world', but when the button is being pressed, the text will\nchange to 'Release me!'.\n\nMore precisely, the kivy language parser detects all substrings of the form\n`X.a.b` where `X` is `self` or `root` or `app` or a known id, and `a` and `b`\nare properties: it then adds the appropriate dependencies to cause the\nthe constraint to be reevaluated whenever something changes. For example,\nthis works exactly as expected::\n\n    <IndexedExample>:\n        beta: self.a.b[self.c.d]\n\nHowever, due to limitations in the parser which hopefully may be lifted in the\nfuture, the following doesn't work::\n\n    <BadExample>:\n        beta: self.a.b[self.c.d].e.f\n\nindeed the `.e.f` part is not recognized because it doesn't follow the expected\npattern, and so, does not result in an appropriate dependency being setup.\nInstead, an intermediate property should be introduced to allow the following\nconstraint::\n\n    <GoodExample>:\n        alpha: self.a.b[self.c.d]\n        beta: self.alpha.e.f\n\n\nGraphical Instructions\n----------------------\n\nThe graphical instructions are a special part of the Kivy language. They are\nhandled by the 'canvas' property definition::\n\n    Widget:\n        canvas:\n            Color:\n                rgb: (1, 1, 1)\n            Rectangle:\n                size: self.size\n                pos: self.pos\n\nAll the classes added inside the canvas property must be derived from the\n:class:`~kivy.graphics.Instruction` class. You cannot put any Widget class\ninside the canvas property (as that would not make sense because a\nwidget is not a graphics instruction).\n\nIf you want to do theming, you'll have the same question as in CSS: which rules\nhave been executed first? In our case, the rules are executed\nin processing order (i.e. top-down).\n\nIf you want to change how Buttons are rendered, you can create your own kv file\nand add something like this::\n\n    <Button>:\n        canvas:\n            Color:\n                rgb: (1, 0, 0)\n            Rectangle:\n                pos: self.pos\n                size: self.size\n            Rectangle:\n                pos: self.pos\n                size: self.texture_size\n                texture: self.texture\n\nThis will result in buttons having a red background with the label in the\nbottom left, in addition to all the preceding rules.\nYou can clear all the previous instructions by using the `Clear` command::\n\n    <Button>:\n        canvas:\n            Clear\n            Color:\n                rgb: (1, 0, 0)\n            Rectangle:\n                pos: self.pos\n                size: self.size\n            Rectangle:\n                pos: self.pos\n                size: self.texture_size\n                texture: self.texture\n\nThen, only your rules that follow the `Clear` command will be taken into\nconsideration.\n\n.. _dynamic_classes:\n\nDynamic classes\n---------------\n\nDynamic classes allow you to create new widgets on-the-fly, without any python\ndeclaration in the first place. The syntax of the dynamic classes is similar to\nthe Rules, but you need to specify the base classes you want to\nsubclass.\n\nThe syntax looks like:\n\n.. code-block:: kv\n\n    # Simple inheritance\n    <NewWidget@Button>:\n        # kv code here ...\n\n    # Multiple inheritance\n    <NewWidget@ButtonBehavior+Label>:\n        # kv code here ...\n\nThe `@` character is used to seperate your class name from the classes you want\nto subclass. The Python equivalent would have been:\n\n.. code-block:: python\n\n    # Simple inheritance\n    class NewWidget(Button):\n        pass\n\n    # Multiple inheritance\n    class NewWidget(ButtonBehavior, Label):\n        pass\n\nAny new properties, usually added in python code, should be declared\nfirst. If the property doesn't exist in the dynamic class, it will be\nautomatically created as an :class:`~kivy.properties.ObjectProperty`\n(pre 1.8.0) or as an appropriate typed property (from version\n1.8.0).\n\n.. versionchanged:: 1.8.0\n\n    If the property value is an expression that can be evaluated right away (no\n    external binding), then the value will be used as default value of the\n    property, and the type of the value will be used for the specialization of\n    the Property class. In other terms: if you declare `hello: \"world\"`, a new\n    :class:`~kivy.properties.StringProperty` will be instantiated, with the\n    default value `\"world\"`. Lists, tuples, dictionaries and strings are\n    supported.\n\nLet's illustrate the usage of these dynamic classes with an\nimplementation of a basic Image button. We could derive our classes from\nthe Button and just add a property for the image filename:\n\n.. code-block:: kv\n\n    <ImageButton@Button>:\n        source: None\n\n        Image:\n            source: root.source\n            pos: root.pos\n            size: root.size\n\n    # let's use the new classes in another rule:\n    <MainUI>:\n        BoxLayout:\n            ImageButton:\n                source: 'hello.png'\n                on_press: root.do_something()\n            ImageButton:\n                source: 'world.png'\n                on_press: root.do_something_else()\n\nIn Python, you can create an instance of the dynamic class as follows:\n\n.. code-block:: python\n\n    from kivy.factory import Factory\n    button_inst = Factory.ImageButton()\n\n.. note::\n\n    Using dynamic classes, a child class can be declared before it's parent.\n    This however, leads to the unintuitive situation where the parent\n    properties/methods override those of the child. Be careful if you choose\n    to do this.\n\n.. _template_usage:\n\nTemplates\n---------\n\n.. versionchanged:: 1.7.0\n\n    Template usage is now deprecated. Please use Dynamic classes instead.\n\nSyntax of templates\n~~~~~~~~~~~~~~~~~~~\n\nUsing a template in Kivy requires 2 things :\n\n    #. a context to pass for the context (will be ctx inside template).\n    #. a kv definition of the template.\n\nSyntax of a template:\n\n.. code-block:: kv\n\n    # With only one base class\n    [ClassName@BaseClass]:\n        # .. definitions ..\n\n    # With more than one base class\n    [ClassName@BaseClass1,BaseClass2]:\n        # .. definitions ..\n\nFor example, for a list, you'll need to create a entry with a image on\nthe left, and a label on the right. You can create a template for making\nthat definition easier to use.\nSo, we'll create a template that uses 2 entries in the context: an image\nfilename and a title:\n\n.. code-block:: kv\n\n    [IconItem@BoxLayout]:\n        Image:\n            source: ctx.image\n        Label:\n            text: ctx.title\n\nThen in Python, you can instantiate the template using:\n\n.. code-block:: python\n\n    from kivy.lang import Builder\n\n    # create a template with hello world + an image\n    # the context values should be passed as kwargs to the Builder.template\n    # function\n    icon1 = Builder.template('IconItem', title='Hello world',\n        image='myimage.png')\n\n    # create a second template with other information\n    ctx = {'title': 'Another hello world',\n           'image': 'myimage2.png'}\n    icon2 = Builder.template('IconItem', **ctx)\n    # and use icon1 and icon2 as other widget.\n\n\nTemplate example\n~~~~~~~~~~~~~~~~\n\nMost of time, when you are creating a screen in the kv lang, you use a lot of\nredefinitions. In our example, we'll create a Toolbar, based on a\nBoxLayout, and put in a few :class:`~kivy.uix.image.Image` widgets that\nwill react to the *on_touch_down* event.:\n\n.. code-block:: kv\n\n    <MyToolbar>:\n        BoxLayout:\n            Image:\n                source: 'data/text.png'\n                size: self.texture_size\n                size_hint: None, None\n                on_touch_down: self.collide_point(*args[1].pos) and\\\n root.create_text()\n\n            Image:\n                source: 'data/image.png'\n                size: self.texture_size\n                size_hint: None, None\n                on_touch_down: self.collide_point(*args[1].pos) and\\\n root.create_image()\n\n            Image:\n                source: 'data/video.png'\n                size: self.texture_size\n                size_hint: None, None\n                on_touch_down: self.collide_point(*args[1].pos) and\\\n root.create_video()\n\nWe can see that the size and size_hint attribute are exactly the same.\nMore than that, the callback in on_touch_down and the image are changing.\nTheses can be the variable part of the template that we can put into a context.\nLet's try to create a template for the Image:\n\n.. code-block:: kv\n\n    [ToolbarButton@Image]:\n\n        # This is the same as before\n        size: self.texture_size\n        size_hint: None, None\n\n        # Now, we are using the ctx for the variable part of the template\n        source: 'data/%s.png' % ctx.image\n        on_touch_down: self.collide_point(*args[1].pos) and ctx.callback()\n\nThe template can be used directly in the MyToolbar rule:\n\n.. code-block:: kv\n\n    <MyToolbar>:\n        BoxLayout:\n            ToolbarButton:\n                image: 'text'\n                callback: root.create_text\n            ToolbarButton:\n                image: 'image'\n                callback: root.create_image\n            ToolbarButton:\n                image: 'video'\n                callback: root.create_video\n\nThat's all :)\n\n\nTemplate limitations\n~~~~~~~~~~~~~~~~~~~~\n\nWhen you are creating a context:\n\n    #. you cannot use references other than \"root\":\n\n        .. code-block:: kv\n\n            <MyRule>:\n                Widget:\n                    id: mywidget\n                    value: 'bleh'\n                Template:\n                    ctxkey: mywidget.value # << fail, this references the id\n                    # mywidget\n\n    #. not all of the dynamic parts will be understood:\n\n        .. code-block:: kv\n\n            <MyRule>:\n                Template:\n                    ctxkey: 'value 1' if root.prop1 else 'value2' # << even if\n                    # root.prop1 is a property, if it changes value, ctxkey\n                    # will not be updated\n\nRedefining a widget's style\n---------------------------\n\nSometimes we would like to inherit from a widget in order to use its Python\nproperties without also using its .kv defined style. For example, we would\nlike to inherit from a Label, but we would also like to define our own\ncanvas instructions instead of automatically using the canvas instructions\ninherited from the Label. We can achieve this by prepending a dash (-) before\nthe class name in the .kv style definition.\n\nIn myapp.py:\n\n.. code-block:: python\n\n    class MyWidget(Label):\n        pass\n\nand in my.kv:\n\n.. code-block:: kv\n\n    <-MyWidget>:\n        canvas:\n            Color:\n                rgb: 1, 1, 1\n            Rectangle:\n                size: (32, 32)\n\nMyWidget will now have a Color and Rectangle instruction in its canvas\nwithout any of the instructions inherited from the Label.\n\nLang Directives\n---------------\n\nYou can use directives to add declarative commands, such as imports or constant\ndefinitions, to the lang files. Directives are added as comments in the\nfollowing format:\n\n.. code-block:: kv\n\n    #:<directivename> <options>\n\nimport <package>\n~~~~~~~~~~~~~~~~\n\n.. versionadded:: 1.0.5\n\nSyntax:\n\n.. code-block:: kv\n\n    #:import <alias> <package>\n\nYou can import a package by writing:\n\n.. code-block:: kv\n\n    #:import os os\n\n    <Rule>:\n        Button:\n            text: os.getcwd()\n\nOr more complex:\n\n.. code-block:: kv\n\n    #:import ut kivy.utils\n\n    <Rule>:\n        canvas:\n            Color:\n                rgba: ut.get_random_color()\n\n.. versionadded:: 1.0.7\n\nYou can directly import classes from a module:\n\n.. code-block:: kv\n\n    #: import Animation kivy.animation.Animation\n    <Rule>:\n        on_prop: Animation(x=.5).start(self)\n\nset <key> <expr>\n~~~~~~~~~~~~~~~~\n\n.. versionadded:: 1.0.6\n\nSyntax:\n\n.. code-block:: kv\n\n    #:set <key> <expr>\n\nSet a key that will be available anywhere in the kv. For example:\n\n.. code-block:: kv\n\n    #:set my_color (.4, .3, .4)\n    #:set my_color_hl (.5, .4, .5)\n\n    <Rule>:\n        state: 'normal'\n        canvas:\n            Color:\n                rgb: my_color if self.state == 'normal' else my_color_hl\n\ninclude <file>\n~~~~~~~~~~~~~~~~\n\n.. versionadded:: 1.9.0\n\nSyntax:\n\n.. code-block:: kv\n\n    #:include [force] <file>\n\nIncludes an external kivy file. This allows you to split complex\nwidgets into their own files. If the include is forced, the file\nwill first be unloaded and then reloaded again. For example:\n\n.. code-block:: kv\n\n    # Test.kv\n    #:include mycomponent.kv\n    #:include force mybutton.kv\n\n    <Rule>:\n        state: 'normal'\n        MyButton:\n        MyComponent:\n\n\n.. code-block:: kv\n\n    # mycomponent.kv\n    #:include mybutton.kv\n\n    <MyComponent>:\n        MyButton:\n\n.. code-block:: kv\n\n    # mybutton.kv\n\n    <MyButton>:\n        canvas:\n            Color:\n                rgb: (1.0, 0.0, 0.0)\n            Rectangle:\n                pos: self.pos\n                size: (self.size[0]/4, self.size[1]/4)\n\n'''\nimport os\n\n__all__ = ('Observable', 'Builder', 'BuilderBase', 'BuilderException', 'Parser',\n           'ParserException')\n\nimport codecs\nimport re\nimport sys\nimport traceback\nimport types\nfrom re import sub, findall\nfrom os import environ\nfrom os.path import join\nfrom copy import copy\nfrom types import CodeType\nfrom functools import partial\nfrom collections import OrderedDict, defaultdict\n\nfrom kivy.factory import Factory\nfrom kivy.logger import Logger\nfrom kivy.utils import QueryDict\nfrom kivy.cache import Cache\nfrom kivy import kivy_data_dir, require\nfrom kivy.compat import PY2, iteritems, iterkeys\nfrom kivy.context import register_context\nfrom kivy.resources import resource_find\nimport kivy.metrics as Metrics\nfrom kivy._event import Observable, EventDispatcher\n\n\ntrace = Logger.trace\nglobal_idmap = {}\n\n# late import\nInstruction = None\n\n# register cache for creating new classtype (template)\nCache.register('kv.lang')\n\n# all previously included files\n__KV_INCLUDES__ = []\n\n# precompile regexp expression\nlang_str = re.compile('([\\'\"][^\\'\"]*[\\'\"])')\nlang_key = re.compile('([a-zA-Z_]+)')\nlang_keyvalue = re.compile('([a-zA-Z_][a-zA-Z0-9_.]*\\.[a-zA-Z0-9_.]+)')\nlang_tr = re.compile('(_\\()')\n\n# class types to check with isinstance\nif PY2:\n    _cls_type = (type, types.ClassType)\nelse:\n    _cls_type = (type, )\n\n# all the widget handlers, used to correctly unbind all the callbacks then the\n# widget is deleted\n_handlers = defaultdict(list)\n\n\nclass ProxyApp(object):\n    # proxy app object\n    # taken from http://code.activestate.com/recipes/496741-object-proxying/\n\n    __slots__ = ['_obj']\n\n    def __init__(self):\n        object.__init__(self)\n        object.__setattr__(self, '_obj', None)\n\n    def _ensure_app(self):\n        app = object.__getattribute__(self, '_obj')\n        if app is None:\n            from kivy.app import App\n            app = App.get_running_app()\n            object.__setattr__(self, '_obj', app)\n            # Clear cached application instance, when it stops\n            app.bind(on_stop=lambda instance:\n                     object.__setattr__(self, '_obj', None))\n        return app\n\n    def __getattribute__(self, name):\n        object.__getattribute__(self, '_ensure_app')()\n        return getattr(object.__getattribute__(self, '_obj'), name)\n\n    def __delattr__(self, name):\n        object.__getattribute__(self, '_ensure_app')()\n        delattr(object.__getattribute__(self, '_obj'), name)\n\n    def __setattr__(self, name, value):\n        object.__getattribute__(self, '_ensure_app')()\n        setattr(object.__getattribute__(self, '_obj'), name, value)\n\n    def __bool__(self):\n        object.__getattribute__(self, '_ensure_app')()\n        return bool(object.__getattribute__(self, '_obj'))\n\n    def __str__(self):\n        object.__getattribute__(self, '_ensure_app')()\n        return str(object.__getattribute__(self, '_obj'))\n\n    def __repr__(self):\n        object.__getattribute__(self, '_ensure_app')()\n        return repr(object.__getattribute__(self, '_obj'))\n\n\nglobal_idmap['app'] = ProxyApp()\nglobal_idmap['pt'] = Metrics.pt\nglobal_idmap['inch'] = Metrics.inch\nglobal_idmap['cm'] = Metrics.cm\nglobal_idmap['mm'] = Metrics.mm\nglobal_idmap['dp'] = Metrics.dp\nglobal_idmap['sp'] = Metrics.sp\n\n\n# delayed calls are canvas expression triggered during an loop. It is one\n# directional linked list of args to call call_fn with. Each element is a list\n# whos last element points to the next list of args to execute when\n# Builder.sync is called.\n_delayed_start = None\n\n\nclass ParserException(Exception):\n    '''Exception raised when something wrong happened in a kv file.\n    '''\n\n    def __init__(self, context, line, message, cause=None):\n        self.filename = context.filename or '<inline>'\n        self.line = line\n        sourcecode = context.sourcecode\n        sc_start = max(0, line - 2)\n        sc_stop = min(len(sourcecode), line + 3)\n        sc = ['...']\n        for x in range(sc_start, sc_stop):\n            if x == line:\n                sc += ['>> %4d:%s' % (line + 1, sourcecode[line][1])]\n            else:\n                sc += ['   %4d:%s' % (x + 1, sourcecode[x][1])]\n        sc += ['...']\n        sc = '\\n'.join(sc)\n\n        message = 'Parser: File \"%s\", line %d:\\n%s\\n%s' % (\n            self.filename, self.line + 1, sc, message)\n        if cause:\n            message += '\\n' + ''.join(traceback.format_tb(cause))\n\n        super(ParserException, self).__init__(message)\n\n\nclass BuilderException(ParserException):\n    '''Exception raised when the Builder failed to apply a rule on a widget.\n    '''\n    pass\n\n\nclass ParserRuleProperty(object):\n    '''Represent a property inside a rule.\n    '''\n\n    __slots__ = ('ctx', 'line', 'name', 'value', 'co_value',\n                 'watched_keys', 'mode', 'count')\n\n    def __init__(self, ctx, line, name, value):\n        super(ParserRuleProperty, self).__init__()\n        #: Associated parser\n        self.ctx = ctx\n        #: Line of the rule\n        self.line = line\n        #: Name of the property\n        self.name = name\n        #: Value of the property\n        self.value = value\n        #: Compiled value\n        self.co_value = None\n        #: Compilation mode\n        self.mode = None\n        #: Watched keys\n        self.watched_keys = None\n        #: Stats\n        self.count = 0\n\n    def precompile(self):\n        name = self.name\n        value = self.value\n\n        # first, remove all the string from the value\n        tmp = sub(lang_str, '', self.value)\n\n        # detecting how to handle the value according to the key name\n        mode = self.mode\n        if self.mode is None:\n            self.mode = mode = 'exec' if name[:3] == 'on_' else 'eval'\n        if mode == 'eval':\n            # if we don't detect any string/key in it, we can eval and give the\n            # result\n            if re.search(lang_key, tmp) is None:\n                self.co_value = eval(value)\n                return\n\n        # ok, we can compile.\n        value = '\\n' * self.line + value\n        self.co_value = compile(value, self.ctx.filename or '<string>', mode)\n\n        # for exec mode, we don't need to watch any keys.\n        if mode == 'exec':\n            return\n\n        # now, detect obj.prop\n        # first, remove all the string from the value\n        tmp = sub(lang_str, '', value)\n        idx = tmp.find('#')\n        if idx != -1:\n            tmp = tmp[:idx]\n        # detect key.value inside value, and split them\n        wk = list(set(findall(lang_keyvalue, tmp)))\n        if len(wk):\n            self.watched_keys = [x.split('.') for x in wk]\n        if findall(lang_tr, tmp):\n            if self.watched_keys:\n                self.watched_keys += [['_']]\n            else:\n                self.watched_keys = [['_']]\n\n    def __repr__(self):\n        return '<ParserRuleProperty name=%r filename=%s:%d ' \\\n               'value=%r watched_keys=%r>' % (\n                   self.name, self.ctx.filename, self.line + 1,\n                   self.value, self.watched_keys)\n\n\nclass ParserRule(object):\n    '''Represents a rule, in terms of the Kivy internal language.\n    '''\n\n    __slots__ = ('ctx', 'line', 'name', 'children', 'id', 'properties',\n                 'canvas_before', 'canvas_root', 'canvas_after',\n                 'handlers', 'level', 'cache_marked', 'avoid_previous_rules')\n\n    def __init__(self, ctx, line, name, level):\n        super(ParserRule, self).__init__()\n        #: Level of the rule in the kv\n        self.level = level\n        #: Associated parser\n        self.ctx = ctx\n        #: Line of the rule\n        self.line = line\n        #: Name of the rule\n        self.name = name\n        #: List of children to create\n        self.children = []\n        #: Id given to the rule\n        self.id = None\n        #: Properties associated to the rule\n        self.properties = OrderedDict()\n        #: Canvas normal\n        self.canvas_root = None\n        #: Canvas before\n        self.canvas_before = None\n        #: Canvas after\n        self.canvas_after = None\n        #: Handlers associated to the rule\n        self.handlers = []\n        #: Properties cache list: mark which class have already been checked\n        self.cache_marked = []\n        #: Indicate if any previous rules should be avoided.\n        self.avoid_previous_rules = False\n\n        if level == 0:\n            self._detect_selectors()\n        else:\n            self._forbid_selectors()\n\n    def precompile(self):\n        for x in self.properties.values():\n            x.precompile()\n        for x in self.handlers:\n            x.precompile()\n        for x in self.children:\n            x.precompile()\n        if self.canvas_before:\n            self.canvas_before.precompile()\n        if self.canvas_root:\n            self.canvas_root.precompile()\n        if self.canvas_after:\n            self.canvas_after.precompile()\n\n    def create_missing(self, widget):\n        # check first if the widget class already been processed by this rule\n        cls = widget.__class__\n        if cls in self.cache_marked:\n            return\n        self.cache_marked.append(cls)\n        for name in self.properties:\n            if hasattr(widget, name):\n                continue\n            value = self.properties[name].co_value\n            if type(value) is CodeType:\n                value = None\n            widget.create_property(name, value)\n\n    def _forbid_selectors(self):\n        c = self.name[0]\n        if c == '<' or c == '[':\n            raise ParserException(\n                self.ctx, self.line,\n                'Selectors rules are allowed only at the first level')\n\n    def _detect_selectors(self):\n        c = self.name[0]\n        if c == '<':\n            self._build_rule()\n        elif c == '[':\n            self._build_template()\n        else:\n            if self.ctx.root is not None:\n                raise ParserException(\n                    self.ctx, self.line,\n                    'Only one root object is allowed by .kv')\n            self.ctx.root = self\n\n    def _build_rule(self):\n        name = self.name\n        if __debug__:\n            trace('Builder: build rule for %s' % name)\n        if name[0] != '<' or name[-1] != '>':\n            raise ParserException(self.ctx, self.line,\n                                  'Invalid rule (must be inside <>)')\n\n        # if the very first name start with a -, avoid previous rules\n        name = name[1:-1]\n        if name[:1] == '-':\n            self.avoid_previous_rules = True\n            name = name[1:]\n\n        rules = name.split(',')\n        for rule in rules:\n            crule = None\n\n            if not len(rule):\n                raise ParserException(self.ctx, self.line,\n                                      'Empty rule detected')\n\n            if '@' in rule:\n                # new class creation ?\n                # ensure the name is correctly written\n                rule, baseclasses = rule.split('@', 1)\n                if not re.match(lang_key, rule):\n                    raise ParserException(self.ctx, self.line,\n                                          'Invalid dynamic class name')\n\n                # save the name in the dynamic classes dict.\n                self.ctx.dynamic_classes[rule] = baseclasses\n                crule = ParserSelectorName(rule)\n\n            else:\n                # classical selectors.\n\n                if rule[0] == '.':\n                    crule = ParserSelectorClass(rule[1:])\n                elif rule[0] == '#':\n                    crule = ParserSelectorId(rule[1:])\n                else:\n                    crule = ParserSelectorName(rule)\n\n            self.ctx.rules.append((crule, self))\n\n    def _build_template(self):\n        name = self.name\n        if __debug__:\n            trace('Builder: build template for %s' % name)\n        if name[0] != '[' or name[-1] != ']':\n            raise ParserException(self.ctx, self.line,\n                                  'Invalid template (must be inside [])')\n        item_content = name[1:-1]\n        if not '@' in item_content:\n            raise ParserException(self.ctx, self.line,\n                                  'Invalid template name (missing @)')\n        template_name, template_root_cls = item_content.split('@')\n        self.ctx.templates.append((template_name, template_root_cls, self))\n\n    def __repr__(self):\n        return '<ParserRule name=%r>' % (self.name, )\n\n\nclass Parser(object):\n    '''Create a Parser object to parse a Kivy language file or Kivy content.\n    '''\n\n    PROP_ALLOWED = ('canvas.before', 'canvas.after')\n    CLASS_RANGE = list(range(ord('A'), ord('Z') + 1))\n    PROP_RANGE = (\n        list(range(ord('A'), ord('Z') + 1)) +\n        list(range(ord('a'), ord('z') + 1)) +\n        list(range(ord('0'), ord('9') + 1)) + [ord('_')])\n\n    __slots__ = ('rules', 'templates', 'root', 'sourcecode',\n                 'directives', 'filename', 'dynamic_classes')\n\n    def __init__(self, **kwargs):\n        super(Parser, self).__init__()\n        self.rules = []\n        self.templates = []\n        self.root = None\n        self.sourcecode = []\n        self.directives = []\n        self.dynamic_classes = {}\n        self.filename = kwargs.get('filename', None)\n        content = kwargs.get('content', None)\n        if content is None:\n            raise ValueError('No content passed')\n        self.parse(content)\n\n    def execute_directives(self):\n        global __KV_INCLUDES__\n        for ln, cmd in self.directives:\n            cmd = cmd.strip()\n            if __debug__:\n                trace('Parser: got directive <%s>' % cmd)\n            if cmd[:5] == 'kivy ':\n                version = cmd[5:].strip()\n                if len(version.split('.')) == 2:\n                    version += '.0'\n                require(version)\n            elif cmd[:4] == 'set ':\n                try:\n                    name, value = cmd[4:].strip().split(' ', 1)\n                except:\n                    Logger.exception('')\n                    raise ParserException(self, ln, 'Invalid directive syntax')\n                try:\n                    value = eval(value)\n                except:\n                    Logger.exception('')\n                    raise ParserException(self, ln, 'Invalid value')\n                global_idmap[name] = value\n            elif cmd[:8] == 'include ':\n                ref = cmd[8:].strip()\n                force_load = False\n\n                if ref[:6] == 'force ':\n                    ref = ref[6:].strip()\n                    force_load = True\n\n                if ref[-3:] != '.kv':\n                    Logger.warn('WARNING: {0} does not have a valid Kivy'\n                                'Language extension (.kv)'.format(ref))\n                    break\n                if ref in __KV_INCLUDES__:\n                    if not os.path.isfile(ref):\n                        raise ParserException(self, ln,\n                            'Invalid or unknown file: {0}'.format(ref))\n                    if not force_load:\n                        Logger.warn('WARNING: {0} has already been included!'\n                                    .format(ref))\n                        break\n                    else:\n                        Logger.debug('Reloading {0} because include was forced.'\n                                    .format(ref))\n                        Builder.unload_file(ref)\n                        Builder.load_file(ref)\n                        continue\n                Logger.debug('Including file: {0}'.format(0))\n                __KV_INCLUDES__.append(ref)\n                Builder.load_file(ref)\n            elif cmd[:7] == 'import ':\n                package = cmd[7:].strip()\n                l = package.split(' ')\n                if len(l) != 2:\n                    raise ParserException(self, ln, 'Invalid import syntax')\n                alias, package = l\n                try:\n                    if package not in sys.modules:\n                        try:\n                            mod = __import__(package)\n                        except ImportError:\n                            mod = __import__('.'.join(package.split('.')[:-1]))\n                        # resolve the whole thing\n                        for part in package.split('.')[1:]:\n                            mod = getattr(mod, part)\n                    else:\n                        mod = sys.modules[package]\n                    global_idmap[alias] = mod\n                except ImportError:\n                    Logger.exception('')\n                    raise ParserException(self, ln,\n                                          'Unable to import package %r' %\n                                          package)\n            else:\n                raise ParserException(self, ln, 'Unknown directive')\n\n    def parse(self, content):\n        '''Parse the contents of a Parser file and return a list\n        of root objects.\n        '''\n        # Read and parse the lines of the file\n        lines = content.splitlines()\n        if not lines:\n            return\n        num_lines = len(lines)\n        lines = list(zip(list(range(num_lines)), lines))\n        self.sourcecode = lines[:]\n\n        if __debug__:\n            trace('Parser: parsing %d lines' % num_lines)\n\n        # Strip all comments\n        self.strip_comments(lines)\n\n        # Execute directives\n        self.execute_directives()\n\n        # Get object from the first level\n        objects, remaining_lines = self.parse_level(0, lines)\n\n        # Precompile rules tree\n        for rule in objects:\n            rule.precompile()\n\n        # After parsing, there should be no remaining lines\n        # or there's an error we did not catch earlier.\n        if remaining_lines:\n            ln, content = remaining_lines[0]\n            raise ParserException(self, ln, 'Invalid data (not parsed)')\n\n    def strip_comments(self, lines):\n        '''Remove all comments from all lines in-place.\n           Comments need to be on a single line and not at the end of a line.\n           i.e. a comment line's first non-whitespace character must be a #.\n        '''\n        # extract directives\n        for ln, line in lines[:]:\n            stripped = line.strip()\n            if stripped[:2] == '#:':\n                self.directives.append((ln, stripped[2:]))\n            if stripped[:1] == '#':\n                lines.remove((ln, line))\n            if not stripped:\n                lines.remove((ln, line))\n\n    def parse_level(self, level, lines, spaces=0):\n        '''Parse the current level (level * spaces) indentation.\n        '''\n        indent = spaces * level if spaces > 0 else 0\n        objects = []\n\n        current_object = None\n        current_property = None\n        current_propobject = None\n        i = 0\n        while i < len(lines):\n            line = lines[i]\n            ln, content = line\n\n            # Get the number of space\n            tmp = content.lstrip(' \\t')\n\n            # Replace any tab with 4 spaces\n            tmp = content[:len(content) - len(tmp)]\n            tmp = tmp.replace('\\t', '    ')\n\n            # first indent designates the indentation\n            if spaces == 0:\n                spaces = len(tmp)\n\n            count = len(tmp)\n\n            if spaces > 0 and count % spaces != 0:\n                raise ParserException(self, ln,\n                                      'Invalid indentation, '\n                                      'must be a multiple of '\n                                      '%s spaces' % spaces)\n            content = content.strip()\n            rlevel = count // spaces if spaces > 0 else 0\n\n            # Level finished\n            if count < indent:\n                return objects, lines[i - 1:]\n\n            # Current level, create an object\n            elif count == indent:\n                x = content.split(':', 1)\n                if not len(x[0]):\n                    raise ParserException(self, ln, 'Identifier missing')\n                if (len(x) == 2 and len(x[1]) and\n                    not x[1].lstrip().startswith('#')):\n                    raise ParserException(self, ln,\n                                          'Invalid data after declaration')\n                name = x[0]\n                # if it's not a root rule, then we got some restriction\n                # aka, a valid name, without point or everything else\n                if count != 0:\n                    if False in [ord(z) in Parser.PROP_RANGE for z in name]:\n                        raise ParserException(self, ln, 'Invalid class name')\n\n                current_object = ParserRule(self, ln, x[0], rlevel)\n                current_property = None\n                objects.append(current_object)\n\n            # Next level, is it a property or an object ?\n            elif count == indent + spaces:\n                x = content.split(':', 1)\n                if not len(x[0]):\n                    raise ParserException(self, ln, 'Identifier missing')\n\n                # It's a class, add to the current object as a children\n                current_property = None\n                name = x[0]\n                if ord(name[0]) in Parser.CLASS_RANGE or name[0] == '+':\n                    _objects, _lines = self.parse_level(\n                        level + 1, lines[i:], spaces)\n                    current_object.children = _objects\n                    lines = _lines\n                    i = 0\n\n                # It's a property\n                else:\n                    if name not in Parser.PROP_ALLOWED:\n                        if not all(ord(z) in Parser.PROP_RANGE for z in name):\n                            raise ParserException(self, ln,\n                                                  'Invalid property name')\n                    if len(x) == 1:\n                        raise ParserException(self, ln, 'Syntax error')\n                    value = x[1].strip()\n                    if name == 'id':\n                        if len(value) <= 0:\n                            raise ParserException(self, ln, 'Empty id')\n                        if value in ('self', 'root'):\n                            raise ParserException(\n                                self, ln,\n                                'Invalid id, cannot be \"self\" or \"root\"')\n                        current_object.id = value\n                    elif len(value):\n                        rule = ParserRuleProperty(self, ln, name, value)\n                        if name[:3] == 'on_':\n                            current_object.handlers.append(rule)\n                        else:\n                            current_object.properties[name] = rule\n                    else:\n                        current_property = name\n                        current_propobject = None\n\n            # Two more levels?\n            elif count == indent + 2 * spaces:\n                if current_property in (\n                        'canvas', 'canvas.after', 'canvas.before'):\n                    _objects, _lines = self.parse_level(\n                        level + 2, lines[i:], spaces)\n                    rl = ParserRule(self, ln, current_property, rlevel)\n                    rl.children = _objects\n                    if current_property == 'canvas':\n                        current_object.canvas_root = rl\n                    elif current_property == 'canvas.before':\n                        current_object.canvas_before = rl\n                    else:\n                        current_object.canvas_after = rl\n                    current_property = None\n                    lines = _lines\n                    i = 0\n                else:\n                    if current_propobject is None:\n                        current_propobject = ParserRuleProperty(\n                            self, ln, current_property, content)\n                        if current_property[:3] == 'on_':\n                            current_object.handlers.append(current_propobject)\n                        else:\n                            current_object.properties[current_property] = \\\n                                current_propobject\n                    else:\n                        current_propobject.value += '\\n' + content\n\n            # Too much indentation, invalid\n            else:\n                raise ParserException(self, ln,\n                                      'Invalid indentation (too many levels)')\n\n            # Check the next line\n            i += 1\n\n        return objects, []\n\n\ndef get_proxy(widget):\n    try:\n        return widget.proxy_ref\n    except AttributeError:\n        return widget\n\n\ndef custom_callback(__kvlang__, idmap, *largs, **kwargs):\n    idmap['args'] = largs\n    exec(__kvlang__.co_value, idmap)\n\n\ndef call_fn(args, instance, v):\n    element, key, value, rule, idmap = args\n    if __debug__:\n        trace('Builder: call_fn %s, key=%s, value=%r, %r' % (\n            element, key, value, rule.value))\n    rule.count += 1\n    e_value = eval(value, idmap)\n    if __debug__:\n        trace('Builder: call_fn => value=%r' % (e_value, ))\n    setattr(element, key, e_value)\n\n\ndef delayed_call_fn(args, instance, v):\n    # it's already on the list\n    if args[-1] is not None:\n        return\n\n    global _delayed_start\n    if _delayed_start is None:\n        _delayed_start = args\n        args[-1] = StopIteration\n    else:\n        args[-1] = _delayed_start\n        _delayed_start = args\n\n\ndef update_intermediates(base, keys, bound, s, fn, args, instance, value):\n    ''' Function that is called when an intermediate property is updated\n    and `rebind` of that property is True. In that case, we unbind\n    all bound funcs that were bound to attrs of the old value of the\n    property and rebind to the new value of the property.\n\n    For example, if the rule is `self.a.b.c.d`, then when b is changed, we\n    unbind from `b`, `c` and `d`, if they were bound before (they were not\n    None and `rebind` of the respective properties was True) and we rebind\n    to the new values of the attrs `b`, `c``, `d` that are not None and\n    `rebind` is True.\n\n    :Parameters:\n        `base`\n            A (proxied) ref to the base widget, `self` in the example\n            above.\n        `keys`\n            A list of the name off the attrs of `base` being watched. In\n            the example above it'd be `['a', 'b', 'c', 'd']`.\n        `bound`\n            A list 4-tuples, each tuple being (widget, attr, callback, uid)\n            representing callback functions bound to the attributed `attr`\n            of `widget`. `uid` is returned by `fast_bind` when binding.\n            The callback may be None, in which case the attr\n            was not bound, but is there to be able to walk the attr tree.\n            E.g. in the example above, if `b` was not an eventdispatcher,\n            `(_b_ref_, `c`, None)` would be added to the list so we can get\n            to `c` and `d`, which may be eventdispatchers and their attrs.\n        `s`\n            The index in `keys` of the of the attr that needs to be\n            updated. That is all the keys from `s` and further will be\n            rebound, since the `s` key was changed. In bound, the\n            corresponding index is `s - 1`. If `s` is None, we start from\n            1 (first attr).\n        `fn`\n            The function to be called args, `args` on bound callback.\n    '''\n    # first remove all the old bound functions from `s` and down.\n    for f, k, fun, uid in bound[s:]:\n        if fun is None:\n            continue\n        try:\n            f.unbind_uid(k, uid)\n        except ReferenceError:\n            pass\n    del bound[s:]\n\n    # find the first attr from which we need to start rebinding.\n    f = getattr(*bound[-1][:2])\n    if f is None:\n        fn(args, None, None)\n        return\n    s += 1\n    append = bound.append\n\n    # bind all attrs, except last to update_intermediates\n    for val in keys[s:-1]:\n        # if we need to dynamically rebind, bindm otherwise just\n        # add the attr to the list\n        if isinstance(f, (EventDispatcher, Observable)):\n            prop = f.property(val, True)\n            if prop is not None and getattr(prop, 'rebind', False):\n                # fast_bind should not dispatch, otherwise\n                # update_intermediates might be called in the middle\n                # here messing things up\n                uid = f.fast_bind(\n                    val, update_intermediates, base, keys, bound, s, fn, args)\n                append([f.proxy_ref, val, update_intermediates, uid])\n            else:\n                append([f.proxy_ref, val, None, None])\n        else:\n            append([getattr(f, 'proxy_ref', f), val, None, None])\n\n        f = getattr(f, val, None)\n        if f is None:\n            break\n        s += 1\n\n    # for the last attr we bind directly to the setting function,\n    # because that attr sets the value of the rule.\n    if isinstance(f, (EventDispatcher, Observable)):\n        uid = f.fast_bind(keys[-1], fn, args)\n        if uid:\n            append([f.proxy_ref, keys[-1], fn, uid])\n    # when we rebind we have to update the\n    # rule with the most recent value, otherwise, the value might be wrong\n    # and wouldn't be updated since we might not have tracked it before.\n    # This only happens for a callback when rebind was True for the prop.\n    fn(args, None, None)\n\n\ndef create_handler(iself, element, key, value, rule, idmap, delayed=False):\n    idmap = copy(idmap)\n    idmap.update(global_idmap)\n    idmap['self'] = iself.proxy_ref\n    handler_append = _handlers[iself.uid].append\n\n    # we need a hash for when delayed, so we don't execute duplicate canvas\n    # callbacks from the same handler during a sync op\n    if delayed:\n        fn = delayed_call_fn\n        args = [element, key, value, rule, idmap, None]  # see _delayed_start\n    else:\n        fn = call_fn\n        args = (element, key, value, rule, idmap)\n\n    # bind every key.value\n    if rule.watched_keys is not None:\n        for keys in rule.watched_keys:\n            base = idmap.get(keys[0])\n            if base is None:\n                continue\n            f = base = getattr(base, 'proxy_ref', base)\n            bound = []\n            was_bound = False\n            append = bound.append\n\n            # bind all attrs, except last to update_intermediates\n            k = 1\n            for val in keys[1:-1]:\n                # if we need to dynamically rebind, bindm otherwise\n                # just add the attr to the list\n                if isinstance(f, (EventDispatcher, Observable)):\n                    prop = f.property(val, True)\n                    if prop is not None and getattr(prop, 'rebind', False):\n                        # fast_bind should not dispatch, otherwise\n                        # update_intermediates might be called in the middle\n                        # here messing things up\n                        uid = f.fast_bind(\n                            val, update_intermediates, base, keys, bound, k,\n                            fn, args)\n                        append([f.proxy_ref, val, update_intermediates, uid])\n                        was_bound = True\n                    else:\n                        append([f.proxy_ref, val, None, None])\n                elif not isinstance(f, _cls_type):\n                    append([getattr(f, 'proxy_ref', f), val, None, None])\n                else:\n                    append([f, val, None, None])\n                f = getattr(f, val, None)\n                if f is None:\n                    break\n                k += 1\n\n            # for the last attr we bind directly to the setting\n            # function, because that attr sets the value of the rule.\n            if isinstance(f, (EventDispatcher, Observable)):\n                uid = f.fast_bind(keys[-1], fn, args)  # f is not None\n                if uid:\n                    append([f.proxy_ref, keys[-1], fn, uid])\n                    was_bound = True\n            if was_bound:\n                handler_append(bound)\n\n    try:\n        return eval(value, idmap)\n    except Exception as e:\n        tb = sys.exc_info()[2]\n        raise BuilderException(rule.ctx, rule.line,\n                               '{}: {}'.format(e.__class__.__name__, e),\n                               cause=tb)\n\n\nclass ParserSelector(object):\n\n    def __init__(self, key):\n        self.key = key.lower()\n\n    def match(self, widget):\n        raise NotImplemented()\n\n    def __repr__(self):\n        return '<%s key=%s>' % (self.__class__.__name__, self.key)\n\n\nclass ParserSelectorId(ParserSelector):\n\n    def match(self, widget):\n        if widget.id:\n            return widget.id.lower() == self.key\n\n\nclass ParserSelectorClass(ParserSelector):\n\n    def match(self, widget):\n        return self.key in widget.cls\n\n\nclass ParserSelectorName(ParserSelector):\n\n    parents = {}\n\n    def get_bases(self, cls):\n        for base in cls.__bases__:\n            if base.__name__ == 'object':\n                break\n            yield base\n            if base.__name__ == 'Widget':\n                break\n            for cbase in self.get_bases(base):\n                yield cbase\n\n    def match(self, widget):\n        parents = ParserSelectorName.parents\n        cls = widget.__class__\n        if not cls in parents:\n            classes = [x.__name__.lower() for x in\n                       [cls] + list(self.get_bases(cls))]\n            parents[cls] = classes\n        return self.key in parents[cls]\n\n\nclass BuilderBase(object):\n    '''The Builder is responsible for creating a :class:`Parser` for parsing a\n    kv file, merging the results into its internal rules, templates, etc.\n\n    By default, :class:`Builder` is a global Kivy instance used in widgets\n    that you can use to load other kv files in addition to the default ones.\n    '''\n\n    _match_cache = {}\n\n    def __init__(self):\n        super(BuilderBase, self).__init__()\n        self.files = []\n        self.dynamic_classes = {}\n        self.templates = {}\n        self.rules = []\n        self.rulectx = {}\n\n    def load_file(self, filename, **kwargs):\n        '''Insert a file into the language builder and return the root widget\n        (if defined) of the kv file.\n\n        :parameters:\n            `rulesonly`: bool, defaults to False\n                If True, the Builder will raise an exception if you have a root\n                widget inside the definition.\n        '''\n        filename = resource_find(filename) or filename\n        if __debug__:\n            trace('Builder: load file %s' % filename)\n        with open(filename, 'r') as fd:\n            kwargs['filename'] = filename\n            data = fd.read()\n\n            # remove bom ?\n            if PY2:\n                if data.startswith((codecs.BOM_UTF16_LE, codecs.BOM_UTF16_BE)):\n                    raise ValueError('Unsupported UTF16 for kv files.')\n                if data.startswith((codecs.BOM_UTF32_LE, codecs.BOM_UTF32_BE)):\n                    raise ValueError('Unsupported UTF32 for kv files.')\n                if data.startswith(codecs.BOM_UTF8):\n                    data = data[len(codecs.BOM_UTF8):]\n\n            return self.load_string(data, **kwargs)\n\n    def unload_file(self, filename):\n        '''Unload all rules associated with a previously imported file.\n\n        .. versionadded:: 1.0.8\n\n        .. warning::\n\n            This will not remove rules or templates already applied/used on\n            current widgets. It will only effect the next widgets creation or\n            template invocation.\n        '''\n        # remove rules and templates\n        self.rules = [x for x in self.rules if x[1].ctx.filename != filename]\n        self._clear_matchcache()\n        templates = {}\n        for x, y in self.templates.items():\n            if y[2] != filename:\n                templates[x] = y\n        self.templates = templates\n        if filename in self.files:\n            self.files.remove(filename)\n\n        # unregister all the dynamic classes\n        Factory.unregister_from_filename(filename)\n\n    def load_string(self, string, **kwargs):\n        '''Insert a string into the Language Builder and return the root widget\n        (if defined) of the kv string.\n\n        :Parameters:\n            `rulesonly`: bool, defaults to False\n                If True, the Builder will raise an exception if you have a root\n                widget inside the definition.\n        '''\n        kwargs.setdefault('rulesonly', False)\n        self._current_filename = fn = kwargs.get('filename', None)\n\n        # put a warning if a file is loaded multiple times\n        if fn in self.files:\n            Logger.warning(\n                'Lang: The file {} is loaded multiples times, '\n                'you might have unwanted behaviors.'.format(fn))\n\n        try:\n            # parse the string\n            parser = Parser(content=string, filename=fn)\n\n            # merge rules with our rules\n            self.rules.extend(parser.rules)\n            self._clear_matchcache()\n\n            # add the template found by the parser into ours\n            for name, cls, template in parser.templates:\n                self.templates[name] = (cls, template, fn)\n                Factory.register(name,\n                                 cls=partial(self.template, name),\n                                 is_template=True, warn=True)\n\n            # register all the dynamic classes\n            for name, baseclasses in iteritems(parser.dynamic_classes):\n                Factory.register(name, baseclasses=baseclasses, filename=fn,\n                                 warn=True)\n\n            # create root object is exist\n            if kwargs['rulesonly'] and parser.root:\n                filename = kwargs.get('rulesonly', '<string>')\n                raise Exception('The file <%s> contain also non-rules '\n                                'directives' % filename)\n\n            # save the loaded files only if there is a root without\n            # template/dynamic classes\n            if fn and (parser.templates or\n                       parser.dynamic_classes or parser.rules):\n                self.files.append(fn)\n\n            if parser.root:\n                widget = Factory.get(parser.root.name)()\n                self._apply_rule(widget, parser.root, parser.root)\n                return widget\n        finally:\n            self._current_filename = None\n\n    def template(self, *args, **ctx):\n        '''Create a specialized template using a specific context.\n        .. versionadded:: 1.0.5\n\n        With templates, you can construct custom widgets from a kv lang\n        definition by giving them a context. Check :ref:`Template usage\n        <template_usage>`.\n        '''\n        # Prevent naming clash with whatever the user might be putting into the\n        # ctx as key.\n        name = args[0]\n        if name not in self.templates:\n            raise Exception('Unknown <%s> template name' % name)\n        baseclasses, rule, fn = self.templates[name]\n        key = '%s|%s' % (name, baseclasses)\n        cls = Cache.get('kv.lang', key)\n        if cls is None:\n            rootwidgets = []\n            for basecls in baseclasses.split('+'):\n                rootwidgets.append(Factory.get(basecls))\n            cls = type(name, tuple(rootwidgets), {})\n            Cache.append('kv.lang', key, cls)\n        widget = cls()\n        # in previous versions, ``ctx`` is passed as is as ``template_ctx``\n        # preventing widgets in it from be collected by the GC. This was\n        # especially relevant to AccordionItem's title_template.\n        proxy_ctx = {k: get_proxy(v) for k, v in ctx.items()}\n        self._apply_rule(widget, rule, rule, template_ctx=proxy_ctx)\n        return widget\n\n    def apply(self, widget):\n        '''Search all the rules that match the widget and apply them.\n        '''\n        rules = self.match(widget)\n        if __debug__:\n            trace('Builder: Found %d rules for %s' % (len(rules), widget))\n        if not rules:\n            return\n        for rule in rules:\n            self._apply_rule(widget, rule, rule)\n\n    def _clear_matchcache(self):\n        BuilderBase._match_cache = {}\n\n    def _apply_rule(self, widget, rule, rootrule, template_ctx=None):\n        # widget: the current instantiated widget\n        # rule: the current rule\n        # rootrule: the current root rule (for children of a rule)\n\n        # will collect reference to all the id in children\n        assert(rule not in self.rulectx)\n        self.rulectx[rule] = rctx = {\n            'ids': {'root': widget.proxy_ref},\n            'set': [], 'hdl': []}\n\n        # extract the context of the rootrule (not rule!)\n        assert(rootrule in self.rulectx)\n        rctx = self.rulectx[rootrule]\n\n        # if a template context is passed, put it as \"ctx\"\n        if template_ctx is not None:\n            rctx['ids']['ctx'] = QueryDict(template_ctx)\n\n        # if we got an id, put it in the root rule for a later global usage\n        if rule.id:\n            # use only the first word as `id` discard the rest.\n            rule.id = rule.id.split('#', 1)[0].strip()\n            rctx['ids'][rule.id] = widget.proxy_ref\n            # set id name as a attribute for root widget so one can in python\n            # code simply access root_widget.id_name\n            _ids = dict(rctx['ids'])\n            _root = _ids.pop('root')\n            _new_ids = _root.ids\n            for _key in iterkeys(_ids):\n                if _ids[_key] == _root:\n                    # skip on self\n                    continue\n                _new_ids[_key] = _ids[_key]\n            _root.ids = _new_ids\n\n        # first, ensure that the widget have all the properties used in\n        # the rule if not, they will be created as ObjectProperty.\n        rule.create_missing(widget)\n\n        # build the widget canvas\n        if rule.canvas_before:\n            with widget.canvas.before:\n                self._build_canvas(widget.canvas.before, widget,\n                                   rule.canvas_before, rootrule)\n        if rule.canvas_root:\n            with widget.canvas:\n                self._build_canvas(widget.canvas, widget,\n                                   rule.canvas_root, rootrule)\n        if rule.canvas_after:\n            with widget.canvas.after:\n                self._build_canvas(widget.canvas.after, widget,\n                                   rule.canvas_after, rootrule)\n\n        # create children tree\n        Factory_get = Factory.get\n        Factory_is_template = Factory.is_template\n        for crule in rule.children:\n            cname = crule.name\n\n            if cname in ('canvas', 'canvas.before', 'canvas.after'):\n                raise ParserException(\n                    crule.ctx, crule.line,\n                    'Canvas instructions added in kv must '\n                    'be declared before child widgets.')\n\n            # depending if the child rule is a template or not, we are not\n            # having the same approach\n            cls = Factory_get(cname)\n\n            if Factory_is_template(cname):\n                # we got a template, so extract all the properties and\n                # handlers, and push them in a \"ctx\" dictionary.\n                ctx = {}\n                idmap = copy(global_idmap)\n                idmap.update({'root': rctx['ids']['root']})\n                if 'ctx' in rctx['ids']:\n                    idmap.update({'ctx': rctx['ids']['ctx']})\n                try:\n                    for prule in crule.properties.values():\n                        value = prule.co_value\n                        if type(value) is CodeType:\n                            value = eval(value, idmap)\n                        ctx[prule.name] = value\n                    for prule in crule.handlers:\n                        value = eval(prule.value, idmap)\n                        ctx[prule.name] = value\n                except Exception as e:\n                    tb = sys.exc_info()[2]\n                    raise BuilderException(\n                        prule.ctx, prule.line,\n                        '{}: {}'.format(e.__class__.__name__, e), cause=tb)\n\n                # create the template with an explicit ctx\n                child = cls(**ctx)\n                widget.add_widget(child)\n\n                # reference it on our root rule context\n                if crule.id:\n                    rctx['ids'][crule.id] = child\n\n            else:\n                # we got a \"normal\" rule, construct it manually\n                # we can't construct it without __no_builder=True, because the\n                # previous implementation was doing the add_widget() before\n                # apply(), and so, we could use \"self.parent\".\n                child = cls(__no_builder=True)\n                widget.add_widget(child)\n                self.apply(child)\n                self._apply_rule(child, crule, rootrule)\n\n        # append the properties and handlers to our final resolution task\n        if rule.properties:\n            rctx['set'].append((widget.proxy_ref,\n                                list(rule.properties.values())))\n        if rule.handlers:\n            rctx['hdl'].append((widget.proxy_ref, rule.handlers))\n\n        # if we are applying another rule that the root one, then it's done for\n        # us!\n        if rootrule is not rule:\n            del self.rulectx[rule]\n            return\n\n        # normally, we can apply a list of properties with a proper context\n        try:\n            rule = None\n            for widget_set, rules in reversed(rctx['set']):\n                for rule in rules:\n                    assert(isinstance(rule, ParserRuleProperty))\n                    key = rule.name\n                    value = rule.co_value\n                    if type(value) is CodeType:\n                        value = create_handler(widget_set, widget_set, key,\n                                               value, rule, rctx['ids'])\n                    setattr(widget_set, key, value)\n        except Exception as e:\n            if rule is not None:\n                tb = sys.exc_info()[2]\n                raise BuilderException(rule.ctx, rule.line,\n                                       '{}: {}'.format(e.__class__.__name__,\n                                                       e), cause=tb)\n            raise e\n\n        # build handlers\n        try:\n            crule = None\n            for widget_set, rules in rctx['hdl']:\n                for crule in rules:\n                    assert(isinstance(crule, ParserRuleProperty))\n                    assert(crule.name.startswith('on_'))\n                    key = crule.name\n                    if not widget_set.is_event_type(key):\n                        key = key[3:]\n                    idmap = copy(global_idmap)\n                    idmap.update(rctx['ids'])\n                    idmap['self'] = widget_set.proxy_ref\n                    if not widget_set.fast_bind(key, custom_callback, crule,\n                                                idmap):\n                        raise AttributeError(key)\n                    #hack for on_parent\n                    if crule.name == 'on_parent':\n                        Factory.Widget.parent.dispatch(widget_set.__self__)\n        except Exception as e:\n            if crule is not None:\n                tb = sys.exc_info()[2]\n                raise BuilderException(\n                    crule.ctx, crule.line,\n                    '{}: {}'.format(e.__class__.__name__, e), cause=tb)\n            raise e\n\n        # rule finished, forget it\n        del self.rulectx[rootrule]\n\n    def match(self, widget):\n        '''Return a list of :class:`ParserRule` objects matching the widget.\n        '''\n        cache = BuilderBase._match_cache\n        k = (widget.__class__, widget.id, tuple(widget.cls))\n        if k in cache:\n            return cache[k]\n        rules = []\n        for selector, rule in self.rules:\n            if selector.match(widget):\n                if rule.avoid_previous_rules:\n                    del rules[:]\n                rules.append(rule)\n        cache[k] = rules\n        return rules\n\n    def sync(self):\n        '''Execute all the waiting operations, such as the execution of all the\n        expressions related to the canvas.\n\n        .. versionadded:: 1.7.0\n        '''\n        global _delayed_start\n        next_args = _delayed_start\n        if next_args is None:\n            return\n\n        while next_args is not StopIteration:\n            # is this try/except still needed? yes, in case widget died in this\n            # frame after the call was scheduled\n            try:\n                call_fn(next_args[:-1], None, None)\n            except ReferenceError:\n                pass\n            args = next_args\n            next_args = args[-1]\n            args[-1] = None\n        _delayed_start = None\n\n    def unbind_widget(self, uid):\n        '''(internal) Unbind all the handlers created by the rules of the\n        widget. The :attr:`kivy.uix.widget.Widget.uid` is passed here\n        instead of the widget itself, because we are using it in the\n        widget destructor.\n\n        .. versionadded:: 1.7.2\n        '''\n        if uid not in _handlers:\n            return\n        for callbacks in _handlers[uid]:\n            for f, k, fn, bound_uid in callbacks:\n                if fn is None:  # it's not a kivy prop.\n                    continue\n                try:\n                    f.unbind_uid(k, bound_uid)\n                except ReferenceError:\n                    # proxy widget is already gone, that's cool :)\n                    pass\n        del _handlers[uid]\n\n    def _build_canvas(self, canvas, widget, rule, rootrule):\n        global Instruction\n        if Instruction is None:\n            Instruction = Factory.get('Instruction')\n        idmap = copy(self.rulectx[rootrule]['ids'])\n        for crule in rule.children:\n            name = crule.name\n            if name == 'Clear':\n                canvas.clear()\n                continue\n            instr = Factory.get(name)()\n            if not isinstance(instr, Instruction):\n                raise BuilderException(\n                    crule.ctx, crule.line,\n                    'You can add only graphics Instruction in canvas.')\n            try:\n                for prule in crule.properties.values():\n                    key = prule.name\n                    value = prule.co_value\n                    if type(value) is CodeType:\n                        value = create_handler(\n                            widget, instr.proxy_ref,\n                            key, value, prule, idmap, True)\n                    setattr(instr, key, value)\n            except Exception as e:\n                tb = sys.exc_info()[2]\n                raise BuilderException(\n                    prule.ctx, prule.line,\n                    '{}: {}'.format(e.__class__.__name__, e), cause=tb)\n\n#: Main instance of a :class:`BuilderBase`.\nBuilder = register_context('Builder', BuilderBase)\nBuilder.load_file(join(kivy_data_dir, 'style.kv'), rulesonly=True)\n\nif 'KIVY_PROFILE_LANG' in environ:\n    import atexit\n    import cgi\n\n    def match_rule(fn, index, rule):\n        if rule.ctx.filename != fn:\n            return\n        for prop, prp in iteritems(rule.properties):\n            if prp.line != index:\n                continue\n            yield prp\n        for child in rule.children:\n            for r in match_rule(fn, index, child):\n                yield r\n        if rule.canvas_root:\n            for r in match_rule(fn, index, rule.canvas_root):\n                yield r\n        if rule.canvas_before:\n            for r in match_rule(fn, index, rule.canvas_before):\n                yield r\n        if rule.canvas_after:\n            for r in match_rule(fn, index, rule.canvas_after):\n                yield r\n\n    def dump_builder_stats():\n        html = [\n            '<!doctype html>'\n            '<html><body>',\n            '<style type=\"text/css\">\\n',\n            'pre { margin: 0; }\\n',\n            '</style>']\n        files = set([x[1].ctx.filename for x in Builder.rules])\n        for fn in files:\n            lines = open(fn).readlines()\n            html += ['<h2>', fn, '</h2>', '<table>']\n            count = 0\n            for index, line in enumerate(lines):\n                line = line.rstrip()\n                line = cgi.escape(line)\n                matched_prp = []\n                for psn, rule in Builder.rules:\n                    matched_prp += list(match_rule(fn, index, rule))\n\n                count = sum(set([x.count for x in matched_prp]))\n\n                color = (255, 155, 155) if count else (255, 255, 255)\n                html += ['<tr style=\"background-color: rgb{}\">'.format(color),\n                         '<td>', str(index + 1), '</td>',\n                         '<td>', str(count), '</td>',\n                         '<td><pre>', line, '</pre></td>',\n                         '</tr>']\n            html += ['</table>']\n        html += ['</body></html>']\n        with open('builder_stats.html', 'w') as fd:\n            fd.write(''.join(html))\n\n        print('Profiling written at builder_stats.html')\n\n    atexit.register(dump_builder_stats)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/loader.py",
    "content": "'''\nAsynchronous data loader\n========================\n\nThis is the Asynchronous Loader. You can use it to load an image\nand use it, even if data are not yet available. You must specify a default\nloading image when using the loader::\n\n    from kivy.loader import Loader\n    image = Loader.image('mysprite.png')\n\nYou can also load an image from a url::\n\n    image = Loader.image('http://mysite.com/test.png')\n\nIf you want to change the default loading image, you can do::\n\n    Loader.loading_image = Image('another_loading.png')\n\nTweaking the asynchronous loader\n--------------------------------\n\n.. versionadded:: 1.6.0\n\nYou can tweak the loader to provide a better user experience or more\nperformance, depending of the images you are going to load. Take a look at the\nparameters:\n\n- :attr:`Loader.num_workers` - define the number of threads to start for\n  loading images.\n- :attr:`Loader.max_upload_per_frame` - define the maximum image uploads in\n  GPU to do per frame.\n\n'''\n\n__all__ = ('Loader', 'LoaderBase', 'ProxyImage')\n\nfrom kivy import kivy_data_dir\nfrom kivy.logger import Logger\nfrom kivy.clock import Clock\nfrom kivy.cache import Cache\nfrom kivy.core.image import ImageLoader, Image\nfrom kivy.compat import PY2, string_types\n\nfrom collections import deque\nfrom time import sleep\nfrom os.path import join\nfrom os import write, close, unlink, environ\nimport threading\nimport mimetypes\n\n# Register a cache for loader\nCache.register('kv.loader', limit=500, timeout=60)\n\n\nclass ProxyImage(Image):\n    '''Image returned by the Loader.image() function.\n\n    :Properties:\n        `loaded`: bool, defaults to False\n            This value may be True if the image is already cached.\n\n    :Events:\n        `on_load`\n            Fired when the image is loaded or changed.\n    '''\n\n    __events__ = ('on_load', )\n\n    def __init__(self, arg, **kwargs):\n        kwargs.setdefault('loaded', False)\n        super(ProxyImage, self).__init__(arg, **kwargs)\n        self.loaded = kwargs.get('loaded')\n\n    def on_load(self):\n        pass\n\n\nclass LoaderBase(object):\n    '''Common base for the Loader and specific implementations.\n    By default, the Loader will be the best available loader implementation.\n\n    The _update() function is called every 1 / 25.s or each frame if we have\n    less than 25 FPS.\n    '''\n\n    def __init__(self):\n        self._loading_image = None\n        self._error_image = None\n        self._num_workers = 2\n        self._max_upload_per_frame = 2\n        self._paused = False\n        self._resume_cond = threading.Condition()\n\n        self._q_load = deque()\n        self._q_done = deque()\n        self._client = []\n        self._running = False\n        self._start_wanted = False\n        self._trigger_update = Clock.create_trigger(self._update)\n\n    def __del__(self):\n        try:\n            Clock.unschedule(self._update)\n        except Exception:\n            pass\n\n    def _set_num_workers(self, num):\n        if num < 2:\n            raise Exception('Must have at least 2 workers')\n        self._num_workers = num\n\n    def _get_num_workers(self):\n        return self._num_workers\n\n    num_workers = property(_get_num_workers, _set_num_workers)\n    '''Number of workers to use while loading (used only if the loader\n    implementation supports it). This setting impacts the loader only on\n    initialization. Once the loader is started, the setting has no impact::\n\n        from kivy.loader import Loader\n        Loader.num_workers = 4\n\n    The default value is 2 for giving a smooth user experience. You could\n    increase the number of workers, then all the images will be loaded faster,\n    but the user will not been able to use the application while loading.\n    Prior to 1.6.0, the default number was 20, and loading many full-hd images\n    was completly blocking the application.\n\n    .. versionadded:: 1.6.0\n    '''\n\n    def _set_max_upload_per_frame(self, num):\n        if num is not None and num < 1:\n            raise Exception('Must have at least 1 image processing per image')\n        self._max_upload_per_frame = num\n\n    def _get_max_upload_per_frame(self):\n        return self._max_upload_per_frame\n\n    max_upload_per_frame = property(_get_max_upload_per_frame,\n                                    _set_max_upload_per_frame)\n    '''The number of images to upload per frame. By default, we'll\n    upload only 2 images to the GPU per frame. If you are uploading many\n    small images, you can easily increase this parameter to 10 or more.\n    If you are loading multiple full HD images, the upload time may have\n    consequences and block the application. If you want a\n    smooth experience, use the default.\n\n    As a matter of fact, a Full-HD RGB image will take ~6MB in memory,\n    so it may take time. If you have activated mipmap=True too, then the\n    GPU must calculate the mipmap of these big images too, in real time.\n    Then it may be best to reduce the :attr:`max_upload_per_frame` to 1\n    or 2. If you want to get rid of that (or reduce it a lot), take a\n    look at the DDS format.\n\n    .. versionadded:: 1.6.0\n    '''\n\n    def _get_loading_image(self):\n        if not self._loading_image:\n            loading_png_fn = join(kivy_data_dir, 'images', 'image-loading.gif')\n            self._loading_image = ImageLoader.load(filename=loading_png_fn)\n        return self._loading_image\n\n    def _set_loading_image(self, image):\n        if isinstance(image, string_types):\n            self._loading_image = ImageLoader.load(filename=image)\n        else:\n            self._loading_image = image\n\n    loading_image = property(_get_loading_image, _set_loading_image)\n    '''Image used for loading.\n    You can change it by doing::\n\n        Loader.loading_image = 'loading.png'\n\n    .. versionchanged:: 1.6.0\n        Not readonly anymore.\n    '''\n\n    def _get_error_image(self):\n        if not self._error_image:\n            error_png_fn = join(\n                'atlas://data/images/defaulttheme/image-missing')\n            self._error_image = ImageLoader.load(filename=error_png_fn)\n        return self._error_image\n\n    def _set_error_image(self, image):\n        if isinstance(image, string_types):\n            self._error_image = ImageLoader.load(filename=image)\n        else:\n            self._error_image = image\n\n    error_image = property(_get_error_image, _set_error_image)\n    '''Image used for error.\n    You can change it by doing::\n\n        Loader.error_image = 'error.png'\n\n    .. versionchanged:: 1.6.0\n        Not readonly anymore.\n    '''\n\n    def start(self):\n        '''Start the loader thread/process.'''\n        self._running = True\n\n    def run(self, *largs):\n        '''Main loop for the loader.'''\n        pass\n\n    def stop(self):\n        '''Stop the loader thread/process.'''\n        self._running = False\n\n    def pause(self):\n        '''Pause the loader, can be useful during interactions.\n\n        .. versionadded:: 1.6.0\n        '''\n        self._paused = True\n\n    def resume(self):\n        '''Resume the loader, after a :meth:`pause`.\n\n        .. versionadded:: 1.6.0\n        '''\n        self._paused = False\n        self._resume_cond.acquire()\n        self._resume_cond.notify_all()\n        self._resume_cond.release()\n\n    def _wait_for_resume(self):\n        while self._running and self._paused:\n            self._resume_cond.acquire()\n            self._resume_cond.wait(0.25)\n            self._resume_cond.release()\n\n    def _load(self, kwargs):\n        '''(internal) Loading function, called by the thread.\n        Will call _load_local() if the file is local,\n        or _load_urllib() if the file is on Internet.\n        '''\n\n        while len(self._q_done) >= (\n                self.max_upload_per_frame * self._num_workers):\n            sleep(0.1)\n\n        self._wait_for_resume()\n\n        filename = kwargs['filename']\n        load_callback = kwargs['load_callback']\n        post_callback = kwargs['post_callback']\n        try:\n            proto = filename.split(':', 1)[0]\n        except:\n            #if blank filename then return\n            return\n        if load_callback is not None:\n            data = load_callback(filename)\n        elif proto in ('http', 'https', 'ftp', 'smb'):\n            data = self._load_urllib(filename, kwargs['kwargs'])\n        else:\n            data = self._load_local(filename, kwargs['kwargs'])\n\n        if post_callback:\n            data = post_callback(data)\n\n        self._q_done.appendleft((filename, data))\n        self._trigger_update()\n\n    def _load_local(self, filename, kwargs):\n        '''(internal) Loading a local file'''\n        # With recent changes to CoreImage, we must keep data otherwise,\n        # we might be unable to recreate the texture afterwise.\n        return ImageLoader.load(filename, keep_data=True, **kwargs)\n\n    def _load_urllib(self, filename, kwargs):\n        '''(internal) Loading a network file. First download it, save it to a\n        temporary file, and pass it to _load_local().'''\n        if PY2:\n            import urllib2 as urllib_request\n\n            def gettype(info):\n                return info.gettype()\n        else:\n            import urllib.request as urllib_request\n\n            def gettype(info):\n                return info.get_content_type()\n        proto = filename.split(':', 1)[0]\n        if proto == 'smb':\n            try:\n                # note: it's important to load SMBHandler every time\n                # otherwise the data is occasionaly not loaded\n                from smb.SMBHandler import SMBHandler\n            except ImportError:\n                Logger.warning(\n                    'Loader: can not load PySMB: make sure it is installed')\n                return\n        import tempfile\n        data = fd = _out_osfd = None\n        try:\n            _out_filename = ''\n\n            if proto == 'smb':\n                # read from samba shares\n                fd = urllib_request.build_opener(SMBHandler).open(filename)\n            else:\n                # read from internet\n                fd = urllib_request.urlopen(filename)\n\n            if '#.' in filename:\n                # allow extension override from URL fragment\n                suffix = '.' + filename.split('#.')[-1]\n            else:\n                ctype = gettype(fd.info())\n                suffix = mimetypes.guess_extension(ctype)\n                if not suffix:\n                    # strip query string and split on path\n                    parts = filename.split('?')[0].split('/')[1:]\n                    while len(parts) > 1 and not parts[0]:\n                        # strip out blanks from '//'\n                        parts = parts[1:]\n                    if len(parts) > 1 and '.' in parts[-1]:\n                        # we don't want '.com', '.net', etc. as the extension\n                        suffix = '.' + parts[-1].split('.')[-1]\n            _out_osfd, _out_filename = tempfile.mkstemp(\n                prefix='kivyloader', suffix=suffix)\n\n            idata = fd.read()\n            fd.close()\n            fd = None\n\n            # write to local filename\n            write(_out_osfd, idata)\n            close(_out_osfd)\n            _out_osfd = None\n\n            # load data\n            data = self._load_local(_out_filename, kwargs)\n\n            # FIXME create a clean API for that\n            for imdata in data._data:\n                imdata.source = filename\n        except Exception:\n            Logger.exception('Loader: Failed to load image <%s>' % filename)\n            # close file when remote file not found or download error\n            try:\n                close(_out_osfd)\n            except OSError:\n                pass\n            return self.error_image\n        finally:\n            if fd:\n                fd.close()\n            if _out_osfd:\n                close(_out_osfd)\n            if _out_filename != '':\n                unlink(_out_filename)\n\n        return data\n\n    def _update(self, *largs):\n        '''(internal) Check if a data is loaded, and pass to the client.'''\n        # want to start it ?\n        if self._start_wanted:\n            if not self._running:\n                self.start()\n            self._start_wanted = False\n\n        # in pause mode, don't unqueue anything.\n        if self._paused:\n            self._trigger_update()\n            return\n\n        for x in range(self.max_upload_per_frame):\n            try:\n                filename, data = self._q_done.pop()\n            except IndexError:\n                return\n\n            # create the image\n            image = data  # ProxyImage(data)\n            if not image.nocache:\n                Cache.append('kv.loader', filename, image)\n\n            # update client\n            for c_filename, client in self._client[:]:\n                if filename != c_filename:\n                    continue\n                # got one client to update\n                client.image = image\n                client.loaded = True\n                client.dispatch('on_load')\n                self._client.remove((c_filename, client))\n\n        self._trigger_update()\n\n    def image(self, filename, load_callback=None, post_callback=None,\n              **kwargs):\n        '''Load a image using the Loader. A ProxyImage is returned with a\n        loading image. You can use it as follows::\n\n            from kivy.app import App\n            from kivy.uix.image import Image\n            from kivy.loader import Loader\n\n            class TestApp(App):\n                def _image_loaded(self, proxyImage):\n                    if proxyImage.image.texture:\n                        self.image.texture = proxyImage.image.texture\n\n                def build(self):\n                    proxyImage = Loader.image(\"myPic.jpg\")\n                    proxyImage.bind(on_load=self._image_loaded)\n                    self.image = Image()\n                    return self.image\n\n            TestApp().run()\n\n        In order to cancel all background loading, call *Loader.stop()*.\n        '''\n        data = Cache.get('kv.loader', filename)\n        if data not in (None, False):\n            # found image, if data is not here, need to reload.\n            return ProxyImage(data,\n                              loading_image=self.loading_image,\n                              loaded=True, **kwargs)\n\n        client = ProxyImage(self.loading_image,\n                            loading_image=self.loading_image, **kwargs)\n        self._client.append((filename, client))\n\n        if data is None:\n            # if data is None, this is really the first time\n            self._q_load.appendleft({\n                'filename': filename,\n                'load_callback': load_callback,\n                'post_callback': post_callback,\n                'kwargs': kwargs})\n            if not kwargs.get('nocache', False):\n                Cache.append('kv.loader', filename, False)\n            self._start_wanted = True\n            self._trigger_update()\n        else:\n            # already queued for loading\n            pass\n\n        return client\n\n#\n# Loader implementation\n#\n\nif 'KIVY_DOC' in environ:\n\n    Loader = None\n\nelse:\n\n    #\n    # Try to use pygame as our first choice for loader\n    #\n\n    from kivy.compat import queue\n    from threading import Thread\n\n    class _Worker(Thread):\n        '''Thread executing tasks from a given tasks queue\n        '''\n        def __init__(self, pool, tasks):\n            Thread.__init__(self)\n            self.tasks = tasks\n            self.daemon = True\n            self.pool = pool\n            self.start()\n\n        def run(self):\n            while self.pool.running:\n                func, args, kargs = self.tasks.get()\n                try:\n                    func(*args, **kargs)\n                except Exception as e:\n                    print(e)\n                self.tasks.task_done()\n\n    class _ThreadPool(object):\n        '''Pool of threads consuming tasks from a queue\n        '''\n        def __init__(self, num_threads):\n            super(_ThreadPool, self).__init__()\n            self.running = True\n            self.tasks = queue.Queue()\n            for _ in range(num_threads):\n                _Worker(self, self.tasks)\n\n        def add_task(self, func, *args, **kargs):\n            '''Add a task to the queue\n            '''\n            self.tasks.put((func, args, kargs))\n\n        def stop(self):\n            self.running = False\n            self.tasks.join()\n\n    class LoaderThreadPool(LoaderBase):\n        def __init__(self):\n            super(LoaderThreadPool, self).__init__()\n            self.pool = None\n\n        def start(self):\n            super(LoaderThreadPool, self).start()\n            self.pool = _ThreadPool(self._num_workers)\n            Clock.schedule_interval(self.run, 0)\n\n        def stop(self):\n            super(LoaderThreadPool, self).stop()\n            Clock.unschedule(self.run)\n            self.pool.stop()\n\n        def run(self, *largs):\n            while self._running:\n                try:\n                    parameters = self._q_load.pop()\n                except:\n                    return\n                self.pool.add_task(self._load, parameters)\n\n    Loader = LoaderThreadPool()\n    Logger.info('Loader: using a thread pool of {} workers'.format(\n        Loader.num_workers))\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/logger.py",
    "content": "'''\nLogger object\n=============\n\nDifferents logging levels are available : trace, debug, info, warning, error\nand critical.\n\nExamples of usage::\n\n    from kivy.logger import Logger\n\n    Logger.info('title: This is a info message.')\n    Logger.debug('title: This is a debug message.')\n\n    try:\n        raise Exception('bleh')\n    except Exception:\n        Logger.exception('Something happened!')\n\nThe message passed to the logger is split into two parts, separated by a colon\n(:). The first part is used as a title, and the second part is used as the\nmessage. This way, you can \"categorize\" your message easily.::\n\n    Logger.info('Application: This is a test')\n\n    # will appear as\n\n    [INFO   ] [Application ] This is a test\n\nLogger configuration\n--------------------\n\nThe Logger can be controlled via the Kivy configuration file::\n\n    [kivy]\n    log_level = info\n    log_enable = 1\n    log_dir = logs\n    log_name = kivy_%y-%m-%d_%_.txt\n\nMore information about the allowed values are described in the\n:mod:`kivy.config` module.\n\nLogger history\n--------------\n\nEven if the logger is not enabled, you still have access to the last 100\nmessages::\n\n    from kivy.logger import LoggerHistory\n\n    print(LoggerHistory.history)\n\n'''\n\nimport logging\nimport os\nimport sys\nimport kivy\nfrom kivy.compat import PY2\nfrom random import randint\nfrom functools import partial\n\n__all__ = ('Logger', 'LOG_LEVELS', 'COLORS', 'LoggerHistory')\n\nLogger = None\n\nBLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = list(range(8))\n\n#These are the sequences need to get colored ouput\nRESET_SEQ = \"\\033[0m\"\nCOLOR_SEQ = \"\\033[1;%dm\"\nBOLD_SEQ = \"\\033[1m\"\n\nprevious_stderr = sys.stderr\n\n\ndef formatter_message(message, use_color=True):\n    if use_color:\n        message = message.replace(\"$RESET\", RESET_SEQ)\n        message = message.replace(\"$BOLD\", BOLD_SEQ)\n    else:\n        message = message.replace(\"$RESET\", \"\").replace(\"$BOLD\", \"\")\n    return message\n\nCOLORS = {\n    'TRACE': MAGENTA,\n    'WARNING': YELLOW,\n    'INFO': GREEN,\n    'DEBUG': CYAN,\n    'CRITICAL': RED,\n    'ERROR': RED}\n\nlogging.TRACE = 9\nLOG_LEVELS = {\n    'trace': logging.TRACE,\n    'debug': logging.DEBUG,\n    'info': logging.INFO,\n    'warning': logging.WARNING,\n    'error': logging.ERROR,\n    'critical': logging.CRITICAL}\n\n\nclass FileHandler(logging.Handler):\n    history = []\n    filename = 'log.txt'\n    fd = None\n\n    def purge_logs(self, directory):\n        '''Purge log is called randomly to prevent the log directory from being\n        filled by lots and lots of log files.\n        You've a chance of 1 in 20 that purge log will be fired.\n        '''\n        if randint(0, 20) != 0:\n            return\n\n        # Use config ?\n        maxfiles = 100\n\n        print('Purge log fired. Analysing...')\n        join = os.path.join\n        unlink = os.unlink\n\n        # search all log files\n        l = [join(directory, x) for x in os.listdir(directory)]\n        if len(l) > maxfiles:\n            # get creation time on every files\n            l = [{'fn': x, 'ctime': os.path.getctime(x)} for x in l]\n\n            # sort by date\n            l = sorted(l, key=lambda x: x['ctime'])\n\n            # get the oldest (keep last maxfiles)\n            l = l[:-maxfiles]\n            print('Purge %d log files' % len(l))\n\n            # now, unlink every files in the list\n            for filename in l:\n                unlink(filename['fn'])\n\n        print('Purge finished!')\n\n    def _configure(self, *largs, **kwargs):\n        from time import strftime\n        from kivy.config import Config\n        log_dir = Config.get('kivy', 'log_dir')\n        log_name = Config.get('kivy', 'log_name')\n\n        _dir = kivy.kivy_home_dir\n        if log_dir and os.path.isabs(log_dir):\n            _dir = log_dir\n        else:\n            _dir = os.path.join(_dir, log_dir)\n        if not os.path.exists(_dir):\n            os.makedirs(_dir)\n\n        self.purge_logs(_dir)\n\n        pattern = log_name.replace('%_', '@@NUMBER@@')\n        pattern = os.path.join(_dir, strftime(pattern))\n        n = 0\n        while True:\n            filename = pattern.replace('@@NUMBER@@', str(n))\n            if not os.path.exists(filename):\n                break\n            n += 1\n            if n > 10000:  # prevent maybe flooding ?\n                raise Exception('Too many logfile, remove them')\n\n        if FileHandler.filename == filename and FileHandler.fd is not None:\n            return\n        FileHandler.filename = filename\n        if FileHandler.fd is not None:\n            FileHandler.fd.close()\n        FileHandler.fd = open(filename, 'w')\n\n        Logger.info('Logger: Record log in %s' % filename)\n\n    def _write_message(self, record):\n        if FileHandler.fd in (None, False):\n            return\n\n        FileHandler.fd.write('[%-18s] ' % record.levelname)\n        try:\n            FileHandler.fd.write(record.msg)\n        except UnicodeEncodeError:\n            if PY2:\n                FileHandler.fd.write(record.msg.encode('utf8'))\n        FileHandler.fd.write('\\n')\n        FileHandler.fd.flush()\n\n    def emit(self, message):\n        # during the startup, store the message in the history\n        if Logger.logfile_activated is None:\n            FileHandler.history += [message]\n            return\n\n        # startup done, if the logfile is not activated, avoid history.\n        if Logger.logfile_activated is False:\n            FileHandler.history = []\n            return\n\n        if FileHandler.fd is None:\n            try:\n                self._configure()\n                from kivy.config import Config\n                Config.add_callback(self._configure, 'kivy', 'log_dir')\n                Config.add_callback(self._configure, 'kivy', 'log_name')\n            except Exception:\n                # deactivate filehandler...\n                FileHandler.fd = False\n                Logger.exception('Error while activating FileHandler logger')\n                return\n            while FileHandler.history:\n                _message = FileHandler.history.pop()\n                self._write_message(_message)\n\n        self._write_message(message)\n\n\nclass LoggerHistory(logging.Handler):\n\n    history = []\n\n    def emit(self, message):\n        LoggerHistory.history = [message] + LoggerHistory.history[:100]\n\n\nclass ColoredFormatter(logging.Formatter):\n\n    def __init__(self, msg, use_color=True):\n        logging.Formatter.__init__(self, msg)\n        self.use_color = use_color\n\n    def format(self, record):\n        try:\n            msg = record.msg.split(':', 1)\n            if len(msg) == 2:\n                record.msg = '[%-12s]%s' % (msg[0], msg[1])\n        except:\n            pass\n        levelname = record.levelname\n        if record.levelno == logging.TRACE:\n            levelname = 'TRACE'\n            record.levelname = levelname\n        if self.use_color and levelname in COLORS:\n            levelname_color = (\n                COLOR_SEQ % (30 + COLORS[levelname]) + levelname + RESET_SEQ)\n            record.levelname = levelname_color\n        return logging.Formatter.format(self, record)\n\n\nclass ConsoleHandler(logging.StreamHandler):\n\n    def filter(self, record):\n        try:\n            msg = record.msg\n            k = msg.split(':', 1)\n            if k[0] == 'stderr' and len(k) == 2:\n                previous_stderr.write(k[1] + '\\n')\n                return False\n        except:\n            pass\n        return True\n\n\nclass LogFile(object):\n\n    def __init__(self, channel, func):\n        self.buffer = ''\n        self.func = func\n        self.channel = channel\n        self.errors = ''\n\n    def write(self, s):\n        s = self.buffer + s\n        self.flush()\n        f = self.func\n        channel = self.channel\n        lines = s.split('\\n')\n        for l in lines[:-1]:\n            f('%s: %s' % (channel, l))\n        self.buffer = lines[-1]\n\n    def flush(self):\n        return\n\n\ndef logger_config_update(section, key, value):\n    if LOG_LEVELS.get(value) is None:\n        raise AttributeError('Loglevel {0!r} doesn\\'t exists'.format(value))\n    Logger.setLevel(level=LOG_LEVELS.get(value))\n\n#: Kivy default logger instance\nLogger = logging.getLogger('kivy')\nLogger.logfile_activated = None\nLogger.trace = partial(Logger.log, logging.TRACE)\n\n# set the Kivy logger as the default\nlogging.root = Logger\n\n# add default kivy logger\nLogger.addHandler(LoggerHistory())\nif 'KIVY_NO_FILELOG' not in os.environ:\n    Logger.addHandler(FileHandler())\n\n# Use the custom handler instead of streaming one.\nif 'KIVY_NO_CONSOLELOG' not in os.environ:\n    if hasattr(sys, '_kivy_logging_handler'):\n        Logger.addHandler(getattr(sys, '_kivy_logging_handler'))\n    else:\n        use_color = (\n            os.name != 'nt' and\n            os.environ.get('KIVY_BUILD') not in ('android', 'ios') and\n            os.environ.get('TERM') in (\n                'xterm', 'rxvt', 'rxvt-unicode', 'xterm-256color'))\n        color_fmt = formatter_message(\n            '[%(levelname)-18s] %(message)s', use_color)\n        formatter = ColoredFormatter(color_fmt, use_color=use_color)\n        console = ConsoleHandler()\n        console.setFormatter(formatter)\n        Logger.addHandler(console)\n\n# install stderr handlers\nsys.stderr = LogFile('stderr', Logger.warning)\n\n#: Kivy history handler\nLoggerHistory = LoggerHistory\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/metrics.py",
    "content": "'''\nMetrics\n=======\n\n.. versionadded:: 1.5.0\n\nA screen is defined by its physical size, density and resolution. These\nfactors are essential for creating UI's with correct size everywhere.\n\nIn Kivy, all the graphics pipelines work with pixels. But using pixels as a\nmeasurement unit is problematic because sizes change according to the\nscreen.\n\nDimensions\n----------\n\nIf you want to design your UI for different screen sizes, you will want better\nmeasurement units to work with. Kivy provides some more scalable alternatives.\n\n:Units:\n    `pt`\n        Points - 1/72 of an inch based on the physical size of the screen.\n        Prefer to use sp instead of pt.\n    `mm`\n        Millimeters - Based on the physical size of the screen.\n    `cm`\n        Centimeters - Based on the physical size of the screen.\n    `in`\n        Inches - Based on the physical size of the screen.\n    `dp`\n        Density-independent Pixels - An abstract unit that is based on the\n        physical density of the screen. With a :attr:`~MetricsBase.density` of\n        1, 1dp is equal to 1px. When running on a higher density screen, the\n        number of pixels used to draw 1dp is scaled up a factor appropriate to\n        the screen's dpi, and the inverse for a lower dpi.\n        The ratio of dp-to-pixels will change with the screen density, but not\n        necessarily in direct proportion. Using the dp unit is a simple\n        solution to making the view dimensions in your layout resize\n        properly for different screen densities. In others words, it\n        provides consistency for the real-world size of your UI across\n        different devices.\n    `sp`\n        Scale-independent Pixels - This is like the dp unit, but it is also\n        scaled by the user's font size preference. We recommend you use this\n        unit when specifying font sizes, so the font size will be adjusted to\n        both the screen density and the user's preference.\n\nExamples\n--------\n\nHere is an example of creating a label with a sp font_size and setting the\nheight manually with a 10dp margin::\n\n    #:kivy 1.5.0\n    <MyWidget>:\n        Label:\n            text: 'Hello world'\n            font_size: '15sp'\n            size_hint_y: None\n            height: self.texture_size[1] + dp(10)\n\nManual control of metrics\n-------------------------\n\nThe metrics cannot be changed at runtime. Once a value has been converted to\npixels, you can't retrieve the original value anymore. This stems from the fact\nthat the DPI and density of a device cannot be changed at runtime.\n\nWe provide some environment variables to control metrics:\n\n- `KIVY_METRICS_DENSITY`: if set, this value will be used for\n  :attr:`~MetricsBase.density` instead of the systems one. On android,\n  the value varies between 0.75, 1, 1.5 and 2.\n\n- `KIVY_METRICS_FONTSCALE`: if set, this value will be used for\n  :attr:`~MetricsBase.fontscale` instead of the systems one. On android, the\n  value varies between 0.8 and 1.2.\n\n- `KIVY_DPI`: if set, this value will be used for :attr:`~MetricsBase.dpi`.\n  Please\n  note that setting the DPI will not impact the dp/sp notation because these\n  are based on the screen density.\n\nFor example, if you want to simulate a high-density screen (like the HTC One\nX)::\n\n    KIVY_DPI=320 KIVY_METRICS_DENSITY=2 python main.py --size 1280x720\n\nOr a medium-density (like Motorola Droid 2)::\n\n    KIVY_DPI=240 KIVY_METRICS_DENSITY=1.5 python main.py --size 854x480\n\nYou can also simulate an alternative user preference for fontscale as follows::\n\n    KIVY_METRICS_FONTSCALE=1.2 python main.py\n\n'''\n\n\n__all__ = ('Metrics', 'MetricsBase', 'pt', 'inch', 'cm', 'mm', 'dp', 'sp',\n           'metrics')\n\n\nfrom os import environ\nfrom kivy.utils import reify, platform\nfrom kivy.properties import dpi2px\n\n\ndef pt(value):\n    '''Convert from points to pixels\n    '''\n    return dpi2px(value, 'pt')\n\n\ndef inch(value):\n    '''Convert from inches to pixels\n    '''\n    return dpi2px(value, 'in')\n\n\ndef cm(value):\n    '''Convert from centimeters to pixels\n    '''\n    return dpi2px(value, 'cm')\n\n\ndef mm(value):\n    '''Convert from millimeters to pixels\n    '''\n    return dpi2px(value, 'mm')\n\n\ndef dp(value):\n    '''Convert from density-independent pixels to pixels\n    '''\n    return dpi2px(value, 'dp')\n\n\ndef sp(value):\n    '''Convert from scale-independent pixels to pixels\n    '''\n    return dpi2px(value, 'sp')\n\n\nclass MetricsBase(object):\n    '''Class that contains the default attributes for Metrics. Don't use this\n    class directly, but use the `Metrics` instance.\n    '''\n\n    @reify\n    def dpi(self):\n        '''Return the DPI of the screen. Depending on the platform, the DPI can\n        be taken from the Window provider (Desktop mainly) or from a\n        platform-specific module (like android/ios).\n        '''\n        custom_dpi = environ.get('KIVY_DPI')\n        if custom_dpi:\n            return float(custom_dpi)\n\n        if platform == 'android':\n            import android\n            return android.get_dpi()\n        elif platform == 'ios':\n            import ios\n            return ios.get_dpi()\n\n        # for all other platforms..\n        from kivy.base import EventLoop\n        EventLoop.ensure_window()\n        return EventLoop.window.dpi\n\n    @reify\n    def dpi_rounded(self):\n        '''Return the DPI of the screen, rounded to the nearest of 120, 160,\n        240 or 320.\n        '''\n        dpi = self.dpi\n        if dpi < 140:\n            return 120\n        elif dpi < 200:\n            return 160\n        elif dpi < 280:\n            return 240\n        return 320\n\n    @reify\n    def density(self):\n        '''Return the density of the screen. This value is 1 by default\n        on desktops but varies on android depending on the screen.\n        '''\n        custom_density = environ.get('KIVY_METRICS_DENSITY')\n        if custom_density:\n            return float(custom_density)\n\n        if platform == 'android':\n            import jnius\n            Hardware = jnius.autoclass('org.renpy.android.Hardware')\n            return Hardware.metrics.scaledDensity\n        elif platform == 'ios':\n            # 0.75 is for mapping the same density as android tablet\n            import ios\n            return ios.get_scale() * 0.75\n        elif platform == 'macosx':\n            from kivy.base import EventLoop\n            EventLoop.ensure_window()\n            return  EventLoop.window.dpi / 96.\n\n        return 1.0\n\n    @reify\n    def fontscale(self):\n        '''Return the fontscale user preference. This value is 1 by default but\n        can vary between 0.8 and 1.2.\n        '''\n        custom_fontscale = environ.get('KIVY_METRICS_FONTSCALE')\n        if custom_fontscale:\n            return float(custom_fontscale)\n\n        if platform == 'android':\n            from jnius import autoclass\n            PythonActivity = autoclass('org.renpy.android.PythonActivity')\n            config = PythonActivity.mActivity.getResources().getConfiguration()\n            return config.fontScale\n\n        return 1.0\n\n\n#: Default instance of :class:`MetricsBase`, used everywhere in the code\n#: .. versionadded:: 1.7.0\nMetrics = MetricsBase()\n\n#: default instance of :class:`MetricsBase`, used everywhere in the code\n#: (deprecated, use `Metrics` instead.)\nmetrics = Metrics\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/modules/__init__.py",
    "content": "'''\nModules\n=======\n\nModules are classes that can be loaded when a Kivy application is starting. The\nloading of modules is managed by the config file. Currently, we include:\n\n    * :class:`~kivy.modules.touchring`: Draw a circle around each touch.\n    * :class:`~kivy.modules.monitor`: Add a red topbar that indicates the FPS\n      and a small graph indicating input activity.\n    * :class:`~kivy.modules.keybinding`: Bind some keys to actions, such as a\n      screenshot.\n    * :class:`~kivy.modules.recorder`: Record and playback a sequence of\n      events.\n    * :class:`~kivy.modules.screen`: Emulate the characteristics (dpi/density/\n      resolution) of different screens.\n    * :class:`~kivy.modules.inspector`: Examines your widget hierarchy and\n      widget properties.\n    * :class:`~kivy.modules.webdebugger`: Realtime examination of your app\n      internals via a web browser.\n\nModules are automatically loaded from the Kivy path and User path:\n\n    * `PATH_TO_KIVY/kivy/modules`\n    * `HOME/.kivy/mods`\n\nActivating a module\n-------------------\n\nThere are various ways in which you can activate a kivy module.\n\nActivate a module in the config\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nTo activate a module this way, you can edit your configuration file (in your\n`HOME/.kivy/config.ini`)::\n\n    [modules]\n    # uncomment to activate\n    touchring =\n    # monitor =\n    # keybinding =\n\nOnly the name of the module followed by \"=\" is sufficient to activate the\nmodule.\n\nActivate a module in Python\n^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nBefore starting your application, preferably at the start of your import, you\ncan do something like this::\n\n    import kivy\n    kivy.require('1.0.8')\n\n    # Activate the touchring module\n    from kivy.config import Config\n    Config.set('modules', 'touchring', '')\n\nActivate a module via the commandline\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWhen starting your application from the commandline, you can add a\n*-m <modulename>* to the arguments. For example::\n\n    python main.py -m webdebugger\n\n.. note::\n    Some modules, such as the screen, may require additional parameters. They\n    will, however, print these parameters to the console when launched without\n    them.\n\n\nCreate your own module\n----------------------\n\nCreate a file in your `HOME/.kivy/mods`, and create 2 functions::\n\n    def start(win, ctx):\n        pass\n\n    def stop(win, ctx):\n        pass\n\nStart/stop are functions that will be called for every window opened in\nKivy. When you are starting a module, you can use these to store and\nmanage the module state. Use the `ctx` variable as a dictionary. This\ncontext is unique for each instance/start() call of the module, and will\nbe passed to stop() too.\n\n'''\n\n__all__ = ('Modules', )\n\nfrom kivy.config import Config\nfrom kivy.logger import Logger\nimport kivy\nimport os\nimport sys\n\n\nclass ModuleContext:\n    '''Context of a module\n\n    You can access to the config with self.config.\n    '''\n\n    def __init__(self):\n        self.config = {}\n\n    def __repr__(self):\n        return repr(self.config)\n\n\nclass ModuleBase:\n    '''Handle Kivy modules. It will automatically load and instanciate the\n    module for the general window.'''\n\n    def __init__(self, **kwargs):\n        self.mods = {}\n        self.wins = []\n\n    def add_path(self, path):\n        '''Add a path to search for modules in'''\n        if not os.path.exists(path):\n            return\n        if path not in sys.path:\n            sys.path.append(path)\n        dirs = os.listdir(path)\n        for module in dirs:\n            name, ext = os.path.splitext(module)\n            # accept only python extensions\n            if ext not in ('.py', '.pyo', '.pyc') or name == '__init__':\n                continue\n            self.mods[name] = {\n                'name': name,\n                'activated': False,\n                'context': ModuleContext()}\n\n    def list(self):\n        '''Return the list of available modules'''\n        return self.mods\n\n    def import_module(self, name):\n        try:\n            modname = 'kivy.modules.{0}'.format(name)\n            module = __import__(name=modname)\n            module = sys.modules[modname]\n        except ImportError:\n            try:\n                module = __import__(name=name)\n                module = sys.modules[name]\n            except ImportError:\n                Logger.exception('Modules: unable to import <%s>' % name)\n                raise\n        # basic check on module\n        if not hasattr(module, 'start'):\n            Logger.warning('Modules: Module <%s> missing start() function' %\n                           name)\n            return\n        if not hasattr(module, 'stop'):\n            err = 'Modules: Module <%s> missing stop() function' % name\n            Logger.warning(err)\n            return\n        self.mods[name]['module'] = module\n\n    def activate_module(self, name, win):\n        '''Activate a module on a window'''\n        if name not in self.mods:\n            Logger.warning('Modules: Module <%s> not found' % name)\n            return\n\n        mod = self.mods[name]\n\n        # ensure the module has been configured\n        if 'module' not in mod:\n            self._configure_module(name)\n\n        pymod = mod['module']\n        if not mod['activated']:\n            context = mod['context']\n            msg = 'Modules: Start <{0}> with config {1}'.format(\n                  name, context)\n            Logger.debug(msg)\n            pymod.start(win, context)\n            mod['activated'] = True\n\n    def deactivate_module(self, name, win):\n        '''Deactivate a module from a window'''\n        if not name in self.mods:\n            Logger.warning('Modules: Module <%s> not found' % name)\n            return\n        if not 'module' in self.mods[name]:\n            return\n\n        module = self.mods[name]['module']\n        if self.mods[name]['activated']:\n            module.stop(win, self.mods[name]['context'])\n            self.mods[name]['activated'] = False\n\n    def register_window(self, win):\n        '''Add the window to the window list'''\n        if win not in self.wins:\n            self.wins.append(win)\n        self.update()\n\n    def unregister_window(self, win):\n        '''Remove the window from the window list'''\n        if win in self.wins:\n            self.wins.remove(win)\n        self.update()\n\n    def update(self):\n        '''Update the status of the module for each window'''\n        modules_to_activate = [x[0] for x in Config.items('modules')]\n        for win in self.wins:\n            for name in self.mods:\n                if not name in modules_to_activate:\n                    self.deactivate_module(name, win)\n            for name in modules_to_activate:\n                try:\n                    self.activate_module(name, win)\n                except:\n                    import traceback\n                    traceback.print_exc()\n                    raise\n\n    def configure(self):\n        '''(internal) Configure all the modules before using them.\n        '''\n        modules_to_configure = [x[0] for x in Config.items('modules')]\n        for name in modules_to_configure:\n            if name not in self.mods:\n                Logger.warning('Modules: Module <%s> not found' % name)\n                continue\n            self._configure_module(name)\n\n    def _configure_module(self, name):\n        if 'module' not in self.mods[name]:\n            try:\n                self.import_module(name)\n            except ImportError:\n                return\n\n        # convert configuration like:\n        # -m mjpegserver:port=8080,fps=8\n        # and pass it in context.config token\n        config = dict()\n\n        args = Config.get('modules', name)\n        if args != '':\n            values = Config.get('modules', name).split(',')\n            for value in values:\n                x = value.split('=', 1)\n                if len(x) == 1:\n                    config[x[0]] = True\n                else:\n                    config[x[0]] = x[1]\n\n        self.mods[name]['context'].config = config\n\n        # call configure if module have one\n        if hasattr(self.mods[name]['module'], 'configure'):\n            self.mods[name]['module'].configure(config)\n\n    def usage_list(self):\n        print()\n        print('Available modules')\n        print('=================')\n        for module in self.list():\n            if not 'module' in self.mods[module]:\n                self.import_module(module)\n            text = self.mods[module]['module'].__doc__.strip(\"\\n \")\n            print('%-12s: %s' % (module, text))\n        print()\n\nModules = ModuleBase()\nModules.add_path(kivy.kivy_modules_dir)\nif not 'KIVY_DOC' in os.environ:\n    Modules.add_path(kivy.kivy_usermodules_dir)\n\nif __name__ == '__main__':\n    print(Modules.list())\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/modules/_webdebugger.py",
    "content": "# -*- coding: utf-8 -*-\n\nimport threading\nimport json\nfrom gc import get_objects, garbage\nfrom kivy.clock import Clock\nfrom kivy.cache import Cache\nfrom collections import OrderedDict\nfrom kivy.logger import Logger\n\ntry:\n    from flask import Flask, render_template_string, make_response\nexcept ImportError:\n    Logger.error('WebDebugger: unable to import Flask. Install it!')\n    raise\n\nhistory_max = 250\n\n\nclass MissingOrderedDict(OrderedDict):\n\n    def __missing__(self, key):\n        self[key] = [0] * history_max\n        return self[key]\n\n\nmetrics = MissingOrderedDict()\napp = Flask(__name__)\n\n\n@app.route('/')\ndef index():\n    return render_template_string(html_index)\n\n\n@app.route('/metrics.json')\ndef metrics_json():\n    resp = make_response(json.dumps(metrics), 200)\n    resp.headers['Content-Type'] = 'text/json'\n    return resp\n\n\n@app.route('/f/<name>')\ndef getfile(name):\n    name = name.replace('.', '_')\n    text = globals()[name]\n    resp = make_response(text, 200)\n    if name.endswith('_js'):\n        resp.headers['Content-Type'] = 'text/javascript'\n    elif name.endswith('_jpg'):\n        resp.headers['Content-Type'] = 'image/jpeg'\n    return resp\n\n\nclass FlaskThread(threading.Thread):\n\n    def run(self):\n        Clock.schedule_interval(self.dump_metrics, .1)\n        app.run(debug=True, use_debugger=True, use_reloader=False)\n\n    def dump_metrics(self, dt):\n        m = metrics\n        m['Python objects'].append(len(get_objects()))\n        m['Python garbage'].append(len(garbage))\n        m['FPS (internal)'].append(Clock.get_fps())\n        m['FPS (real)'].append(Clock.get_rfps())\n        m['Events'].append(sum([len(x) for x in Clock._events.values()]))\n        for category in Cache._categories:\n            m['Cache ' + category].append(\n                len(Cache._objects.get(category, [])))\n        for values in m.values():\n            values.pop(0)\n            values[0] = 0\n\n\ndef start(win, ctx):\n    ctx.thread = FlaskThread()\n    ctx.thread.daemon = True\n    ctx.thread.start()\n\n\ndef stop(win, ctx):\n    pass\n\n# -----------------------------------------------------------------------------\n# DATA FILES\n# -----------------------------------------------------------------------------\n\nhtml_index = '''\n<html>\n<head>\n<title>Kivy - Web Debugger</title>\n<script type='text/javascript' src='/f/jquery.js'></script>\n<script type='text/javascript' src='/f/raphael.js'></script>\n<script type='text/javascript' src='/f/g_raphael.js'></script>\n<script type='text/javascript' src='/f/g_raphael_line.js'></script>\n<style type='text/css'>\nbody {\n    font-family: Arial, Helvetica, sans-serif;\n    font-size: 13px;\n    color: #eee;\n    background: url('/f/background.jpg') repeat-x #718693;\n}\n\n.panel {\n    width: 400px;\n    float: left;\n    background-color: #BCCAD5;\n    margin: 0px 10px 10px 0px;\n    padding: 20px;\n    -moz-border-radius: 16px;\n    -webkit-border-radius: 16px;\n    border-radius: 16px;\n}\n\n.panel h2 {\n    margin: 0px;\n    padding: 0px 0px 10px 0px;\n    color: #516673;\n}\n\n</style>\n<script type='text/javascript'>\n\nvar graphics = {};\nvar rid = 0;\nvar ids = {}\n\nfunction request_metrics() {\n    $.ajax({\n    url: '/metrics.json',\n    error: function(xhr, status) {\n        $('#error').html('Connection lost').show();\n        setTimeout('request_metrics()', 1000);\n    },\n    success: function(data) {\n        $('#error').hide();\n        for (var key in data) {\n            if ( typeof(graphics[key]) == 'undefined' ) {\n                rid += 1;\n                $('<div class=\"panel panel' + rid + '\"><div id=\"r' + rid + '\"></div></div>').appendTo($('#metrics'));\n                $('.panel' + rid).prepend(\n                    $('<h2 id=\"h' + rid + '\"></h2>').html(key));\n                graphics[key] = Raphael('r' + rid, 400, 150);\n                ids[key] = rid;\n            }\n\n            var indices = [];\n            for (var i = 0; i < data[key].length; i++)\n                indices[i] = i;\n            var r = graphics[key];\n            $('#h'+ids[key]).html(key + ': ' + data[key][i-1]);\n            r.clear();\n            r.linechart(26, 0, 340, 150, indices, data[key], {\n                shade: true, axis: \"0 1 0 1\" });\n        }\n        setTimeout('request_metrics()', 250);\n    }\n    });\n}\n\nrequest_metrics();\n\n</script>\n</head>\n<body>\n<h1>Kivy - Web Debugger</h1>\n<div id='error'></div>\n\n<h2>Metrics</h2>\n<div id='metrics'>\n</div>\n</body>\n</html>\n'''\n\njquery_js = r'''\n/*! jQuery v1.7.1 jquery.com | jquery.org/license */\n(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f(\"<\"+a+\">\").appendTo(b),e=d.css(\"display\");d.remove();if(e===\"none\"||e===\"\"){cl||(cl=c.createElement(\"iframe\"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode===\"CSS1Compat\"?\"<!doctype html>\":\"\")+\"<html><body>\"),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,\"display\"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject(\"Microsoft.XMLHTTP\")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h==\"string\"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k===\"*\")k=l;else if(l!==\"*\"&&l!==k){m=l+\" \"+k,n=e[m]||e[\"* \"+k];if(!n){p=b;for(o in e){j=o.split(\" \");if(j[0]===l||j[0]===\"*\"){p=e[j[1]+\" \"+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error(\"No conversion from \"+m.replace(\" \",\" to \")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function cb(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]===\"*\")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader(\"content-type\"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+\" \"+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function ca(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bE.test(a)?d(a,e):ca(a+\"[\"+(typeof e==\"object\"||f.isArray(e)?b:\"\")+\"]\",e,c,d)});else if(!c&&b!=null&&typeof b==\"object\")for(var e in b)ca(a+\"[\"+e+\"]\",b[e],c,d);else d(a,b)}function b_(a,c){var d,e,g=f.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((g[d]?a:e||(e={}))[d]=c[d]);e&&f.extend(!0,a,e)}function b$(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bT,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l==\"string\"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=b$(a,c,d,e,l,g)));(k||!l)&&!g[\"*\"]&&(l=b$(a,c,d,e,\"*\",g));return l}function bZ(a){return function(b,c){typeof b!=\"string\"&&(c=b,b=\"*\");if(f.isFunction(c)){var d=b.toLowerCase().split(bP),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\\+/.test(h),j&&(h=h.substr(1)||\"*\"),i=a[h]=a[h]||[],i[j?\"unshift\":\"push\"](c)}}}function bC(a,b,c){var d=b===\"width\"?a.offsetWidth:a.offsetHeight,e=b===\"width\"?bx:by,g=0,h=e.length;if(d>0){if(c!==\"border\")for(;g<h;g++)c||(d-=parseFloat(f.css(a,\"padding\"+e[g]))||0),c===\"margin\"?d+=parseFloat(f.css(a,c+e[g]))||0:d-=parseFloat(f.css(a,\"border\"+e[g]+\"Width\"))||0;return d+\"px\"}d=bz(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0;if(c)for(;g<h;g++)d+=parseFloat(f.css(a,\"padding\"+e[g]))||0,c!==\"padding\"&&(d+=parseFloat(f.css(a,\"border\"+e[g]+\"Width\"))||0),c===\"margin\"&&(d+=parseFloat(f.css(a,c+e[g]))||0);return d+\"px\"}function bp(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:\"script\"}):f.globalEval((b.text||b.textContent||b.innerHTML||\"\").replace(bf,\"/*$0*/\")),b.parentNode&&b.parentNode.removeChild(b)}function bo(a){var b=c.createElement(\"div\");bh.appendChild(b),b.innerHTML=a.outerHTML;return b.firstChild}function bn(a){var b=(a.nodeName||\"\").toLowerCase();b===\"input\"?bm(a):b!==\"script\"&&typeof a.getElementsByTagName!=\"undefined\"&&f.grep(a.getElementsByTagName(\"input\"),bm)}function bm(a){if(a.type===\"checkbox\"||a.type===\"radio\")a.defaultChecked=a.checked}function bl(a){return typeof a.getElementsByTagName!=\"undefined\"?a.getElementsByTagName(\"*\"):typeof a.querySelectorAll!=\"undefined\"?a.querySelectorAll(\"*\"):[]}function bk(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c===\"object\")b.outerHTML=a.outerHTML;else if(c!==\"input\"||a.type!==\"checkbox\"&&a.type!==\"radio\"){if(c===\"option\")b.selected=a.defaultSelected;else if(c===\"input\"||c===\"textarea\")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bj(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c,d,e,g=f._data(a),h=f._data(b,g),i=g.events;if(i){delete h.handle,h.events={};for(c in i)for(d=0,e=i[c].length;d<e;d++)f.event.add(b,c+(i[c][d].namespace?\".\":\"\")+i[c][d].namespace,i[c][d],i[c][d].data)}h.data&&(h.data=f.extend({},h.data))}}function bi(a,b){return f.nodeName(a,\"table\")?a.getElementsByTagName(\"tbody\")[0]||a.appendChild(a.ownerDocument.createElement(\"tbody\")):a}function U(a){var b=V.split(\"|\"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function T(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b==\"string\"){var d=f.grep(a,function(a){return a.nodeType===1});if(O.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+\"defer\",e=b+\"queue\",g=b+\"mark\",h=f._data(a,d);h&&(c===\"queue\"||!f._data(a,e))&&(c===\"mark\"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b===\"data\"&&f.isEmptyObject(a[b]))continue;if(b!==\"toJSON\")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e=\"data-\"+c.replace(k,\"-$1\").toLowerCase();d=a.getAttribute(e);if(typeof d==\"string\"){try{d=d===\"true\"?!0:d===\"false\"?!1:d===\"null\"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\\s+/);for(c=0,d=a.length;c<d;c++)b[a[c]]=!0;return b}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll(\"left\")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\\w\\W]+>)[^>]*$|#([\\w\\-]*)$)/,j=/\\S/,k=/^\\s+/,l=/\\s+$/,m=/^<(\\w+)\\s*\\/?>(?:<\\/\\1>)?$/,n=/^[\\],:{}\\s]*$/,o=/\\\\(?:[\"\\\\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/\"[^\"\\\\\\n\\r]*\"|true|false|null|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?/g,q=/(?:^|:|,)(?:\\s*\\[)+/g,r=/(webkit)[ \\/]([\\w.]+)/,s=/(opera)(?:.*version)?[ \\/]([\\w.]+)/,t=/(msie) ([\\w.]+)/,u=/(mozilla)(?:.*? rv:([\\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+\"\").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a===\"body\"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a==\"string\"){a.charAt(0)!==\"<\"||a.charAt(a.length-1)!==\">\"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:\"\",jquery:\"1.7.1\",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b===\"find\"?d.selector=this.selector+(this.selector?\" \":\"\")+c:b&&(d.selector=this.selector+\".\"+b+\"(\"+c+\")\");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),\"slice\",F.call(arguments).join(\",\"))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i==\"boolean\"&&(l=i,i=arguments[1]||{},j=2),typeof i!=\"object\"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger(\"ready\").off(\"ready\")}},bindReady:function(){if(!A){A=e.Callbacks(\"once memory\");if(c.readyState===\"complete\")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener(\"DOMContentLoaded\",B,!1),a.addEventListener(\"load\",e.ready,!1);else if(c.attachEvent){c.attachEvent(\"onreadystatechange\",B),a.attachEvent(\"onload\",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)===\"function\"},isArray:Array.isArray||function(a){return e.type(a)===\"array\"},isWindow:function(a){return a&&typeof a==\"object\"&&\"setInterval\"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||\"object\"},isPlainObject:function(a){if(!a||e.type(a)!==\"object\"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,\"constructor\")&&!D.call(a.constructor.prototype,\"isPrototypeOf\"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!=\"string\"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,\"@\").replace(p,\"]\").replace(q,\"\")))return(new Function(\"return \"+b))();e.error(\"Invalid JSON: \"+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,\"text/xml\")):(d=new ActiveXObject(\"Microsoft.XMLDOM\"),d.async=\"false\",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName(\"parsererror\").length)&&e.error(\"Invalid XML: \"+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,\"ms-\").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:G?function(a){return a==null?\"\":G.call(a)}:function(a){return a==null?\"\":(a+\"\").replace(k,\"\").replace(l,\"\")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d===\"string\"||d===\"function\"||d===\"regexp\"||e.isWindow(a)?E.call(c,a):e.merge(c,a)}return c},inArray:function(a,b,c){var d;if(b){if(H)return H.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length==\"number\")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j==\"number\"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c==\"string\"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=F.call(arguments,2),g=function(){return a.apply(c,f.concat(F.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h){var i=a.length;if(typeof c==\"object\"){for(var j in c)e.access(a,j,c[j],f,g,d);return a}if(d!==b){f=!h&&f&&e.isFunction(d);for(var k=0;k<i;k++)g(a[k],c,f?d.call(a[k],k,g(a[k],c)):d,h);return a}return i?g(a[0],c):b},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf(\"compatible\")<0&&u.exec(a)||[];return{browser:b[1]||\"\",version:b[2]||\"0\"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each(\"Boolean Number String Function Array Date RegExp Object\".split(\" \"),function(a,b){I[\"[object \"+b+\"]\"]=b.toLowerCase()}),z=e.uaMatch(y),z.browser&&(e.browser[z.browser]=!0,e.browser.version=z.version),e.browser.webkit&&(e.browser.safari=!0),j.test(\" \")&&(k=/^[\\s\\xA0]+/,l=/[\\s\\xA0]+$/),h=e(c),c.addEventListener?B=function(){c.removeEventListener(\"DOMContentLoaded\",B,!1),e.ready()}:c.attachEvent&&(B=function(){c.readyState===\"complete\"&&(c.detachEvent(\"onreadystatechange\",B),e.ready())});return e}(),g={};f.Callbacks=function(a){a=a?g[a]||h(a):{};var c=[],d=[],e,i,j,k,l,m=function(b){var d,e,g,h,i;for(d=0,e=b.length;d<e;d++)g=b[d],h=f.type(g),h===\"array\"?m(g):h===\"function\"&&(!a.unique||!o.has(g))&&c.push(g)},n=function(b,f){f=f||[],e=!a.memory||[b,f],i=!0,l=j||0,j=0,k=c.length;for(;c&&l<k;l++)if(c[l].apply(b,f)===!1&&a.stopOnFalse){e=!0;break}i=!1,c&&(a.once?e===!0?o.disable():c=[]:d&&d.length&&(e=d.shift(),o.fireWith(e[0],e[1])))},o={add:function(){if(c){var a=c.length;m(arguments),i?k=c.length:e&&e!==!0&&(j=a,n(e[0],e[1]))}return this},remove:function(){if(c){var b=arguments,d=0,e=b.length;for(;d<e;d++)for(var f=0;f<c.length;f++)if(b[d]===c[f]){i&&f<=k&&(k--,f<=l&&l--),c.splice(f--,1);if(a.unique)break}}return this},has:function(a){if(c){var b=0,d=c.length;for(;b<d;b++)if(a===c[b])return!0}return!1},empty:function(){c=[];return this},disable:function(){c=d=e=b;return this},disabled:function(){return!c},lock:function(){d=b,(!e||e===!0)&&o.disable();return this},locked:function(){return!d},fireWith:function(b,c){d&&(i?a.once||d.push([b,c]):(!a.once||!e)&&n(b,c));return this},fire:function(){o.fireWith(this,arguments);return this},fired:function(){return!!e}};return o};var i=[].slice;f.extend({Deferred:function(a){var b=f.Callbacks(\"once memory\"),c=f.Callbacks(\"once memory\"),d=f.Callbacks(\"memory\"),e=\"pending\",g={resolve:b,reject:c,notify:d},h={done:b.add,fail:c.add,progress:d.add,state:function(){return e},isResolved:b.fired,isRejected:c.fired,then:function(a,b,c){i.done(a).fail(b).progress(c);return this},always:function(){i.done.apply(i,arguments).fail.apply(i,arguments);return this},pipe:function(a,b,c){return f.Deferred(function(d){f.each({done:[a,\"resolve\"],fail:[b,\"reject\"],progress:[c,\"notify\"]},function(a,b){var c=b[0],e=b[1],g;f.isFunction(c)?i[a](function(){g=c.apply(this,arguments),g&&f.isFunction(g.promise)?g.promise().then(d.resolve,d.reject,d.notify):d[e+\"With\"](this===i?d:this,[g])}):i[a](d[e])})}).promise()},promise:function(a){if(a==null)a=h;else for(var b in h)a[b]=h[b];return a}},i=h.promise({}),j;for(j in g)i[j]=g[j].fire,i[j+\"With\"]=g[j].fireWith;i.done(function(){e=\"resolved\"},c.disable,d.lock).fail(function(){e=\"rejected\"},b.disable,d.lock),a&&a.call(i,i);return i},when:function(a){function m(a){return function(b){e[a]=arguments.length>1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c<d;c++)b[c]&&b[c].promise&&f.isFunction(b[c].promise)?b[c].promise().then(l(c),j.reject,m(c)):--g;g||j.resolveWith(j,b)}else j!==a&&j.resolveWith(j,d?[a]:[]);return k}}),f.support=function(){var b,d,e,g,h,i,j,k,l,m,n,o,p,q=c.createElement(\"div\"),r=c.documentElement;q.setAttribute(\"className\",\"t\"),q.innerHTML=\"   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>\",d=q.getElementsByTagName(\"*\"),e=q.getElementsByTagName(\"a\")[0];if(!d||!d.length||!e)return{};g=c.createElement(\"select\"),h=g.appendChild(c.createElement(\"option\")),i=q.getElementsByTagName(\"input\")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName(\"tbody\").length,htmlSerialize:!!q.getElementsByTagName(\"link\").length,style:/top/.test(e.getAttribute(\"style\")),hrefNormalized:e.getAttribute(\"href\")===\"/a\",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value===\"on\",optSelected:h.selected,getSetAttribute:q.className!==\"t\",enctype:!!c.createElement(\"form\").enctype,html5Clone:c.createElement(\"nav\").cloneNode(!0).outerHTML!==\"<:nav></:nav>\",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent(\"onclick\",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent(\"onclick\")),i=c.createElement(\"input\"),i.value=\"t\",i.setAttribute(\"type\",\"radio\"),b.radioValue=i.value===\"t\",i.setAttribute(\"checked\",\"checked\"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML=\"\",a.getComputedStyle&&(j=c.createElement(\"div\"),j.style.width=\"0\",j.style.marginRight=\"0\",q.style.width=\"2px\",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n=\"on\"+o,p=n in q,p||(q.setAttribute(n,\"return;\"),p=typeof q[n]==\"function\"),b[o+\"Bubbles\"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName(\"body\")[0];!r||(j=1,k=\"position:absolute;top:0;left:0;width:1px;height:1px;margin:0;\",m=\"visibility:hidden;border:0;\",n=\"style='\"+k+\"border:5px solid #000;padding:0;'\",o=\"<div \"+n+\"><div></div></div>\"+\"<table \"+n+\" cellpadding='0' cellspacing='0'>\"+\"<tr><td></td></tr></table>\",a=c.createElement(\"div\"),a.style.cssText=m+\"width:0;height:0;position:static;top:0;margin-top:\"+j+\"px\",r.insertBefore(a,r.firstChild),q=c.createElement(\"div\"),a.appendChild(q),q.innerHTML=\"<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>\",l=q.getElementsByTagName(\"td\"),p=l[0].offsetHeight===0,l[0].style.display=\"\",l[1].style.display=\"none\",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML=\"\",q.style.width=q.style.paddingLeft=\"1px\",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!=\"undefined\"&&(q.style.display=\"inline\",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display=\"\",q.innerHTML=\"<div style='width:4px;'></div>\",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position=\"fixed\",e.style.top=\"20px\",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top=\"\",d.style.overflow=\"hidden\",d.style.position=\"relative\",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\\{.*\\}|\\[.*\\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:\"jQuery\"+(f.fn.jquery+Math.random()).replace(/\\D/g,\"\"),noData:{embed:!0,object:\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c==\"string\",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c===\"events\";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c==\"object\"||typeof c==\"function\")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(\" \")));for(e=0,g=b.length;e<g;e++)delete d[b[e]];if(!(c?m:f.isEmptyObject)(d))return}}if(!c){delete j[k].data;if(!m(j[k]))return}f.support.deleteExpando||!j.setInterval?delete j[k]:j[k]=null,i&&(f.support.deleteExpando?delete a[h]:a.removeAttribute?a.removeAttribute(h):a[h]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute(\"classid\")===b}return!0}}),f.fn.extend({data:function(a,c){var d,e,g,h=null;if(typeof a==\"undefined\"){if(this.length){h=f.data(this[0]);if(this[0].nodeType===1&&!f._data(this[0],\"parsedAttrs\")){e=this[0].attributes;for(var i=0,j=e.length;i<j;i++)g=e[i].name,g.indexOf(\"data-\")===0&&(g=f.camelCase(g.substring(5)),l(this[0],g,h[g]));f._data(this[0],\"parsedAttrs\",!0)}}return h}if(typeof a==\"object\")return this.each(function(){f.data(this,a)});d=a.split(\".\"),d[1]=d[1]?\".\"+d[1]:\"\";if(c===b){h=this.triggerHandler(\"getData\"+d[1]+\"!\",[d[0]]),h===b&&this.length&&(h=f.data(this[0],a),h=l(this[0],a,h));return h===b&&d[1]?this.data(d[0]):h}return this.each(function(){var b=f(this),e=[d[0],c];b.triggerHandler(\"setData\"+d[1]+\"!\",e),f.data(this,a,c),b.triggerHandler(\"changeData\"+d[1]+\"!\",e)})},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||\"fx\")+\"mark\",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||\"fx\";var d=c+\"mark\",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,\"mark\"))}},queue:function(a,b,c){var d;if(a){b=(b||\"fx\")+\"queue\",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||\"fx\";var c=f.queue(a,b),d=c.shift(),e={};d===\"inprogress\"&&(d=c.shift()),d&&(b===\"fx\"&&c.unshift(\"inprogress\"),f._data(a,b+\".run\",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+\"queue \"+b+\".run\",!0),n(a,b,\"queue\"))}}),f.fn.extend({queue:function(a,c){typeof a!=\"string\"&&(c=a,a=\"fx\");if(c===b)return f.queue(this[0],a);return this.each(function(){var b=f.queue(this,a,c);a===\"fx\"&&b[0]!==\"inprogress\"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||\"fx\";return this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||\"fx\",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!=\"string\"&&(c=a,a=b),a=a||\"fx\";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+\"defer\",j=a+\"queue\",k=a+\"mark\",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f.Callbacks(\"once memory\"),!0))h++,l.add(m);m();return d.promise()}});var o=/[\\n\\t\\r]/g,p=/\\s+/,q=/\\r/g,r=/^(?:button|input)$/i,s=/^(?:button|input|object|select|textarea)$/i,t=/^a(?:rea)?$/i,u=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,v=f.support.getSetAttribute,w,x,y;f.fn.extend({attr:function(a,b){return f.access(this,a,b,!0,f.attr)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,a,b,!0,f.prop)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a==\"string\"){b=a.split(p);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{g=\" \"+e.className+\" \";for(h=0,i=b.length;h<i;h++)~g.indexOf(\" \"+b[h]+\" \")||(g+=b[h]+\" \");e.className=f.trim(g)}}}return this},removeClass:function(a){var c,d,e,g,h,i,j;if(f.isFunction(a))return this.each(function(b){f(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a==\"string\"||a===b){c=(a||\"\").split(p);for(d=0,e=this.length;d<e;d++){g=this[d];if(g.nodeType===1&&g.className)if(a){h=(\" \"+g.className+\" \").replace(o,\" \");for(i=0,j=c.length;i<j;i++)h=h.replace(\" \"+c[i]+\" \",\" \");g.className=f.trim(h)}else g.className=\"\"}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b==\"boolean\";if(f.isFunction(a))return this.each(function(c){f(this).toggleClass(a.call(this,c,this.className,b),b)});return this.each(function(){if(c===\"string\"){var e,g=0,h=f(this),i=b,j=a.split(p);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?\"addClass\":\"removeClass\"](e)}else if(c===\"undefined\"||c===\"boolean\")this.className&&f._data(this,\"__className__\",this.className),this.className=this.className||a===!1?\"\":f._data(this,\"__className__\")||\"\"})},hasClass:function(a){var b=\" \"+a+\" \",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(\" \"+this[c].className+\" \").replace(o,\" \").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h=\"\":typeof h==\"number\"?h+=\"\":f.isArray(h)&&(h=f.map(h,function(a){return a==null?\"\":a+\"\"})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!(\"set\"in c)||c.set(this,h,\"value\")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&\"get\"in c&&(d=c.get(g,\"value\"))!==b)return d;d=g.value;return typeof d==\"string\"?d.replace(q,\"\"):d==null?\"\":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type===\"select-one\";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c<d;c++){e=i[c];if(e.selected&&(f.support.optDisabled?!e.disabled:e.getAttribute(\"disabled\")===null)&&(!e.parentNode.disabled||!f.nodeName(e.parentNode,\"optgroup\"))){b=f(e).val();if(j)return b;h.push(b)}}if(j&&!h.length&&i.length)return f(i[g]).val();return h},set:function(a,b){var c=f.makeArray(b);f(a).find(\"option\").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute==\"undefined\")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&\"set\"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,\"\"+d);return d}if(h&&\"get\"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h<g;h++)e=d[h],e&&(c=f.propFix[e]||e,f.attr(a,e,\"\"),a.removeAttribute(v?e:c),u.test(e)&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(r.test(a.nodeName)&&a.parentNode)f.error(\"type property can't be changed\");else if(!f.support.radioValue&&b===\"radio\"&&f.nodeName(a,\"input\")){var c=a.value;a.setAttribute(\"type\",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(w&&f.nodeName(a,\"button\"))return w.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(w&&f.nodeName(a,\"button\"))return w.set(a,b,c);a.value=b}}},propFix:{tabindex:\"tabIndex\",readonly:\"readOnly\",\"for\":\"htmlFor\",\"class\":\"className\",maxlength:\"maxLength\",cellspacing:\"cellSpacing\",cellpadding:\"cellPadding\",rowspan:\"rowSpan\",colspan:\"colSpan\",usemap:\"useMap\",frameborder:\"frameBorder\",contenteditable:\"contentEditable\"},prop:function(a,c,d){var e,g,h,i=a.nodeType;if(!!a&&i!==3&&i!==8&&i!==2){h=i!==1||!f.isXMLDoc(a),h&&(c=f.propFix[c]||c,g=f.propHooks[c]);return d!==b?g&&\"set\"in g&&(e=g.set(a,d,c))!==b?e:a[c]=d:g&&\"get\"in g&&(e=g.get(a,c))!==null?e:a[c]}},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode(\"tabindex\");return c&&c.specified?parseInt(c.value,10):s.test(a.nodeName)||t.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabindex=f.propHooks.tabIndex,x={get:function(a,c){var d,e=f.prop(a,c);return e===!0||typeof e!=\"boolean\"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},v||(y={name:!0,id:!0},w=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&(y[c]?d.nodeValue!==\"\":d.specified)?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+\"\"}},f.attrHooks.tabindex.set=w.set,f.each([\"width\",\"height\"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===\"\"){a.setAttribute(b,\"auto\");return c}}})}),f.attrHooks.contenteditable={get:w.get,set:function(a,b,c){b===\"\"&&(b=\"false\"),w.set(a,b,c)}}),f.support.hrefNormalized||f.each([\"href\",\"src\",\"width\",\"height\"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=\"\"+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.enctype||(f.propFix.enctype=\"encoding\"),f.support.checkOn||f.each([\"radio\",\"checkbox\"],function(){f.valHooks[this]={get:function(a){return a.getAttribute(\"value\")===null?\"on\":a.value}}}),f.each([\"radio\",\"checkbox\"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\\.]*)?(?:\\.(.+))?$/,B=/\\bhover(\\.\\S+)?\\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\\w*)(?:#([\\w\\-]+))?(?:\\.([\\w\\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||\"\").toLowerCase(),b[3]=b[3]&&new RegExp(\"(?:^|\\\\s)\"+b[3]+\"(?:\\\\s|$)\"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c[\"class\"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,\"mouseenter$1 mouseleave$1\")};\nf.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!=\"undefined\"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(\" \");for(k=0;k<c.length;k++){l=A.exec(c[k])||[],m=l[1],n=(l[2]||\"\").split(\".\").sort(),s=f.event.special[m]||{},m=(g?s.delegateType:s.bindType)||m,s=f.event.special[m]||{},o=f.extend({type:m,origType:l[1],data:e,handler:d,guid:d.guid,selector:g,quick:G(g),namespace:n.join(\".\")},p),r=j[m];if(!r){r=j[m]=[],r.delegateCount=0;if(!s.setup||s.setup.call(a,e,n,i)===!1)a.addEventListener?a.addEventListener(m,i,!1):a.attachEvent&&a.attachEvent(\"on\"+m,i)}s.add&&(s.add.call(a,o),o.handler.guid||(o.handler.guid=d.guid)),g?r.splice(r.delegateCount++,0,o):r.push(o),f.event.global[m]=!0}a=null}},global:{},remove:function(a,b,c,d,e){var g=f.hasData(a)&&f._data(a),h,i,j,k,l,m,n,o,p,q,r,s;if(!!g&&!!(o=g.events)){b=f.trim(I(b||\"\")).split(\" \");for(h=0;h<b.length;h++){i=A.exec(b[h])||[],j=k=i[1],l=i[2];if(!j){for(j in o)f.event.remove(a,j+b[h],c,d,!0);continue}p=f.event.special[j]||{},j=(d?p.delegateType:p.bindType)||j,r=o[j]||[],m=r.length,l=l?new RegExp(\"(^|\\\\.)\"+l.split(\".\").sort().join(\"\\\\.(?:.*\\\\.)?\")+\"(\\\\.|$)\"):null;for(n=0;n<r.length;n++)s=r[n],(e||k===s.origType)&&(!c||c.guid===s.guid)&&(!l||l.test(s.namespace))&&(!d||d===s.selector||d===\"**\"&&s.selector)&&(r.splice(n--,1),s.selector&&r.delegateCount--,p.remove&&p.remove.call(a,s));r.length===0&&m!==r.length&&((!p.teardown||p.teardown.call(a,l)===!1)&&f.removeEvent(a,j,g.handle),delete o[j])}f.isEmptyObject(o)&&(q=g.handle,q&&(q.elem=null),f.removeData(a,[\"events\",\"handle\"],!0))}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){if(!e||e.nodeType!==3&&e.nodeType!==8){var h=c.type||c,i=[],j,k,l,m,n,o,p,q,r,s;if(E.test(h+f.event.triggered))return;h.indexOf(\"!\")>=0&&(h=h.slice(0,-1),k=!0),h.indexOf(\".\")>=0&&(i=h.split(\".\"),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c==\"object\"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join(\".\"),c.namespace_re=c.namespace?new RegExp(\"(^|\\\\.)\"+i.join(\"\\\\.(?:.*\\\\.)?\")+\"(\\\\.|$)\"):null,o=h.indexOf(\":\")<0?\"on\"+h:\"\";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;l<r.length&&!c.isPropagationStopped();l++)m=r[l][0],c.type=r[l][1],q=(f._data(m,\"events\")||{})[c.type]&&f._data(m,\"handle\"),q&&q.apply(m,d),q=o&&m[o],q&&f.acceptData(m)&&q.apply(m,d)===!1&&c.preventDefault();c.type=h,!g&&!c.isDefaultPrevented()&&(!p._default||p._default.apply(e.ownerDocument,d)===!1)&&(h!==\"click\"||!f.nodeName(e,\"a\"))&&f.acceptData(e)&&o&&e[h]&&(h!==\"focus\"&&h!==\"blur\"||c.target.offsetWidth!==0)&&!f.isWindow(e)&&(n=e[o],n&&(e[o]=null),f.event.triggered=h,e[h](),f.event.triggered=b,n&&(e[o]=n));return c.result}},dispatch:function(c){c=f.event.fix(c||a.event);var d=(f._data(this,\"events\")||{})[c.type]||[],e=d.delegateCount,g=[].slice.call(arguments,0),h=!c.exclusive&&!c.namespace,i=[],j,k,l,m,n,o,p,q,r,s,t;g[0]=c,c.delegateTarget=this;if(e&&!c.target.disabled&&(!c.button||c.type!==\"click\")){m=f(this),m.context=this.ownerDocument||this;for(l=c.target;l!=this;l=l.parentNode||this){o={},q=[],m[0]=l;for(j=0;j<e;j++)r=d[j],s=r.selector,o[s]===b&&(o[s]=r.quick?H(l,r.quick):m.is(s)),o[s]&&q.push(r);q.length&&i.push({elem:l,matches:q})}}d.length>e&&i.push({elem:this,matches:d.slice(e)});for(j=0;j<i.length&&!c.isPropagationStopped();j++){p=i[j],c.currentTarget=p.elem;for(k=0;k<p.matches.length&&!c.isImmediatePropagationStopped();k++){r=p.matches[k];if(h||!c.namespace&&!r.namespace||c.namespace_re&&c.namespace_re.test(r.namespace))c.data=r.data,c.handleObj=r,n=((f.event.special[r.origType]||{}).handle||r.handler).apply(p.elem,g),n!==b&&(c.result=n,n===!1&&(c.preventDefault(),c.stopPropagation()))}}return c.result},props:\"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which\".split(\" \"),fixHooks:{},keyHooks:{props:\"char charCode key keyCode\".split(\" \"),filter:function(a,b){a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode);return a}},mouseHooks:{props:\"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement\".split(\" \"),filter:function(a,d){var e,f,g,h=d.button,i=d.fromElement;a.pageX==null&&d.clientX!=null&&(e=a.target.ownerDocument||c,f=e.documentElement,g=e.body,a.pageX=d.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=d.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?d.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0);return a}},fix:function(a){if(a[f.expando])return a;var d,e,g=a,h=f.event.fixHooks[a.type]||{},i=h.props?this.props.concat(h.props):this.props;a=f.Event(g);for(d=i.length;d;)e=i[--d],a[e]=g[e];a.target||(a.target=g.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey===b&&(a.metaKey=a.ctrlKey);return h.filter?h.filter(a,g):a},special:{ready:{setup:f.bindReady},load:{noBubble:!0},focus:{delegateType:\"focusin\"},blur:{delegateType:\"focusout\"},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=f.extend(new f.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?f.event.trigger(e,null,b):f.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},f.event.handle=f.event.dispatch,f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent(\"on\"+b,c)},f.Event=function(a,b){if(!(this instanceof f.Event))return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?K:J):this.type=a,b&&f.extend(this,b),this.timeStamp=a&&a.timeStamp||f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=K;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=K;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=K,this.stopPropagation()},isDefaultPrevented:J,isPropagationStopped:J,isImmediatePropagationStopped:J},f.each({mouseenter:\"mouseover\",mouseleave:\"mouseout\"},function(a,b){f.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c=this,d=a.relatedTarget,e=a.handleObj,g=e.selector,h;if(!d||d!==c&&!f.contains(c,d))a.type=e.origType,h=e.handler.apply(this,arguments),a.type=b;return h}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(){if(f.nodeName(this,\"form\"))return!1;f.event.add(this,\"click._submit keypress._submit\",function(a){var c=a.target,d=f.nodeName(c,\"input\")||f.nodeName(c,\"button\")?c.form:b;d&&!d._submit_attached&&(f.event.add(d,\"submit._submit\",function(a){this.parentNode&&!a.isTrigger&&f.event.simulate(\"submit\",this.parentNode,a,!0)}),d._submit_attached=!0)})},teardown:function(){if(f.nodeName(this,\"form\"))return!1;f.event.remove(this,\"._submit\")}}),f.support.changeBubbles||(f.event.special.change={setup:function(){if(z.test(this.nodeName)){if(this.type===\"checkbox\"||this.type===\"radio\")f.event.add(this,\"propertychange._change\",function(a){a.originalEvent.propertyName===\"checked\"&&(this._just_changed=!0)}),f.event.add(this,\"click._change\",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1,f.event.simulate(\"change\",this,a,!0))});return!1}f.event.add(this,\"beforeactivate._change\",function(a){var b=a.target;z.test(b.nodeName)&&!b._change_attached&&(f.event.add(b,\"change._change\",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&f.event.simulate(\"change\",this.parentNode,a,!0)}),b._change_attached=!0)})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!==\"radio\"&&b.type!==\"checkbox\")return a.handleObj.handler.apply(this,arguments)},teardown:function(){f.event.remove(this,\"._change\");return z.test(this.nodeName)}}),f.support.focusinBubbles||f.each({focus:\"focusin\",blur:\"focusout\"},function(a,b){var d=0,e=function(a){f.event.simulate(b,a.target,f.event.fix(a),!0)};f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.fn.extend({on:function(a,c,d,e,g){var h,i;if(typeof a==\"object\"){typeof c!=\"string\"&&(d=c,c=b);for(i in a)this.on(i,c,d,a[i],g);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c==\"string\"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=J;else if(!e)return this;g===1&&(h=e,e=function(a){f().off(a);return h.apply(this,arguments)},e.guid=h.guid||(h.guid=f.guid++));return this.each(function(){f.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on.call(this,a,b,c,d,1)},off:function(a,c,d){if(a&&a.preventDefault&&a.handleObj){var e=a.handleObj;f(a.delegateTarget).off(e.namespace?e.type+\".\"+e.namespace:e.type,e.selector,e.handler);return this}if(typeof a==\"object\"){for(var g in a)this.off(g,c,a[g]);return this}if(c===!1||typeof c==\"function\")d=c,c=b;d===!1&&(d=J);return this.each(function(){f.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){f(this.context).on(a,this.selector,b,c);return this},die:function(a,b){f(this.context).off(a,this.selector||\"**\",b);return this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length==1?this.off(a,\"**\"):this.off(b,a,c)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f._data(this,\"lastToggle\"+a.guid)||0)%d;f._data(this,\"lastToggle\"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),f.each(\"blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu\".split(\" \"),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}if(j.nodeType===1){g||(j[d]=c,j.sizset=h);if(typeof b!=\"string\"){if(j===b){k=!0;break}}else if(m.filter(b,[j]).length>0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}j.nodeType===1&&!g&&(j[d]=c,j.sizset=h);if(j.nodeName.toLowerCase()===b){k=j;break}j=j[a]}e[h]=k}}}var a=/((?:\\((?:\\([^()]+\\)|[^()]+)+\\)|\\[(?:\\[[^\\[\\]]*\\]|['\"][^'\"]*['\"]|[^\\[\\]'\"]+)+\\]|\\\\.|[^ >+~,(\\[\\\\]+)+|[>+~])(\\s*,\\s*)?((?:.|\\r|\\n)*)/g,d=\"sizcache\"+(Math.random()+\"\").replace(\".\",\"\"),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\\\/g,k=/\\r\\n/g,l=/\\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!=\"string\")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(\"\"),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]===\"~\"||w[0]===\"+\")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q=\"\",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)===\"[object Array]\")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},m.matches=function(a,b){return m(a,null,null,b)},m.matchesSelector=function(a,b){return m(b,null,null,[a]).length>0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e<f;e++){h=o.order[e];if(g=o.leftMatch[h].exec(a)){i=g[1],g.splice(1,1);if(i.substr(i.length-1)!==\"\\\\\"){g[1]=(g[1]||\"\").replace(j,\"\"),d=o.find[h](g,b,c);if(d!=null){a=a.replace(o.match[h],\"\");break}}}}d||(d=typeof b.getElementsByTagName!=\"undefined\"?b.getElementsByTagName(\"*\"):[]);return{set:d,expr:a}},m.filter=function(a,c,d,e){var f,g,h,i,j,k,l,n,p,q=a,r=[],s=c,t=c&&c[0]&&m.isXML(c[0]);while(a&&c.length){for(h in o.filter)if((f=o.leftMatch[h].exec(a))!=null&&f[2]){k=o.filter[h],l=f[1],g=!1,f.splice(1,1);if(l.substr(l.length-1)===\"\\\\\")continue;s===r&&(r=[]);if(o.preFilter[h]){f=o.preFilter[h](f,s,d,r,e,t);if(!f)g=i=!0;else if(f===!0)continue}if(f)for(n=0;(j=s[n])!=null;n++)j&&(i=k(j,f,n,s),p=e^i,d&&i!=null?p?g=!0:s[n]=!1:p&&(r.push(j),g=!0));if(i!==b){d||(s=r),a=a.replace(o.match[h],\"\");if(!g)return[];break}}if(a===q)if(g==null)m.error(a);else break;q=a}return s},m.error=function(a){throw new Error(\"Syntax error, unrecognized expression: \"+a)};var n=m.getText=function(a){var b,c,d=a.nodeType,e=\"\";if(d){if(d===1||d===9){if(typeof a.textContent==\"string\")return a.textContent;if(typeof a.innerText==\"string\")return a.innerText.replace(k,\"\");for(a=a.firstChild;a;a=a.nextSibling)e+=n(a)}else if(d===3||d===4)return a.nodeValue}else for(b=0;c=a[b];b++)c.nodeType!==8&&(e+=n(c));return e},o=m.selectors={order:[\"ID\",\"NAME\",\"TAG\"],match:{ID:/#((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)/,CLASS:/\\.((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)/,NAME:/\\[name=['\"]*((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)['\"]*\\]/,ATTR:/\\[\\s*((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)\\s*(?:(\\S?=)\\s*(?:(['\"])(.*?)\\3|(#?(?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)*)|)|)\\s*\\]/,TAG:/^((?:[\\w\\u00c0-\\uFFFF\\*\\-]|\\\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\\(\\s*(even|odd|(?:[+\\-]?\\d+|(?:[+\\-]?\\d*)?n\\s*(?:[+\\-]\\s*\\d+)?))\\s*\\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\))?(?=[^\\-]|$)/,PSEUDO:/:((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)(?:\\((['\"]?)((?:\\([^\\)]+\\)|[^\\(\\)]*)+)\\2\\))?/},leftMatch:{},attrMap:{\"class\":\"className\",\"for\":\"htmlFor\"},attrHandle:{href:function(a){return a.getAttribute(\"href\")},type:function(a){return a.getAttribute(\"type\")}},relative:{\"+\":function(a,b){var c=typeof b==\"string\",d=c&&!l.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&m.filter(b,a,!0)},\">\":function(a,b){var c,d=typeof b==\"string\",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&m.filter(b,a,!0)}},\"\":function(a,b,c){var d,f=e++,g=x;typeof b==\"string\"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g(\"parentNode\",b,f,a,d,c)},\"~\":function(a,b,c){var d,f=e++,g=x;typeof b==\"string\"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g(\"previousSibling\",b,f,a,d,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!=\"undefined\"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!=\"undefined\"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute(\"name\")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!=\"undefined\")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=\" \"+a[1].replace(j,\"\")+\" \";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(\" \"+h.className+\" \").replace(/[\\t\\n\\r]/g,\" \").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,\"\")},TAG:function(a,b){return a[1].replace(j,\"\").toLowerCase()},CHILD:function(a){if(a[1]===\"nth\"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\\+|\\s*/g,\"\");var b=/(-?)(\\d*)(?:n([+\\-]?\\d*))?/.exec(a[2]===\"even\"&&\"2n\"||a[2]===\"odd\"&&\"2n+1\"||!/\\D/.test(a[2])&&\"0n+\"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,\"\");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||\"\").replace(j,\"\"),a[2]===\"~=\"&&(a[4]=\" \"+a[4]+\" \");return a},PSEUDO:function(b,c,d,e,f){if(b[1]===\"not\")if((a.exec(b[3])||\"\").length>1||/^\\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!==\"hidden\"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute(\"type\"),c=a.type;return a.nodeName.toLowerCase()===\"input\"&&\"text\"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()===\"input\"&&\"radio\"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()===\"input\"&&\"checkbox\"===a.type},file:function(a){return a.nodeName.toLowerCase()===\"input\"&&\"file\"===a.type},password:function(a){return a.nodeName.toLowerCase()===\"input\"&&\"password\"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b===\"input\"||b===\"button\")&&\"submit\"===a.type},image:function(a){return a.nodeName.toLowerCase()===\"input\"&&\"image\"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b===\"input\"||b===\"button\")&&\"reset\"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b===\"input\"&&\"button\"===a.type||b===\"button\"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e===\"contains\")return(a.textContent||a.innerText||n([a])||\"\").indexOf(b[3])>=0;if(e===\"not\"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}m.error(e)},CHILD:function(a,b){var c,e,f,g,h,i,j,k=b[1],l=a;switch(k){case\"only\":case\"first\":while(l=l.previousSibling)if(l.nodeType===1)return!1;if(k===\"first\")return!0;l=a;case\"last\":while(l=l.nextSibling)if(l.nodeType===1)return!1;return!0;case\"nth\":c=b[2],e=b[3];if(c===1&&e===0)return!0;f=b[0],g=a.parentNode;if(g&&(g[d]!==f||!a.nodeIndex)){i=0;for(l=g.firstChild;l;l=l.nextSibling)l.nodeType===1&&(l.nodeIndex=++i);g[d]=f}j=a.nodeIndex-e;return c===0?j===0:j%c===0&&j/c>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute(\"id\")===b},TAG:function(a,b){return b===\"*\"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(\" \"+(a.className||a.getAttribute(\"class\"))+\" \").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+\"\",f=b[2],g=b[4];return d==null?f===\"!=\":!f&&m.attr?d!=null:f===\"=\"?e===g:f===\"*=\"?e.indexOf(g)>=0:f===\"~=\"?(\" \"+e+\" \").indexOf(g)>=0:g?f===\"!=\"?e!==g:f===\"^=\"?e.indexOf(g)===0:f===\"$=\"?e.substr(e.length-g.length)===g:f===\"|=\"?e===g||e.substr(0,g.length+1)===g+\"-\":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return\"\\\\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\\[]*\\])(?![^\\(]*\\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\\r|\\n)*?)/.source+o.match[r].source.replace(/\\\\(\\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)===\"[object Array]\")Array.prototype.push.apply(d,a);else if(typeof a.length==\"number\")for(var e=a.length;c<e;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var u,v;c.documentElement.compareDocumentPosition?u=function(a,b){if(a===b){h=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(u=function(a,b){if(a===b){h=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,i=b.parentNode,j=g;if(g===i)return v(a,b);if(!g)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return v(e[k],f[k]);return k===c?v(a,f[k],-1):v(e[k],b,1)},v=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),function(){var a=c.createElement(\"div\"),d=\"script\"+(new Date).getTime(),e=c.documentElement;a.innerHTML=\"<a name='\"+d+\"'/>\",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!=\"undefined\"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!=\"undefined\"&&e.getAttributeNode(\"id\").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!=\"undefined\"&&a.getAttributeNode(\"id\");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement(\"div\");a.appendChild(c.createComment(\"\")),a.getElementsByTagName(\"*\").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]===\"*\"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML=\"<a href='#'></a>\",a.firstChild&&typeof a.firstChild.getAttribute!=\"undefined\"&&a.firstChild.getAttribute(\"href\")!==\"#\"&&(o.attrHandle.href=function(a){return a.getAttribute(\"href\",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement(\"div\"),d=\"__sizzle__\";b.innerHTML=\"<p class='TEST'></p>\";if(!b.querySelectorAll||b.querySelectorAll(\".TEST\").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\\w+$)|^\\.([\\w\\-]+$)|^#([\\w\\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b===\"body\"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!==\"object\"){var k=e,l=e.getAttribute(\"id\"),n=l||d,p=e.parentNode,q=/^\\s*[+~]/.test(b);l?n=n.replace(/'/g,\"\\\\$&\"):e.setAttribute(\"id\",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll(\"[id='\"+n+\"'] \"+b),f)}catch(r){}finally{l||k.removeAttribute(\"id\")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement(\"div\"),\"div\"),e=!1;try{b.call(c.documentElement,\"[test!='']:sizzle\")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\\=\\s*([^'\"\\]]*)\\s*\\]/g,\"='$1']\");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement(\"div\");a.innerHTML=\"<div class='test e'></div><div class='test'></div>\";if(!!a.getElementsByClassName&&a.getElementsByClassName(\"e\").length!==0){a.lastChild.className=\"e\";if(a.getElementsByClassName(\"e\").length===1)return;o.order.splice(1,0,\"CLASS\"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!=\"undefined\"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!==\"HTML\":!1};var y=function(a,b,c){var d,e=[],f=\"\",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,\"\");a=o.relative[a]?a+\"*\":a;for(var h=0,i=g.length;h<i;h++)m(a,g[h],e,c);return m.filter(f,e)};m.attr=f.attr,m.selectors.attrMap={},f.find=m,f.expr=m.selectors,f.expr[\":\"]=f.expr.filters,f.unique=m.uniqueSort,f.text=m.getText,f.isXMLDoc=m.isXML,f.contains=m.contains}();var L=/Until$/,M=/^(?:parents|prevUntil|prevAll)/,N=/,/,O=/^.[^:#\\[\\.,]*$/,P=Array.prototype.slice,Q=f.expr.match.POS,R={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!=\"string\")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack(\"\",\"find\",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(T(this,a,!1),\"not\",a)},filter:function(a){return this.pushStack(T(this,a,!0),\"filter\",a)},is:function(a){return!!a&&(typeof a==\"string\"?Q.test(a)?f(a,this.context).index(this[0])>=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d<a.length;d++)f(g).is(a[d])&&c.push({selector:a[d],elem:g,level:h});g=g.parentNode,h++}return c}var i=Q.test(a)||typeof a!=\"string\"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(i?i.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,\"closest\",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a==\"string\")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a==\"string\"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,\"parentNode\")},parentsUntil:function(a,b,c){return f.dir(a,\"parentNode\",c)},next:function(a){return f.nth(a,2,\"nextSibling\")},prev:function(a){return f.nth(a,2,\"previousSibling\")},nextAll:function(a){return f.dir(a,\"nextSibling\")},prevAll:function(a){return f.dir(a,\"previousSibling\")},nextUntil:function(a,b,c){return f.dir(a,\"nextSibling\",c)},prevUntil:function(a,b,c){return f.dir(a,\"previousSibling\",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,\"iframe\")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d==\"string\"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(\",\"))}}),f.extend({filter:function(a,b,c){c&&(a=\":not(\"+a+\")\");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V=\"abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video\",W=/ jQuery\\d+=\"(?:\\d+|null)\"/g,X=/^\\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:]+)[^>]*)\\/>/ig,Z=/<([\\w:]+)/,$=/<tbody/i,_=/<|&#?\\w+;/,ba=/<(?:script|style)/i,bb=/<(?:script|object|embed|option|style)/i,bc=new RegExp(\"<(?:\"+V+\")\",\"i\"),bd=/checked\\s*(?:[^=]|=\\s*.checked.)/i,be=/\\/(java|ecma)script/i,bf=/^\\s*<!(?:\\[CDATA\\[|\\-\\-)/,bg={option:[1,\"<select multiple='multiple'>\",\"</select>\"],legend:[1,\"<fieldset>\",\"</fieldset>\"],thead:[1,\"<table>\",\"</table>\"],tr:[2,\"<table><tbody>\",\"</tbody></table>\"],td:[3,\"<table><tbody><tr>\",\"</tr></tbody></table>\"],col:[2,\"<table><tbody></tbody><colgroup>\",\"</colgroup></table>\"],area:[1,\"<map>\",\"</map>\"],_default:[0,\"\",\"\"]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,\"div<div>\",\"</div>\"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!=\"object\"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,\"body\")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,\"before\",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,\"after\",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName(\"*\")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function()\n{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName(\"*\"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,\"\"):null;if(typeof a==\"string\"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||[\"\",\"\"])[1].toLowerCase()]){a=a.replace(Y,\"<$1></$2>\");try{for(var c=0,d=this.length;c<d;c++)this[c].nodeType===1&&(f.cleanData(this[c].getElementsByTagName(\"*\")),this[c].innerHTML=a)}catch(e){this.empty().append(a)}}else f.isFunction(a)?this.each(function(b){var c=f(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!=\"string\"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),\"replaceWith\",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j==\"string\"&&bd.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,\"tr\");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bi(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,bp)}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i,j=a[0];b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof j==\"string\"&&j.length<512&&i===c&&j.charAt(0)===\"<\"&&!bb.test(j)&&(f.support.checkClone||!bd.test(j))&&(f.support.html5Clone||!bc.test(j))&&(g=!0,h=f.fragments[j],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean(a,i,e,d)),g&&(f.fragments[j]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:\"append\",prependTo:\"prepend\",insertBefore:\"before\",insertAfter:\"after\",replaceAll:\"replaceWith\"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test(\"<\"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement==\"undefined\"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k==\"number\"&&(k+=\"\");if(!k)continue;if(typeof k==\"string\")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,\"<$1></$2>\");var l=(Z.exec(k)||[\"\",\"\"])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement(\"div\");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l===\"table\"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===\"<table>\"&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],\"tbody\")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)==\"number\")for(i=0;i<r;i++)bn(k[i]);else bn(k);k.nodeType?h.push(k):h=f.merge(h,k)}if(d){g=function(a){return!a.type||be.test(a.type)};for(j=0;h[j];j++)if(e&&f.nodeName(h[j],\"script\")&&(!h[j].type||h[j].type.toLowerCase()===\"text/javascript\"))e.push(h[j].parentNode?h[j].parentNode.removeChild(h[j]):h[j]);else{if(h[j].nodeType===1){var s=f.grep(h[j].getElementsByTagName(\"script\"),g);h.splice.apply(h,[j+1,0].concat(s))}d.appendChild(h[j])}}return h},cleanData:function(a){var b,c,d=f.cache,e=f.event.special,g=f.support.deleteExpando;for(var h=0,i;(i=a[h])!=null;h++){if(i.nodeName&&f.noData[i.nodeName.toLowerCase()])continue;c=i[f.expando];if(c){b=d[c];if(b&&b.events){for(var j in b.events)e[j]?f.event.remove(i,j):f.removeEvent(i,j,b.handle);b.handle&&(b.handle.elem=null)}g?delete i[f.expando]:i.removeAttribute&&i.removeAttribute(f.expando),delete d[c]}}}});var bq=/alpha\\([^)]*\\)/i,br=/opacity=([^)]*)/,bs=/([A-Z]|^ms)/g,bt=/^-?\\d+(?:px)?$/i,bu=/^-?\\d/,bv=/^([\\-+])=([\\-+.\\de]+)/,bw={position:\"absolute\",visibility:\"hidden\",display:\"block\"},bx=[\"Left\",\"Right\"],by=[\"Top\",\"Bottom\"],bz,bA,bB;f.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return f.access(this,a,c,!0,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)})},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bz(a,\"opacity\",\"opacity\");return c===\"\"?\"1\":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{\"float\":f.support.cssFloat?\"cssFloat\":\"styleFloat\"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&\"get\"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h===\"string\"&&(g=bv.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h=\"number\");if(d==null||h===\"number\"&&isNaN(d))return;h===\"number\"&&!f.cssNumber[i]&&(d+=\"px\");if(!k||!(\"set\"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c===\"cssFloat\"&&(c=\"float\");if(g&&\"get\"in g&&(e=g.get(a,!0,d))!==b)return e;if(bz)return bz(a,c)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]}}),f.curCSS=f.css,f.each([\"height\",\"width\"],function(a,b){f.cssHooks[b]={get:function(a,c,d){var e;if(c){if(a.offsetWidth!==0)return bC(a,b,d);f.swap(a,bw,function(){e=bC(a,b,d)});return e}},set:function(a,b){if(!bt.test(b))return b;b=parseFloat(b);if(b>=0)return b+\"px\"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||\"\")?parseFloat(RegExp.$1)/100+\"\":b?\"1\":\"\"},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?\"alpha(opacity=\"+b*100+\")\":\"\",g=d&&d.filter||c.filter||\"\";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,\"\"))===\"\"){c.removeAttribute(\"filter\");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+\" \"+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:\"inline-block\"},function(){b?c=bz(a,\"margin-right\",\"marginRight\"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,\"-$1\").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===\"\"&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b===\"fontSize\"?\"1em\":f||0,f=g.pixelLeft+\"px\",g.left=c,d&&(a.runtimeStyle.left=d));return f===\"\"?\"auto\":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,\"display\"))===\"none\"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\\[\\]$/,bF=/\\r?\\n/g,bG=/#.*$/,bH=/^(.*?):[ \\t]*([^\\r\\n]*)\\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\\-storage|.+\\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\\/\\//,bM=/\\?/,bN=/<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\\w\\+\\.\\-]+:)(?:\\/\\/([^\\/?#:]*)(?::(\\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=[\"*/\"]+[\"*\"];try{bV=e.href}catch(bY){bV=c.createElement(\"a\"),bV.href=\"\",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!=\"string\"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(\" \");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h=\"GET\";c&&(f.isFunction(c)?(d=c,c=b):typeof c==\"object\"&&(c=f.param(c,f.ajaxSettings.traditional),h=\"POST\"));var i=this;f.ajax({url:a,type:h,dataType:\"html\",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f(\"<div>\").append(c.replace(bN,\"\")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,\"\\r\\n\")}}):{name:b.name,value:c.replace(bF,\"\\r\\n\")}}).get()}}),f.each(\"ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend\".split(\" \"),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each([\"get\",\"post\"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,\"script\")},getJSON:function(a,b,c){return f.get(a,b,c,\"json\")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:\"GET\",contentType:\"application/x-www-form-urlencoded\",processData:!0,async:!0,accepts:{xml:\"application/xml, text/xml\",html:\"text/html\",text:\"text/plain\",json:\"application/json, text/javascript\",\"*\":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:\"responseXML\",text:\"responseText\"},converters:{\"* text\":a.String,\"text html\":!0,\"text json\":f.parseJSON,\"text xml\":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||\"\",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader(\"Last-Modified\"))f.lastModified[k]=y;if(z=v.getResponseHeader(\"Etag\"))f.etag[k]=z}if(a===304)w=\"notmodified\",o=!0;else try{r=cc(d,x),w=\"success\",o=!0}catch(A){w=\"parsererror\",u=A}}else{u=w;if(!w||a)w=\"error\",a<0&&(a=0)}v.status=a,v.statusText=\"\"+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger(\"ajax\"+(o?\"Success\":\"Error\"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger(\"ajaxComplete\",[v,d]),--f.active||f.event.trigger(\"ajaxStop\"))}}typeof a==\"object\"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks(\"once memory\"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||\"abort\",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+\"\").replace(bG,\"\").replace(bL,bW[1]+\"//\"),d.dataTypes=f.trim(d.dataType||\"*\").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]===\"http:\"?80:443))==(bW[3]||(bW[1]===\"http:\"?80:443)))),d.data&&d.processData&&typeof d.data!=\"string\"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger(\"ajaxStart\");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?\"&\":\"?\")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,\"$1_=\"+x);d.url=y+(y===d.url?(bM.test(d.url)?\"&\":\"?\")+\"_=\"+x:\"\")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader(\"Content-Type\",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader(\"If-Modified-Since\",f.lastModified[k]),f.etag[k]&&v.setRequestHeader(\"If-None-Match\",f.etag[k])),v.setRequestHeader(\"Accept\",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!==\"*\"?\", \"+bX+\"; q=0.01\":\"\"):d.accepts[\"*\"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,\"No Transport\");else{v.readyState=1,t&&g.trigger(\"ajaxSend\",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort(\"timeout\")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+\"=\"+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join(\"&\").replace(bD,\"+\")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\\=)\\?(&|$)|\\?\\?/i;f.ajaxSetup({jsonp:\"callback\",jsonpCallback:function(){return f.expando+\"_\"+cd++}}),f.ajaxPrefilter(\"json jsonp\",function(b,c,d){var e=b.contentType===\"application/x-www-form-urlencoded\"&&typeof b.data==\"string\";if(b.dataTypes[0]===\"jsonp\"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l=\"$1\"+h+\"$2\";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\\?/.test(j)?\"&\":\"?\")+b.jsonp+\"=\"+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters[\"script json\"]=function(){g||f.error(h+\" was not called\");return g[0]},b.dataTypes[0]=\"json\";return\"script\"}}),f.ajaxSetup({accepts:{script:\"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"},contents:{script:/javascript|ecmascript/},converters:{\"text script\":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter(\"script\",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type=\"GET\",a.global=!1)}),f.ajaxTransport(\"script\",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName(\"head\")[0]||c.documentElement;return{send:function(f,g){d=c.createElement(\"script\"),d.async=\"async\",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,\"success\")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&\"withCredentials\"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e[\"X-Requested-With\"]&&(e[\"X-Requested-With\"]=\"XMLHttpRequest\");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=\"\"}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\\-]=)?([\\d+.\\-]+)([a-z%]*)$/i,cp,cq=[[\"height\",\"marginTop\",\"marginBottom\",\"paddingTop\",\"paddingBottom\"],[\"width\",\"marginLeft\",\"marginRight\",\"paddingLeft\",\"paddingRight\"],[\"opacity\"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu(\"show\",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,\"olddisplay\")&&e===\"none\"&&(e=d.style.display=\"\"),e===\"\"&&f.css(d,\"display\")===\"none\"&&f._data(d,\"olddisplay\",cv(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===\"\"||e===\"none\")d.style.display=f._data(d,\"olddisplay\")||\"\"}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(cu(\"hide\",3),a,b,c);var d,e,g=0,h=this.length;for(;g<h;g++)d=this[g],d.style&&(e=f.css(d,\"display\"),e!==\"none\"&&!f._data(d,\"olddisplay\")&&f._data(d,\"olddisplay\",e));for(g=0;g<h;g++)this[g].style&&(this[g].style.display=\"none\");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a==\"boolean\";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(\":hidden\");f(this)[b?\"show\":\"hide\"]()}):this.animate(cu(\"toggle\",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(\":hidden\").css(\"opacity\",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){function g(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(\":hidden\"),g,h,i,j,k,l,m,n,o;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]),h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||\"swing\";if(h===\"hide\"&&d||h===\"show\"&&!d)return b.complete.call(this);c&&(g===\"height\"||g===\"width\")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,\"display\")===\"inline\"&&f.css(this,\"float\")===\"none\"&&(!f.support.inlineBlockNeedsLayout||cv(this.nodeName)===\"inline\"?this.style.display=\"inline-block\":this.style.zoom=1))}b.overflow!=null&&(this.style.overflow=\"hidden\");for(i in a)j=new f.fx(this,b,i),h=a[i],cn.test(h)?(o=f._data(this,\"toggle\"+i)||(h===\"toggle\"?d?\"show\":\"hide\":0),o?(f._data(this,\"toggle\"+i,o===\"show\"?\"hide\":\"show\"),j[o]()):j[h]()):(k=co.exec(h),l=j.cur(),k?(m=parseFloat(k[2]),n=k[3]||(f.cssNumber[i]?\"\":\"px\"),n!==\"px\"&&(f.style(this,i,(m||1)+n),l=(m||1)/j.cur()*l,f.style(this,i,l+n)),k[1]&&(m=(k[1]===\"-=\"?-1:1)*m+l),j.custom(l,m,n)):j.custom(l,h,\"\"));return!0}var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return e.queue===!1?this.each(g):this.queue(e.queue,g)},stop:function(a,c,d){typeof a!=\"string\"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||\"fx\",[]);return this.each(function(){function h(a,b,c){var e=b[c];f.removeData(a,c,!0),e.stop(d)}var b,c=!1,e=f.timers,g=f._data(this);d||f._unmark(!0,this);if(a==null)for(b in g)g[b]&&g[b].stop&&b.indexOf(\".run\")===b.length-4&&h(this,g,b);else g[b=a+\".run\"]&&g[b].stop&&h(this,g,b);for(b=e.length;b--;)e[b].elem===this&&(a==null||e[b].queue===a)&&(d?e[b](!0):e[b].saveState(),c=!0,e.splice(b,1));(!d||!c)&&f.dequeue(this,a)})}}),f.each({slideDown:cu(\"show\",1),slideUp:cu(\"hide\",1),slideToggle:cu(\"toggle\",1),fadeIn:{opacity:\"show\"},fadeOut:{opacity:\"hide\"},fadeToggle:{opacity:\"toggle\"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a==\"object\"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration==\"number\"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue=\"fx\";d.old=d.complete,d.complete=function(a){f.isFunction(d.old)&&d.old.call(this),d.queue?f.dequeue(this,d.queue):a!==!1&&f._unmark(this)};return d},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b===\"auto\"?0:b:a},custom:function(a,c,d){function h(a){return e.step(a)}var e=this,g=f.fx;this.startTime=cr||cs(),this.end=c,this.now=this.start=a,this.pos=this.state=0,this.unit=d||this.unit||(f.cssNumber[this.prop]?\"\":\"px\"),h.queue=this.options.queue,h.elem=this.elem,h.saveState=function(){e.options.hide&&f._data(e.elem,\"fxshow\"+e.prop)===b&&f._data(e.elem,\"fxshow\"+e.prop,e.start)},h()&&f.timers.push(h)&&!cp&&(cp=setInterval(g.tick,g.interval))},show:function(){var a=f._data(this.elem,\"fxshow\"+this.prop);this.options.orig[this.prop]=a||f.style(this.elem,this.prop),this.options.show=!0,a!==b?this.custom(this.cur(),a):this.custom(this.prop===\"width\"||this.prop===\"height\"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f._data(this.elem,\"fxshow\"+this.prop)||f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b,c,d,e=cr||cs(),g=!0,h=this.elem,i=this.options;if(a||e>=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each([\"\",\"X\",\"Y\"],function(a,b){h.style[\"overflow\"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,\"fxshow\"+b,!0),f.removeData(h,\"toggle\"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||f.fx.stop()},interval:13,stop:function(){clearInterval(cp),cp=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,\"opacity\",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=a.now+a.unit:a.elem[a.prop]=a.now}}}),f.each([\"width\",\"height\"],function(a,b){f.fx.step[b]=function(a){f.style(a.elem,b,Math.max(0,a.now)+a.unit)}}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var cw=/^t(?:able|d|h)$/i,cx=/^(?:body|html)$/i;\"getBoundingClientRect\"in c.documentElement?f.fn.offset=function(a){var b=this[0],c;if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);try{c=b.getBoundingClientRect()}catch(d){}var e=b.ownerDocument,g=e.documentElement;if(!c||!f.contains(g,b))return c?{top:c.top,left:c.left}:{top:0,left:0};var h=e.body,i=cy(e),j=g.clientTop||h.clientTop||0,k=g.clientLeft||h.clientLeft||0,l=i.pageYOffset||f.support.boxModel&&g.scrollTop||h.scrollTop,m=i.pageXOffset||f.support.boxModel&&g.scrollLeft||h.scrollLeft,n=c.top+l-j,o=c.left+m-k;return{top:n,left:o}}:f.fn.offset=function(a){var b=this[0];if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);var c,d=b.offsetParent,e=b,g=b.ownerDocument,h=g.documentElement,i=g.body,j=g.defaultView,k=j?j.getComputedStyle(b,null):b.currentStyle,l=b.offsetTop,m=b.offsetLeft;while((b=b.parentNode)&&b!==i&&b!==h){if(f.support.fixedPosition&&k.position===\"fixed\")break;c=j?j.getComputedStyle(b,null):b.currentStyle,l-=b.scrollTop,m-=b.scrollLeft,b===d&&(l+=b.offsetTop,m+=b.offsetLeft,f.support.doesNotAddBorder&&(!f.support.doesAddBorderForTableAndCells||!cw.test(b.nodeName))&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),e=d,d=b.offsetParent),f.support.subtractsBorderForOverflowNotVisible&&c.overflow!==\"visible\"&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),k=c}if(k.position===\"relative\"||k.position===\"static\")l+=i.offsetTop,m+=i.offsetLeft;f.support.fixedPosition&&k.position===\"fixed\"&&(l+=Math.max(h.scrollTop,i.scrollTop),m+=Math.max(h.scrollLeft,i.scrollLeft));return{top:l,left:m}},f.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,\"marginTop\"))||0,c+=parseFloat(f.css(a,\"marginLeft\"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,\"position\");d===\"static\"&&(a.style.position=\"relative\");var e=f(a),g=e.offset(),h=f.css(a,\"top\"),i=f.css(a,\"left\"),j=(d===\"absolute\"||d===\"fixed\")&&f.inArray(\"auto\",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),\"using\"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,\"marginTop\"))||0,c.left-=parseFloat(f.css(a,\"marginLeft\"))||0,d.top+=parseFloat(f.css(b[0],\"borderTopWidth\"))||0,d.left+=parseFloat(f.css(b[0],\"borderLeftWidth\"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,\"position\")===\"static\")a=a.offsetParent;return a})}}),f.each([\"Left\",\"Top\"],function(a,c){var d=\"scroll\"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?\"pageXOffset\"in g?g[a?\"pageYOffset\":\"pageXOffset\"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each([\"Height\",\"Width\"],function(a,c){var d=c.toLowerCase();f.fn[\"inner\"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,\"padding\")):this[d]():null},f.fn[\"outer\"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?\"margin\":\"border\")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement[\"client\"+c],h=e.document.body;return e.document.compatMode===\"CSS1Compat\"&&g||h&&h[\"client\"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement[\"client\"+c],e.body[\"scroll\"+c],e.documentElement[\"scroll\"+c],e.body[\"offset\"+c],e.documentElement[\"offset\"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a==\"string\"?a:a+\"px\")}}),a.jQuery=a.$=f,typeof define==\"function\"&&define.amd&&define.amd.jQuery&&define(\"jquery\",[],function(){return f})})(window);\n'''\n\ng_raphael_js = r'''\nRaphael.el.popup=function(d,k,h,g){var c=this.paper||this[0].paper,f,j,b,e,a;if(!c){return}switch(this.type){case\"text\":case\"circle\":case\"ellipse\":b=true;break;default:b=false}d=d==null?\"up\":d;k=k||5;f=this.getBBox();h=typeof h==\"number\"?h:(b?f.x+f.width/2:f.x);g=typeof g==\"number\"?g:(b?f.y+f.height/2:f.y);e=Math.max(f.width/2-k,0);a=Math.max(f.height/2-k,0);this.translate(h-f.x-(b?f.width/2:0),g-f.y-(b?f.height/2:0));f=this.getBBox();var i={up:[\"M\",h,g,\"l\",-k,-k,-e,0,\"a\",k,k,0,0,1,-k,-k,\"l\",0,-f.height,\"a\",k,k,0,0,1,k,-k,\"l\",k*2+e*2,0,\"a\",k,k,0,0,1,k,k,\"l\",0,f.height,\"a\",k,k,0,0,1,-k,k,\"l\",-e,0,\"z\"].join(\",\"),down:[\"M\",h,g,\"l\",k,k,e,0,\"a\",k,k,0,0,1,k,k,\"l\",0,f.height,\"a\",k,k,0,0,1,-k,k,\"l\",-(k*2+e*2),0,\"a\",k,k,0,0,1,-k,-k,\"l\",0,-f.height,\"a\",k,k,0,0,1,k,-k,\"l\",e,0,\"z\"].join(\",\"),left:[\"M\",h,g,\"l\",-k,k,0,a,\"a\",k,k,0,0,1,-k,k,\"l\",-f.width,0,\"a\",k,k,0,0,1,-k,-k,\"l\",0,-(k*2+a*2),\"a\",k,k,0,0,1,k,-k,\"l\",f.width,0,\"a\",k,k,0,0,1,k,k,\"l\",0,a,\"z\"].join(\",\"),right:[\"M\",h,g,\"l\",k,-k,0,-a,\"a\",k,k,0,0,1,k,-k,\"l\",f.width,0,\"a\",k,k,0,0,1,k,k,\"l\",0,k*2+a*2,\"a\",k,k,0,0,1,-k,k,\"l\",-f.width,0,\"a\",k,k,0,0,1,-k,-k,\"l\",0,-a,\"z\"].join(\",\")};j={up:{x:-!b*(f.width/2),y:-k*2-(b?f.height/2:f.height)},down:{x:-!b*(f.width/2),y:k*2+(b?f.height/2:f.height)},left:{x:-k*2-(b?f.width/2:f.width),y:-!b*(f.height/2)},right:{x:k*2+(b?f.width/2:f.width),y:-!b*(f.height/2)}}[d];this.translate(j.x,j.y);return c.path(i[d]).attr({fill:\"#000\",stroke:\"none\"}).insertBefore(this.node?this:this[0])};Raphael.el.tag=function(f,b,l,k){var i=3,e=this.paper||this[0].paper;if(!e){return}var c=e.path().attr({fill:\"#000\",stroke:\"#000\"}),j=this.getBBox(),m,h,a,g;switch(this.type){case\"text\":case\"circle\":case\"ellipse\":a=true;break;default:a=false}f=f||0;l=typeof l==\"number\"?l:(a?j.x+j.width/2:j.x);k=typeof k==\"number\"?k:(a?j.y+j.height/2:j.y);b=b==null?5:b;h=0.5522*b;if(j.height>=b*2){c.attr({path:[\"M\",l,k+b,\"a\",b,b,0,1,1,0,-b*2,b,b,0,1,1,0,b*2,\"m\",0,-b*2-i,\"a\",b+i,b+i,0,1,0,0,(b+i)*2,\"L\",l+b+i,k+j.height/2+i,\"l\",j.width+2*i,0,0,-j.height-2*i,-j.width-2*i,0,\"L\",l,k-b-i].join(\",\")})}else{m=Math.sqrt(Math.pow(b+i,2)-Math.pow(j.height/2+i,2));c.attr({path:[\"M\",l,k+b,\"c\",-h,0,-b,h-b,-b,-b,0,-h,b-h,-b,b,-b,h,0,b,b-h,b,b,0,h,h-b,b,-b,b,\"M\",l+m,k-j.height/2-i,\"a\",b+i,b+i,0,1,0,0,j.height+2*i,\"l\",b+i-m+j.width+2*i,0,0,-j.height-2*i,\"L\",l+m,k-j.height/2-i].join(\",\")})}f=360-f;c.rotate(f,l,k);if(this.attrs){this.attr(this.attrs.x?\"x\":\"cx\",l+b+i+(!a?this.type==\"text\"?j.width:0:j.width/2)).attr(\"y\",a?k:k-j.height/2);this.rotate(f,l,k);f>90&&f<270&&this.attr(this.attrs.x?\"x\":\"cx\",l-b-i-(!a?j.width:j.width/2)).rotate(180,l,k)}else{if(f>90&&f<270){this.translate(l-j.x-j.width-b-i,k-j.y-j.height/2);this.rotate(f-180,j.x+j.width+b+i,j.y+j.height/2)}else{this.translate(l-j.x+b+i,k-j.y-j.height/2);this.rotate(f,j.x-b-i,j.y+j.height/2)}}return c.insertBefore(this.node?this:this[0])};Raphael.el.drop=function(d,g,f){var e=this.getBBox(),c=this.paper||this[0].paper,a,j,b,i,h;if(!c){return}switch(this.type){case\"text\":case\"circle\":case\"ellipse\":a=true;break;default:a=false}d=d||0;g=typeof g==\"number\"?g:(a?e.x+e.width/2:e.x);f=typeof f==\"number\"?f:(a?e.y+e.height/2:e.y);j=Math.max(e.width,e.height)+Math.min(e.width,e.height);b=c.path([\"M\",g,f,\"l\",j,0,\"A\",j*0.4,j*0.4,0,1,0,g+j*0.7,f-j*0.7,\"z\"]).attr({fill:\"#000\",stroke:\"none\"}).rotate(22.5-d,g,f);d=(d+90)*Math.PI/180;i=(g+j*Math.sin(d))-(a?0:e.width/2);h=(f+j*Math.cos(d))-(a?0:e.height/2);this.attrs?this.attr(this.attrs.x?\"x\":\"cx\",i).attr(this.attrs.y?\"y\":\"cy\",h):this.translate(i-e.x,h-e.y);return b.insertBefore(this.node?this:this[0])};Raphael.el.flag=function(e,k,j){var g=3,c=this.paper||this[0].paper;if(!c){return}var b=c.path().attr({fill:\"#000\",stroke:\"#000\"}),i=this.getBBox(),f=i.height/2,a;switch(this.type){case\"text\":case\"circle\":case\"ellipse\":a=true;break;default:a=false}e=e||0;k=typeof k==\"number\"?k:(a?i.x+i.width/2:i.x);j=typeof j==\"number\"?j:(a?i.y+i.height/2:i.y);b.attr({path:[\"M\",k,j,\"l\",f+g,-f-g,i.width+2*g,0,0,i.height+2*g,-i.width-2*g,0,\"z\"].join(\",\")});e=360-e;b.rotate(e,k,j);if(this.attrs){this.attr(this.attrs.x?\"x\":\"cx\",k+f+g+(!a?this.type==\"text\"?i.width:0:i.width/2)).attr(\"y\",a?j:j-i.height/2);this.rotate(e,k,j);e>90&&e<270&&this.attr(this.attrs.x?\"x\":\"cx\",k-f-g-(!a?i.width:i.width/2)).rotate(180,k,j)}else{if(e>90&&e<270){this.translate(k-i.x-i.width-f-g,j-i.y-i.height/2);this.rotate(e-180,i.x+i.width+f+g,i.y+i.height/2)}else{this.translate(k-i.x+f+g,j-i.y-i.height/2);this.rotate(e,i.x-f-g,i.y+i.height/2)}}return b.insertBefore(this.node?this:this[0])};Raphael.el.label=function(){var c=this.getBBox(),b=this.paper||this[0].paper,a=Math.min(20,c.width+10,c.height+10)/2;if(!b){return}return b.rect(c.x-a/2,c.y-a/2,c.width+a,c.height+a,a).attr({stroke:\"none\",fill:\"#000\"}).insertBefore(this.node?this:this[0])};Raphael.el.blob=function(z,j,i){var g=this.getBBox(),B=Math.PI/180,n=this.paper||this[0].paper,r,A,q;if(!n){return}switch(this.type){case\"text\":case\"circle\":case\"ellipse\":A=true;break;default:A=false}r=n.path().attr({fill:\"#000\",stroke:\"none\"});z=(+z+1?z:45)+90;q=Math.min(g.height,g.width);j=typeof j==\"number\"?j:(A?g.x+g.width/2:g.x);i=typeof i==\"number\"?i:(A?g.y+g.height/2:g.y);var m=Math.max(g.width+q,q*25/12),t=Math.max(g.height+q,q*25/12),u=j+q*Math.sin((z-22.5)*B),b=i+q*Math.cos((z-22.5)*B),v=j+q*Math.sin((z+22.5)*B),d=i+q*Math.cos((z+22.5)*B),o=(v-u)/2,l=(d-b)/2,f=m/2,e=t/2,s=-Math.sqrt(Math.abs(f*f*e*e-f*f*l*l-e*e*o*o)/(f*f*l*l+e*e*o*o)),c=s*f*l/e+(v+u)/2,a=s*-e*o/f+(d+b)/2;r.attr({x:c,y:a,path:[\"M\",j,i,\"L\",v,d,\"A\",f,e,0,1,1,u,b,\"z\"].join(\",\")});this.translate(c-g.x-g.width/2,a-g.y-g.height/2);return r.insertBefore(this.node?this:this[0])};Raphael.fn.label=function(a,d,b){var c=this.set();b=this.text(a,d,b).attr(Raphael.g.txtattr);return c.push(b.label(),b)};Raphael.fn.popup=function(a,f,d,b,c){var e=this.set();d=this.text(a,f,d).attr(Raphael.g.txtattr);return e.push(d.popup(b,c),d)};Raphael.fn.tag=function(a,f,d,c,b){var e=this.set();d=this.text(a,f,d).attr(Raphael.g.txtattr);return e.push(d.tag(c,b),d)};Raphael.fn.flag=function(a,e,c,b){var d=this.set();c=this.text(a,e,c).attr(Raphael.g.txtattr);return d.push(c.flag(b),c)};Raphael.fn.drop=function(a,e,c,b){var d=this.set();c=this.text(a,e,c).attr(Raphael.g.txtattr);return d.push(c.drop(b),c)};Raphael.fn.blob=function(a,e,c,b){var d=this.set();c=this.text(a,e,c).attr(Raphael.g.txtattr);return d.push(c.blob(b),c)};Raphael.el.lighter=function(b){b=b||2;var a=[this.attrs.fill,this.attrs.stroke];this.fs=this.fs||[a[0],a[1]];a[0]=Raphael.rgb2hsb(Raphael.getRGB(a[0]).hex);a[1]=Raphael.rgb2hsb(Raphael.getRGB(a[1]).hex);a[0].b=Math.min(a[0].b*b,1);a[0].s=a[0].s/b;a[1].b=Math.min(a[1].b*b,1);a[1].s=a[1].s/b;this.attr({fill:\"hsb(\"+[a[0].h,a[0].s,a[0].b]+\")\",stroke:\"hsb(\"+[a[1].h,a[1].s,a[1].b]+\")\"});return this};Raphael.el.darker=function(b){b=b||2;var a=[this.attrs.fill,this.attrs.stroke];this.fs=this.fs||[a[0],a[1]];a[0]=Raphael.rgb2hsb(Raphael.getRGB(a[0]).hex);a[1]=Raphael.rgb2hsb(Raphael.getRGB(a[1]).hex);a[0].s=Math.min(a[0].s*b,1);a[0].b=a[0].b/b;a[1].s=Math.min(a[1].s*b,1);a[1].b=a[1].b/b;this.attr({fill:\"hsb(\"+[a[0].h,a[0].s,a[0].b]+\")\",stroke:\"hsb(\"+[a[1].h,a[1].s,a[1].b]+\")\"});return this};Raphael.el.resetBrightness=function(){if(this.fs){this.attr({fill:this.fs[0],stroke:this.fs[1]});delete this.fs}return this};(function(){var c=[\"lighter\",\"darker\",\"resetBrightness\"],a=[\"popup\",\"tag\",\"flag\",\"label\",\"drop\",\"blob\"];for(var b in a){(function(d){Raphael.st[d]=function(){return Raphael.el[d].apply(this,arguments)}})(a[b])}for(var b in c){(function(d){Raphael.st[d]=function(){for(var e=0;e<this.length;e++){this[e][d].apply(this[e],arguments)}return this}})(c[b])}})();Raphael.g={shim:{stroke:\"none\",fill:\"#000\",\"fill-opacity\":0},txtattr:{font:\"12px Arial, sans-serif\",fill:\"#fff\"},colors:(function(){var c=[0.6,0.2,0.05,0.1333,0.75,0],a=[];for(var b=0;b<10;b++){if(b<c.length){a.push(\"hsb(\"+c[b]+\",.75, .75)\")}else{a.push(\"hsb(\"+c[b-c.length]+\", 1, .5)\")}}return a})(),snapEnds:function(j,k,h){var e=j,l=k;if(e==l){return{from:e,to:l,power:0}}function m(d){return Math.abs(d-0.5)<0.25?~~(d)+0.5:Math.round(d)}var g=(l-e)/h,a=~~(g),c=a,b=0;if(a){while(c){b--;c=~~(g*Math.pow(10,b))/Math.pow(10,b)}b++}else{while(!a){b=b||1;a=~~(g*Math.pow(10,b))/Math.pow(10,b);b++}b&&b--}l=m(k*Math.pow(10,b))/Math.pow(10,b);if(l<k){l=m((k+0.5)*Math.pow(10,b))/Math.pow(10,b)}e=m((j-(b>0?0:0.5))*Math.pow(10,b))/Math.pow(10,b);return{from:e,to:l,power:b}},axis:function(p,o,k,D,e,G,g,J,h,a,q){a=a==null?2:a;h=h||\"t\";G=G||10;q=arguments[arguments.length-1];var C=h==\"|\"||h==\" \"?[\"M\",p+0.5,o,\"l\",0,0.001]:g==1||g==3?[\"M\",p+0.5,o,\"l\",0,-k]:[\"M\",p,o+0.5,\"l\",k,0],s=this.snapEnds(D,e,G),H=s.from,z=s.to,F=s.power,E=0,w={font:\"11px 'Fontin Sans', Fontin-Sans, sans-serif\"},v=q.set(),I;I=(z-H)/G;var n=H,m=F>0?F:0;r=k/G;if(+g==1||+g==3){var b=o,u=(g-1?1:-1)*(a+3+!!(g-1));while(b>=o-k){h!=\"-\"&&h!=\" \"&&(C=C.concat([\"M\",p-(h==\"+\"||h==\"|\"?a:!(g-1)*a*2),b+0.5,\"l\",a*2+1,0]));v.push(q.text(p+u,b,(J&&J[E++])||(Math.round(n)==n?n:+n.toFixed(m))).attr(w).attr({\"text-anchor\":g-1?\"start\":\"end\"}));n+=I;b-=r}if(Math.round(b+r-(o-k))){h!=\"-\"&&h!=\" \"&&(C=C.concat([\"M\",p-(h==\"+\"||h==\"|\"?a:!(g-1)*a*2),o-k+0.5,\"l\",a*2+1,0]));v.push(q.text(p+u,o-k,(J&&J[E])||(Math.round(n)==n?n:+n.toFixed(m))).attr(w).attr({\"text-anchor\":g-1?\"start\":\"end\"}))}}else{n=H;m=(F>0)*F;u=(g?-1:1)*(a+9+!g);var c=p,r=k/G,A=0,B=0;while(c<=p+k){h!=\"-\"&&h!=\" \"&&(C=C.concat([\"M\",c+0.5,o-(h==\"+\"?a:!!g*a*2),\"l\",0,a*2+1]));v.push(A=q.text(c,o+u,(J&&J[E++])||(Math.round(n)==n?n:+n.toFixed(m))).attr(w));var l=A.getBBox();if(B>=l.x-5){v.pop(v.length-1).remove()}else{B=l.x+l.width}n+=I;c+=r}if(Math.round(c-r-p-k)){h!=\"-\"&&h!=\" \"&&(C=C.concat([\"M\",p+k+0.5,o-(h==\"+\"?a:!!g*a*2),\"l\",0,a*2+1]));v.push(q.text(p+k,o+u,(J&&J[E])||(Math.round(n)==n?n:+n.toFixed(m))).attr(w))}}var K=q.path(C);K.text=v;K.all=q.set([K,v]);K.remove=function(){this.text.remove();this.constructor.prototype.remove.call(this)};return K},labelise:function(a,c,b){if(a){return(a+\"\").replace(/(##+(?:\\.#+)?)|(%%+(?:\\.%+)?)/g,function(d,f,e){if(f){return(+c).toFixed(f.replace(/^#+\\.?/g,\"\").length)}if(e){return(c*100/b).toFixed(e.replace(/^%+\\.?/g,\"\").length)+\"%\"}})}else{return(+c).toFixed(0)}}};\n'''\n\ng_raphael_line_js = r'''\n(function(){function a(g,n){var f=g.length/n,h=0,e=f,m=0,i=[];while(h<g.length){e--;if(e<0){m+=g[h]*(1+e);i.push(m/f);m=g[h++]*-e;e+=f}else{m+=g[h++]}}return i}function d(f,e,p,n,k,j){var h=(p-f)/2,g=(k-p)/2,q=Math.atan((p-f)/Math.abs(n-e)),o=Math.atan((k-p)/Math.abs(n-j));q=e<n?Math.PI-q:q;o=j<n?Math.PI-o:o;var i=Math.PI/2-((q+o)%(Math.PI*2))/2,s=h*Math.sin(i+q),m=h*Math.cos(i+q),r=g*Math.sin(i+o),l=g*Math.cos(i+o);return{x1:p-s,y1:n+m,x2:p+r,y2:n+l}}function b(f,P,O,e,h,A,z,J){var s=this;J=J||{};if(!f.raphael.is(A[0],\"array\")){A=[A]}if(!f.raphael.is(z[0],\"array\")){z=[z]}var q=J.gutter||10,B=Math.max(A[0].length,z[0].length),t=J.symbol||\"\",S=J.colors||s.colors,v=null,p=null,ad=f.set(),T=[];for(var ac=0,L=z.length;ac<L;ac++){B=Math.max(B,z[ac].length)}var ae=f.set();for(ac=0,L=z.length;ac<L;ac++){if(J.shade){ae.push(f.path().attr({stroke:\"none\",fill:S[ac],opacity:J.nostroke?1:0.3}))}if(z[ac].length>e-2*q){z[ac]=a(z[ac],e-2*q);B=e-2*q}if(A[ac]&&A[ac].length>e-2*q){A[ac]=a(A[ac],e-2*q)}}var W=Array.prototype.concat.apply([],A),U=Array.prototype.concat.apply([],z),u=s.snapEnds(Math.min.apply(Math,W),Math.max.apply(Math,W),A[0].length-1),E=u.from,o=u.to,N=s.snapEnds(Math.min.apply(Math,U),Math.max.apply(Math,U),z[0].length-1),C=N.from,n=N.to,Z=(e-q*2)/((o-E)||1),V=(h-q*2)/((n-C)||1);var G=f.set();if(J.axis){var m=(J.axis+\"\").split(/[,\\s]+/);+m[0]&&G.push(s.axis(P+q,O+q,e-2*q,E,o,J.axisxstep||Math.floor((e-2*q)/20),2,f));+m[1]&&G.push(s.axis(P+e-q,O+h-q,h-2*q,C,n,J.axisystep||Math.floor((h-2*q)/20),3,f));+m[2]&&G.push(s.axis(P+q,O+h-q,e-2*q,E,o,J.axisxstep||Math.floor((e-2*q)/20),0,f));+m[3]&&G.push(s.axis(P+q,O+h-q,h-2*q,C,n,J.axisystep||Math.floor((h-2*q)/20),1,f))}var M=f.set(),aa=f.set(),r;for(ac=0,L=z.length;ac<L;ac++){if(!J.nostroke){M.push(r=f.path().attr({stroke:S[ac],\"stroke-width\":J.width||2,\"stroke-linejoin\":\"round\",\"stroke-linecap\":\"round\",\"stroke-dasharray\":J.dash||\"\"}))}var g=Raphael.is(t,\"array\")?t[ac]:t,H=f.set();T=[];for(var ab=0,w=z[ac].length;ab<w;ab++){var l=P+q+((A[ac]||A[0])[ab]-E)*Z,k=O+h-q-(z[ac][ab]-C)*V;(Raphael.is(g,\"array\")?g[ab]:g)&&H.push(f[Raphael.is(g,\"array\")?g[ab]:g](l,k,(J.width||2)*3).attr({fill:S[ac],stroke:\"none\"}));if(J.smooth){if(ab&&ab!=w-1){var R=P+q+((A[ac]||A[0])[ab-1]-E)*Z,F=O+h-q-(z[ac][ab-1]-C)*V,Q=P+q+((A[ac]||A[0])[ab+1]-E)*Z,D=O+h-q-(z[ac][ab+1]-C)*V,af=d(R,F,l,k,Q,D);T=T.concat([af.x1,af.y1,l,k,af.x2,af.y2])}if(!ab){T=[\"M\",l,k,\"C\",l,k]}}else{T=T.concat([ab?\"L\":\"M\",l,k])}}if(J.smooth){T=T.concat([l,k,l,k])}aa.push(H);if(J.shade){ae[ac].attr({path:T.concat([\"L\",l,O+h-q,\"L\",P+q+((A[ac]||A[0])[0]-E)*Z,O+h-q,\"z\"]).join(\",\")})}!J.nostroke&&r.attr({path:T.join(\",\")})}function K(an){var ak=[];for(var al=0,ap=A.length;al<ap;al++){ak=ak.concat(A[al])}ak.sort();var aq=[],ah=[];for(al=0,ap=ak.length;al<ap;al++){ak[al]!=ak[al-1]&&aq.push(ak[al])&&ah.push(P+q+(ak[al]-E)*Z)}ak=aq;ap=ak.length;var ag=an||f.set();for(al=0;al<ap;al++){var Y=ah[al]-(ah[al]-(ah[al-1]||P))/2,ao=((ah[al+1]||P+e)-ah[al])/2+(ah[al]-(ah[al-1]||P))/2,x;an?(x={}):ag.push(x=f.rect(Y-1,O,Math.max(ao+1,1),h).attr({stroke:\"none\",fill:\"#000\",opacity:0}));x.values=[];x.symbols=f.set();x.y=[];x.x=ah[al];x.axis=ak[al];for(var aj=0,am=z.length;aj<am;aj++){aq=A[aj]||A[0];for(var ai=0,y=aq.length;ai<y;ai++){if(aq[ai]==ak[al]){x.values.push(z[aj][ai]);x.y.push(O+h-q-(z[aj][ai]-C)*V);x.symbols.push(ad.symbols[aj][ai])}}}an&&an.call(x)}!an&&(v=ag)}function I(al){var ah=al||f.set(),x;for(var aj=0,an=z.length;aj<an;aj++){for(var ai=0,ak=z[aj].length;ai<ak;ai++){var ag=P+q+((A[aj]||A[0])[ai]-E)*Z,am=P+q+((A[aj]||A[0])[ai?ai-1:1]-E)*Z,y=O+h-q-(z[aj][ai]-C)*V;al?(x={}):ah.push(x=f.circle(ag,y,Math.abs(am-ag)/2).attr({stroke:\"none\",fill:\"#000\",opacity:0}));x.x=ag;x.y=y;x.value=z[aj][ai];x.line=ad.lines[aj];x.shade=ad.shades[aj];x.symbol=ad.symbols[aj][ai];x.symbols=ad.symbols[aj];x.axis=(A[aj]||A[0])[ai];al&&al.call(x)}}!al&&(p=ah)}ad.push(M,ae,aa,G,v,p);ad.lines=M;ad.shades=ae;ad.symbols=aa;ad.axis=G;ad.hoverColumn=function(j,i){!v&&K();v.mouseover(j).mouseout(i);return this};ad.clickColumn=function(i){!v&&K();v.click(i);return this};ad.hrefColumn=function(Y){var ag=f.raphael.is(arguments[0],\"array\")?arguments[0]:arguments;if(!(arguments.length-1)&&typeof Y==\"object\"){for(var j in Y){for(var y=0,X=v.length;y<X;y++){if(v[y].axis==j){v[y].attr(\"href\",Y[j])}}}}!v&&K();for(y=0,X=ag.length;y<X;y++){v[y]&&v[y].attr(\"href\",ag[y])}return this};ad.hover=function(j,i){!p&&I();p.mouseover(j).mouseout(i);return this};ad.click=function(i){!p&&I();p.click(i);return this};ad.each=function(i){I(i);return this};ad.eachColumn=function(i){K(i);return this};return ad}var c=function(){};c.prototype=Raphael.g;b.prototype=new c;Raphael.fn.linechart=function(f,k,g,e,j,i,h){return new b(this,f,k,g,e,j,i,h)}})();\n'''\n\nraphael_js = r'''\n(function(a){var b=\"0.3.4\",c=\"hasOwnProperty\",d=/[\\.\\/]/,e=\"*\",f=function(){},g=function(a,b){return a-b},h,i,j={n:{}},k=function(a,b){var c=j,d=i,e=Array.prototype.slice.call(arguments,2),f=k.listeners(a),l=0,m=!1,n,o=[],p={},q=[],r=h,s=[];h=a,i=0;for(var t=0,u=f.length;t<u;t++)\"zIndex\"in f[t]&&(o.push(f[t].zIndex),f[t].zIndex<0&&(p[f[t].zIndex]=f[t]));o.sort(g);while(o[l]<0){n=p[o[l++]],q.push(n.apply(b,e));if(i){i=d;return q}}for(t=0;t<u;t++){n=f[t];if(\"zIndex\"in n)if(n.zIndex==o[l]){q.push(n.apply(b,e));if(i)break;do{l++,n=p[o[l]],n&&q.push(n.apply(b,e));if(i)break}while(n)}else p[n.zIndex]=n;else{q.push(n.apply(b,e));if(i)break}}i=d,h=r;return q.length?q:null};k.listeners=function(a){var b=a.split(d),c=j,f,g,h,i,k,l,m,n,o=[c],p=[];for(i=0,k=b.length;i<k;i++){n=[];for(l=0,m=o.length;l<m;l++){c=o[l].n,g=[c[b[i]],c[e]],h=2;while(h--)f=g[h],f&&(n.push(f),p=p.concat(f.f||[]))}o=n}return p},k.on=function(a,b){var c=a.split(d),e=j;for(var g=0,h=c.length;g<h;g++)e=e.n,!e[c[g]]&&(e[c[g]]={n:{}}),e=e[c[g]];e.f=e.f||[];for(g=0,h=e.f.length;g<h;g++)if(e.f[g]==b)return f;e.f.push(b);return function(a){+a==+a&&(b.zIndex=+a)}},k.stop=function(){i=1},k.nt=function(a){if(a)return(new RegExp(\"(?:\\\\.|\\\\/|^)\"+a+\"(?:\\\\.|\\\\/|$)\")).test(h);return h},k.off=k.unbind=function(a,b){var f=a.split(d),g,h,i,k,l,m,n,o=[j];for(k=0,l=f.length;k<l;k++)for(m=0;m<o.length;m+=i.length-2){i=[m,1],g=o[m].n;if(f[k]!=e)g[f[k]]&&i.push(g[f[k]]);else for(h in g)g[c](h)&&i.push(g[h]);o.splice.apply(o,i)}for(k=0,l=o.length;k<l;k++){g=o[k];while(g.n){if(b){if(g.f){for(m=0,n=g.f.length;m<n;m++)if(g.f[m]==b){g.f.splice(m,1);break}!g.f.length&&delete g.f}for(h in g.n)if(g.n[c](h)&&g.n[h].f){var p=g.n[h].f;for(m=0,n=p.length;m<n;m++)if(p[m]==b){p.splice(m,1);break}!p.length&&delete g.n[h].f}}else{delete g.f;for(h in g.n)g.n[c](h)&&g.n[h].f&&delete g.n[h].f}g=g.n}}},k.once=function(a,b){var c=function(){var d=b.apply(this,arguments);k.unbind(a,c);return d};return k.on(a,c)},k.version=b,k.toString=function(){return\"You are running Eve \"+b},typeof module!=\"undefined\"&&module.exports?module.exports=k:typeof define!=\"undefined\"?define(\"eve\",[],function(){return k}):a.eve=k})(this),function(){function cF(a){for(var b=0;b<cy.length;b++)cy[b].el.paper==a&&cy.splice(b--,1)}function cE(b,d,e,f,h,i){e=Q(e);var j,k,l,m=[],o,p,q,t=b.ms,u={},v={},w={};if(f)for(y=0,z=cy.length;y<z;y++){var x=cy[y];if(x.el.id==d.id&&x.anim==b){x.percent!=e?(cy.splice(y,1),l=1):k=x,d.attr(x.totalOrigin);break}}else f=+v;for(var y=0,z=b.percents.length;y<z;y++){if(b.percents[y]==e||b.percents[y]>f*b.top){e=b.percents[y],p=b.percents[y-1]||0,t=t/b.top*(e-p),o=b.percents[y+1],j=b.anim[e];break}f&&d.attr(b.anim[b.percents[y]])}if(!!j){if(!k){for(var A in j)if(j[g](A))if(U[g](A)||d.paper.customAttributes[g](A)){u[A]=d.attr(A),u[A]==null&&(u[A]=T[A]),v[A]=j[A];switch(U[A]){case C:w[A]=(v[A]-u[A])/t;break;case\"colour\":u[A]=a.getRGB(u[A]);var B=a.getRGB(v[A]);w[A]={r:(B.r-u[A].r)/t,g:(B.g-u[A].g)/t,b:(B.b-u[A].b)/t};break;case\"path\":var D=bR(u[A],v[A]),E=D[1];u[A]=D[0],w[A]=[];for(y=0,z=u[A].length;y<z;y++){w[A][y]=[0];for(var F=1,G=u[A][y].length;F<G;F++)w[A][y][F]=(E[y][F]-u[A][y][F])/t}break;case\"transform\":var H=d._,I=ca(H[A],v[A]);if(I){u[A]=I.from,v[A]=I.to,w[A]=[],w[A].real=!0;for(y=0,z=u[A].length;y<z;y++){w[A][y]=[u[A][y][0]];for(F=1,G=u[A][y].length;F<G;F++)w[A][y][F]=(v[A][y][F]-u[A][y][F])/t}}else{var J=d.matrix||new cb,K={_:{transform:H.transform},getBBox:function(){return d.getBBox(1)}};u[A]=[J.a,J.b,J.c,J.d,J.e,J.f],b$(K,v[A]),v[A]=K._.transform,w[A]=[(K.matrix.a-J.a)/t,(K.matrix.b-J.b)/t,(K.matrix.c-J.c)/t,(K.matrix.d-J.d)/t,(K.matrix.e-J.e)/t,(K.matrix.f-J.f)/t]}break;case\"csv\":var L=r(j[A])[s](c),M=r(u[A])[s](c);if(A==\"clip-rect\"){u[A]=M,w[A]=[],y=M.length;while(y--)w[A][y]=(L[y]-u[A][y])/t}v[A]=L;break;default:L=[][n](j[A]),M=[][n](u[A]),w[A]=[],y=d.paper.customAttributes[A].length;while(y--)w[A][y]=((L[y]||0)-(M[y]||0))/t}}var O=j.easing,P=a.easing_formulas[O];if(!P){P=r(O).match(N);if(P&&P.length==5){var R=P;P=function(a){return cC(a,+R[1],+R[2],+R[3],+R[4],t)}}else P=bf}q=j.start||b.start||+(new Date),x={anim:b,percent:e,timestamp:q,start:q+(b.del||0),status:0,initstatus:f||0,stop:!1,ms:t,easing:P,from:u,diff:w,to:v,el:d,callback:j.callback,prev:p,next:o,repeat:i||b.times,origin:d.attr(),totalOrigin:h},cy.push(x);if(f&&!k&&!l){x.stop=!0,x.start=new Date-t*f;if(cy.length==1)return cA()}l&&(x.start=new Date-x.ms*f),cy.length==1&&cz(cA)}else k.initstatus=f,k.start=new Date-k.ms*f;eve(\"raphael.anim.start.\"+d.id,d,b)}}function cD(a,b){var c=[],d={};this.ms=b,this.times=1;if(a){for(var e in a)a[g](e)&&(d[Q(e)]=a[e],c.push(Q(e)));c.sort(bd)}this.anim=d,this.top=c[c.length-1],this.percents=c}function cC(a,b,c,d,e,f){function o(a,b){var c,d,e,f,j,k;for(e=a,k=0;k<8;k++){f=m(e)-a;if(z(f)<b)return e;j=(3*i*e+2*h)*e+g;if(z(j)<1e-6)break;e=e-f/j}c=0,d=1,e=a;if(e<c)return c;if(e>d)return d;while(c<d){f=m(e);if(z(f-a)<b)return e;a>f?c=e:d=e,e=(d-c)/2+c}return e}function n(a,b){var c=o(a,b);return((l*c+k)*c+j)*c}function m(a){return((i*a+h)*a+g)*a}var g=3*b,h=3*(d-b)-g,i=1-g-h,j=3*c,k=3*(e-c)-j,l=1-j-k;return n(a,1/(200*f))}function cq(){return this.x+q+this.y+q+this.width+\" × \"+this.height}function cp(){return this.x+q+this.y}function cb(a,b,c,d,e,f){a!=null?(this.a=+a,this.b=+b,this.c=+c,this.d=+d,this.e=+e,this.f=+f):(this.a=1,this.b=0,this.c=0,this.d=1,this.e=0,this.f=0)}function bH(b,c,d){b=a._path2curve(b),c=a._path2curve(c);var e,f,g,h,i,j,k,l,m,n,o=d?0:[];for(var p=0,q=b.length;p<q;p++){var r=b[p];if(r[0]==\"M\")e=i=r[1],f=j=r[2];else{r[0]==\"C\"?(m=[e,f].concat(r.slice(1)),e=m[6],f=m[7]):(m=[e,f,e,f,i,j,i,j],e=i,f=j);for(var s=0,t=c.length;s<t;s++){var u=c[s];if(u[0]==\"M\")g=k=u[1],h=l=u[2];else{u[0]==\"C\"?(n=[g,h].concat(u.slice(1)),g=n[6],h=n[7]):(n=[g,h,g,h,k,l,k,l],g=k,h=l);var v=bG(m,n,d);if(d)o+=v;else{for(var w=0,x=v.length;w<x;w++)v[w].segment1=p,v[w].segment2=s,v[w].bez1=m,v[w].bez2=n;o=o.concat(v)}}}}}return o}function bG(b,c,d){var e=a.bezierBBox(b),f=a.bezierBBox(c);if(!a.isBBoxIntersect(e,f))return d?0:[];var g=bB.apply(0,b),h=bB.apply(0,c),i=~~(g/5),j=~~(h/5),k=[],l=[],m={},n=d?0:[];for(var o=0;o<i+1;o++){var p=a.findDotsAtSegment.apply(a,b.concat(o/i));k.push({x:p.x,y:p.y,t:o/i})}for(o=0;o<j+1;o++)p=a.findDotsAtSegment.apply(a,c.concat(o/j)),l.push({x:p.x,y:p.y,t:o/j});for(o=0;o<i;o++)for(var q=0;q<j;q++){var r=k[o],s=k[o+1],t=l[q],u=l[q+1],v=z(s.x-r.x)<.001?\"y\":\"x\",w=z(u.x-t.x)<.001?\"y\":\"x\",x=bD(r.x,r.y,s.x,s.y,t.x,t.y,u.x,u.y);if(x){if(m[x.x.toFixed(4)]==x.y.toFixed(4))continue;m[x.x.toFixed(4)]=x.y.toFixed(4);var y=r.t+z((x[v]-r[v])/(s[v]-r[v]))*(s.t-r.t),A=t.t+z((x[w]-t[w])/(u[w]-t[w]))*(u.t-t.t);y>=0&&y<=1&&A>=0&&A<=1&&(d?n++:n.push({x:x.x,y:x.y,t1:y,t2:A}))}}return n}function bF(a,b){return bG(a,b,1)}function bE(a,b){return bG(a,b)}function bD(a,b,c,d,e,f,g,h){if(!(x(a,c)<y(e,g)||y(a,c)>x(e,g)||x(b,d)<y(f,h)||y(b,d)>x(f,h))){var i=(a*d-b*c)*(e-g)-(a-c)*(e*h-f*g),j=(a*d-b*c)*(f-h)-(b-d)*(e*h-f*g),k=(a-c)*(f-h)-(b-d)*(e-g);if(!k)return;var l=i/k,m=j/k,n=+l.toFixed(2),o=+m.toFixed(2);if(n<+y(a,c).toFixed(2)||n>+x(a,c).toFixed(2)||n<+y(e,g).toFixed(2)||n>+x(e,g).toFixed(2)||o<+y(b,d).toFixed(2)||o>+x(b,d).toFixed(2)||o<+y(f,h).toFixed(2)||o>+x(f,h).toFixed(2))return;return{x:l,y:m}}}function bC(a,b,c,d,e,f,g,h,i){if(!(i<0||bB(a,b,c,d,e,f,g,h)<i)){var j=1,k=j/2,l=j-k,m,n=.01;m=bB(a,b,c,d,e,f,g,h,l);while(z(m-i)>n)k/=2,l+=(m<i?1:-1)*k,m=bB(a,b,c,d,e,f,g,h,l);return l}}function bB(a,b,c,d,e,f,g,h,i){i==null&&(i=1),i=i>1?1:i<0?0:i;var j=i/2,k=12,l=[-0.1252,.1252,-0.3678,.3678,-0.5873,.5873,-0.7699,.7699,-0.9041,.9041,-0.9816,.9816],m=[.2491,.2491,.2335,.2335,.2032,.2032,.1601,.1601,.1069,.1069,.0472,.0472],n=0;for(var o=0;o<k;o++){var p=j*l[o]+j,q=bA(p,a,c,e,g),r=bA(p,b,d,f,h),s=q*q+r*r;n+=m[o]*w.sqrt(s)}return j*n}function bA(a,b,c,d,e){var f=-3*b+9*c-9*d+3*e,g=a*f+6*b-12*c+6*d;return a*g-3*b+3*c}function by(a,b){var c=[];for(var d=0,e=a.length;e-2*!b>d;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4==d?f[3]={x:+a[0],y:+a[1]}:e-2==d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4==d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push([\"C\",(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}function bx(){return this.hex}function bv(a,b,c){function d(){var e=Array.prototype.slice.call(arguments,0),f=e.join(\"␀\"),h=d.cache=d.cache||{},i=d.count=d.count||[];if(h[g](f)){bu(i,f);return c?c(h[f]):h[f]}i.length>=1e3&&delete h[i.shift()],i.push(f),h[f]=a[m](b,e);return c?c(h[f]):h[f]}return d}function bu(a,b){for(var c=0,d=a.length;c<d;c++)if(a[c]===b)return a.push(a.splice(c,1)[0])}function bm(a){if(Object(a)!==a)return a;var b=new a.constructor;for(var c in a)a[g](c)&&(b[c]=bm(a[c]));return b}function a(c){if(a.is(c,\"function\"))return b?c():eve.on(\"raphael.DOMload\",c);if(a.is(c,E))return a._engine.create[m](a,c.splice(0,3+a.is(c[0],C))).add(c);var d=Array.prototype.slice.call(arguments,0);if(a.is(d[d.length-1],\"function\")){var e=d.pop();return b?e.call(a._engine.create[m](a,d)):eve.on(\"raphael.DOMload\",function(){e.call(a._engine.create[m](a,d))})}return a._engine.create[m](a,arguments)}a.version=\"2.1.0\",a.eve=eve;var b,c=/[, ]+/,d={circle:1,rect:1,path:1,ellipse:1,text:1,image:1},e=/\\{(\\d+)\\}/g,f=\"prototype\",g=\"hasOwnProperty\",h={doc:document,win:window},i={was:Object.prototype[g].call(h.win,\"Raphael\"),is:h.win.Raphael},j=function(){this.ca=this.customAttributes={}},k,l=\"appendChild\",m=\"apply\",n=\"concat\",o=\"createTouch\"in h.doc,p=\"\",q=\" \",r=String,s=\"split\",t=\"click dblclick mousedown mousemove mouseout mouseover mouseup touchstart touchmove touchend touchcancel\"[s](q),u={mousedown:\"touchstart\",mousemove:\"touchmove\",mouseup:\"touchend\"},v=r.prototype.toLowerCase,w=Math,x=w.max,y=w.min,z=w.abs,A=w.pow,B=w.PI,C=\"number\",D=\"string\",E=\"array\",F=\"toString\",G=\"fill\",H=Object.prototype.toString,I={},J=\"push\",K=a._ISURL=/^url\\(['\"]?([^\\)]+?)['\"]?\\)$/i,L=/^\\s*((#[a-f\\d]{6})|(#[a-f\\d]{3})|rgba?\\(\\s*([\\d\\.]+%?\\s*,\\s*[\\d\\.]+%?\\s*,\\s*[\\d\\.]+%?(?:\\s*,\\s*[\\d\\.]+%?)?)\\s*\\)|hsba?\\(\\s*([\\d\\.]+(?:deg|\\xb0|%)?\\s*,\\s*[\\d\\.]+%?\\s*,\\s*[\\d\\.]+(?:%?\\s*,\\s*[\\d\\.]+)?)%?\\s*\\)|hsla?\\(\\s*([\\d\\.]+(?:deg|\\xb0|%)?\\s*,\\s*[\\d\\.]+%?\\s*,\\s*[\\d\\.]+(?:%?\\s*,\\s*[\\d\\.]+)?)%?\\s*\\))\\s*$/i,M={NaN:1,Infinity:1,\"-Infinity\":1},N=/^(?:cubic-)?bezier\\(([^,]+),([^,]+),([^,]+),([^\\)]+)\\)/,O=w.round,P=\"setAttribute\",Q=parseFloat,R=parseInt,S=r.prototype.toUpperCase,T=a._availableAttrs={\"arrow-end\":\"none\",\"arrow-start\":\"none\",blur:0,\"clip-rect\":\"0 0 1e9 1e9\",cursor:\"default\",cx:0,cy:0,fill:\"#fff\",\"fill-opacity\":1,font:'10px \"Arial\"',\"font-family\":'\"Arial\"',\"font-size\":\"10\",\"font-style\":\"normal\",\"font-weight\":400,gradient:0,height:0,href:\"http://raphaeljs.com/\",\"letter-spacing\":0,opacity:1,path:\"M0,0\",r:0,rx:0,ry:0,src:\"\",stroke:\"#000\",\"stroke-dasharray\":\"\",\"stroke-linecap\":\"butt\",\"stroke-linejoin\":\"butt\",\"stroke-miterlimit\":0,\"stroke-opacity\":1,\"stroke-width\":1,target:\"_blank\",\"text-anchor\":\"middle\",title:\"Raphael\",transform:\"\",width:0,x:0,y:0},U=a._availableAnimAttrs={blur:C,\"clip-rect\":\"csv\",cx:C,cy:C,fill:\"colour\",\"fill-opacity\":C,\"font-size\":C,height:C,opacity:C,path:\"path\",r:C,rx:C,ry:C,stroke:\"colour\",\"stroke-opacity\":C,\"stroke-width\":C,transform:\"transform\",width:C,x:C,y:C},V=/[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029]/g,W=/[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029]*,[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029]*/,X={hs:1,rg:1},Y=/,?([achlmqrstvxz]),?/gi,Z=/([achlmrqstvz])[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029,]*((-?\\d*\\.?\\d*(?:e[\\-+]?\\d+)?[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029]*,?[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029]*)+)/ig,$=/([rstm])[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029,]*((-?\\d*\\.?\\d*(?:e[\\-+]?\\d+)?[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029]*,?[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029]*)+)/ig,_=/(-?\\d*\\.?\\d*(?:e[\\-+]?\\d+)?)[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029]*,?[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029]*/ig,ba=a._radial_gradient=/^r(?:\\(([^,]+?)[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029]*,[\\x09\\x0a\\x0b\\x0c\\x0d\\x20\\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\\u2029]*([^\\)]+?)\\))?/,bb={},bc=function(a,b){return a.key-b.key},bd=function(a,b){return Q(a)-Q(b)},be=function(){},bf=function(a){return a},bg=a._rectPath=function(a,b,c,d,e){if(e)return[[\"M\",a+e,b],[\"l\",c-e*2,0],[\"a\",e,e,0,0,1,e,e],[\"l\",0,d-e*2],[\"a\",e,e,0,0,1,-e,e],[\"l\",e*2-c,0],[\"a\",e,e,0,0,1,-e,-e],[\"l\",0,e*2-d],[\"a\",e,e,0,0,1,e,-e],[\"z\"]];return[[\"M\",a,b],[\"l\",c,0],[\"l\",0,d],[\"l\",-c,0],[\"z\"]]},bh=function(a,b,c,d){d==null&&(d=c);return[[\"M\",a,b],[\"m\",0,-d],[\"a\",c,d,0,1,1,0,2*d],[\"a\",c,d,0,1,1,0,-2*d],[\"z\"]]},bi=a._getPath={path:function(a){return a.attr(\"path\")},circle:function(a){var b=a.attrs;return bh(b.cx,b.cy,b.r)},ellipse:function(a){var b=a.attrs;return bh(b.cx,b.cy,b.rx,b.ry)},rect:function(a){var b=a.attrs;return bg(b.x,b.y,b.width,b.height,b.r)},image:function(a){var b=a.attrs;return bg(b.x,b.y,b.width,b.height)},text:function(a){var b=a._getBBox();return bg(b.x,b.y,b.width,b.height)}},bj=a.mapPath=function(a,b){if(!b)return a;var c,d,e,f,g,h,i;a=bR(a);for(e=0,g=a.length;e<g;e++){i=a[e];for(f=1,h=i.length;f<h;f+=2)c=b.x(i[f],i[f+1]),d=b.y(i[f],i[f+1]),i[f]=c,i[f+1]=d}return a};a._g=h,a.type=h.win.SVGAngle||h.doc.implementation.hasFeature(\"http://www.w3.org/TR/SVG11/feature#BasicStructure\",\"1.1\")?\"SVG\":\"VML\";if(a.type==\"VML\"){var bk=h.doc.createElement(\"div\"),bl;bk.innerHTML='<v:shape adj=\"1\"/>',bl=bk.firstChild,bl.style.behavior=\"url(#default#VML)\";if(!bl||typeof bl.adj!=\"object\")return a.type=p;bk=null}a.svg=!(a.vml=a.type==\"VML\"),a._Paper=j,a.fn=k=j.prototype=a.prototype,a._id=0,a._oid=0,a.is=function(a,b){b=v.call(b);if(b==\"finite\")return!M[g](+a);if(b==\"array\")return a instanceof Array;return b==\"null\"&&a===null||b==typeof a&&a!==null||b==\"object\"&&a===Object(a)||b==\"array\"&&Array.isArray&&Array.isArray(a)||H.call(a).slice(8,-1).toLowerCase()==b},a.angle=function(b,c,d,e,f,g){if(f==null){var h=b-d,i=c-e;if(!h&&!i)return 0;return(180+w.atan2(-i,-h)*180/B+360)%360}return a.angle(b,c,f,g)-a.angle(d,e,f,g)},a.rad=function(a){return a%360*B/180},a.deg=function(a){return a*180/B%360},a.snapTo=function(b,c,d){d=a.is(d,\"finite\")?d:10;if(a.is(b,E)){var e=b.length;while(e--)if(z(b[e]-c)<=d)return b[e]}else{b=+b;var f=c%b;if(f<d)return c-f;if(f>b-d)return c-f+b}return c};var bn=a.createUUID=function(a,b){return function(){return\"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(a,b).toUpperCase()}}(/[xy]/g,function(a){var b=w.random()*16|0,c=a==\"x\"?b:b&3|8;return c.toString(16)});a.setWindow=function(b){eve(\"raphael.setWindow\",a,h.win,b),h.win=b,h.doc=h.win.document,a._engine.initWin&&a._engine.initWin(h.win)};var bo=function(b){if(a.vml){var c=/^\\s+|\\s+$/g,d;try{var e=new ActiveXObject(\"htmlfile\");e.write(\"<body>\"),e.close(),d=e.body}catch(f){d=createPopup().document.body}var g=d.createTextRange();bo=bv(function(a){try{d.style.color=r(a).replace(c,p);var b=g.queryCommandValue(\"ForeColor\");b=(b&255)<<16|b&65280|(b&16711680)>>>16;return\"#\"+(\"000000\"+b.toString(16)).slice(-6)}catch(e){return\"none\"}})}else{var i=h.doc.createElement(\"i\");i.title=\"Raphaël Colour Picker\",i.style.display=\"none\",h.doc.body.appendChild(i),bo=bv(function(a){i.style.color=a;return h.doc.defaultView.getComputedStyle(i,p).getPropertyValue(\"color\")})}return bo(b)},bp=function(){return\"hsb(\"+[this.h,this.s,this.b]+\")\"},bq=function(){return\"hsl(\"+[this.h,this.s,this.l]+\")\"},br=function(){return this.hex},bs=function(b,c,d){c==null&&a.is(b,\"object\")&&\"r\"in b&&\"g\"in b&&\"b\"in b&&(d=b.b,c=b.g,b=b.r);if(c==null&&a.is(b,D)){var e=a.getRGB(b);b=e.r,c=e.g,d=e.b}if(b>1||c>1||d>1)b/=255,c/=255,d/=255;return[b,c,d]},bt=function(b,c,d,e){b*=255,c*=255,d*=255;var f={r:b,g:c,b:d,hex:a.rgb(b,c,d),toString:br};a.is(e,\"finite\")&&(f.opacity=e);return f};a.color=function(b){var c;a.is(b,\"object\")&&\"h\"in b&&\"s\"in b&&\"b\"in b?(c=a.hsb2rgb(b),b.r=c.r,b.g=c.g,b.b=c.b,b.hex=c.hex):a.is(b,\"object\")&&\"h\"in b&&\"s\"in b&&\"l\"in b?(c=a.hsl2rgb(b),b.r=c.r,b.g=c.g,b.b=c.b,b.hex=c.hex):(a.is(b,\"string\")&&(b=a.getRGB(b)),a.is(b,\"object\")&&\"r\"in b&&\"g\"in b&&\"b\"in b?(c=a.rgb2hsl(b),b.h=c.h,b.s=c.s,b.l=c.l,c=a.rgb2hsb(b),b.v=c.b):(b={hex:\"none\"},b.r=b.g=b.b=b.h=b.s=b.v=b.l=-1)),b.toString=br;return b},a.hsb2rgb=function(a,b,c,d){this.is(a,\"object\")&&\"h\"in a&&\"s\"in a&&\"b\"in a&&(c=a.b,b=a.s,a=a.h,d=a.o),a*=360;var e,f,g,h,i;a=a%360/60,i=c*b,h=i*(1-z(a%2-1)),e=f=g=c-i,a=~~a,e+=[i,h,0,0,h,i][a],f+=[h,i,i,h,0,0][a],g+=[0,0,h,i,i,h][a];return bt(e,f,g,d)},a.hsl2rgb=function(a,b,c,d){this.is(a,\"object\")&&\"h\"in a&&\"s\"in a&&\"l\"in a&&(c=a.l,b=a.s,a=a.h);if(a>1||b>1||c>1)a/=360,b/=100,c/=100;a*=360;var e,f,g,h,i;a=a%360/60,i=2*b*(c<.5?c:1-c),h=i*(1-z(a%2-1)),e=f=g=c-i/2,a=~~a,e+=[i,h,0,0,h,i][a],f+=[h,i,i,h,0,0][a],g+=[0,0,h,i,i,h][a];return bt(e,f,g,d)},a.rgb2hsb=function(a,b,c){c=bs(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g;f=x(a,b,c),g=f-y(a,b,c),d=g==0?null:f==a?(b-c)/g:f==b?(c-a)/g+2:(a-b)/g+4,d=(d+360)%6*60/360,e=g==0?0:g/f;return{h:d,s:e,b:f,toString:bp}},a.rgb2hsl=function(a,b,c){c=bs(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g,h,i;g=x(a,b,c),h=y(a,b,c),i=g-h,d=i==0?null:g==a?(b-c)/i:g==b?(c-a)/i+2:(a-b)/i+4,d=(d+360)%6*60/360,f=(g+h)/2,e=i==0?0:f<.5?i/(2*f):i/(2-2*f);return{h:d,s:e,l:f,toString:bq}},a._path2string=function(){return this.join(\",\").replace(Y,\"$1\")};var bw=a._preload=function(a,b){var c=h.doc.createElement(\"img\");c.style.cssText=\"position:absolute;left:-9999em;top:-9999em\",c.onload=function(){b.call(this),this.onload=null,h.doc.body.removeChild(this)},c.onerror=function(){h.doc.body.removeChild(this)},h.doc.body.appendChild(c),c.src=a};a.getRGB=bv(function(b){if(!b||!!((b=r(b)).indexOf(\"-\")+1))return{r:-1,g:-1,b:-1,hex:\"none\",error:1,toString:bx};if(b==\"none\")return{r:-1,g:-1,b:-1,hex:\"none\",toString:bx};!X[g](b.toLowerCase().substring(0,2))&&b.charAt()!=\"#\"&&(b=bo(b));var c,d,e,f,h,i,j,k=b.match(L);if(k){k[2]&&(f=R(k[2].substring(5),16),e=R(k[2].substring(3,5),16),d=R(k[2].substring(1,3),16)),k[3]&&(f=R((i=k[3].charAt(3))+i,16),e=R((i=k[3].charAt(2))+i,16),d=R((i=k[3].charAt(1))+i,16)),k[4]&&(j=k[4][s](W),d=Q(j[0]),j[0].slice(-1)==\"%\"&&(d*=2.55),e=Q(j[1]),j[1].slice(-1)==\"%\"&&(e*=2.55),f=Q(j[2]),j[2].slice(-1)==\"%\"&&(f*=2.55),k[1].toLowerCase().slice(0,4)==\"rgba\"&&(h=Q(j[3])),j[3]&&j[3].slice(-1)==\"%\"&&(h/=100));if(k[5]){j=k[5][s](W),d=Q(j[0]),j[0].slice(-1)==\"%\"&&(d*=2.55),e=Q(j[1]),j[1].slice(-1)==\"%\"&&(e*=2.55),f=Q(j[2]),j[2].slice(-1)==\"%\"&&(f*=2.55),(j[0].slice(-3)==\"deg\"||j[0].slice(-1)==\"°\")&&(d/=360),k[1].toLowerCase().slice(0,4)==\"hsba\"&&(h=Q(j[3])),j[3]&&j[3].slice(-1)==\"%\"&&(h/=100);return a.hsb2rgb(d,e,f,h)}if(k[6]){j=k[6][s](W),d=Q(j[0]),j[0].slice(-1)==\"%\"&&(d*=2.55),e=Q(j[1]),j[1].slice(-1)==\"%\"&&(e*=2.55),f=Q(j[2]),j[2].slice(-1)==\"%\"&&(f*=2.55),(j[0].slice(-3)==\"deg\"||j[0].slice(-1)==\"°\")&&(d/=360),k[1].toLowerCase().slice(0,4)==\"hsla\"&&(h=Q(j[3])),j[3]&&j[3].slice(-1)==\"%\"&&(h/=100);return a.hsl2rgb(d,e,f,h)}k={r:d,g:e,b:f,toString:bx},k.hex=\"#\"+(16777216|f|e<<8|d<<16).toString(16).slice(1),a.is(h,\"finite\")&&(k.opacity=h);return k}return{r:-1,g:-1,b:-1,hex:\"none\",error:1,toString:bx}},a),a.hsb=bv(function(b,c,d){return a.hsb2rgb(b,c,d).hex}),a.hsl=bv(function(b,c,d){return a.hsl2rgb(b,c,d).hex}),a.rgb=bv(function(a,b,c){return\"#\"+(16777216|c|b<<8|a<<16).toString(16).slice(1)}),a.getColor=function(a){var b=this.getColor.start=this.getColor.start||{h:0,s:1,b:a||.75},c=this.hsb2rgb(b.h,b.s,b.b);b.h+=.075,b.h>1&&(b.h=0,b.s-=.2,b.s<=0&&(this.getColor.start={h:0,s:1,b:b.b}));return c.hex},a.getColor.reset=function(){delete this.start},a.parsePathString=function(b){if(!b)return null;var c=bz(b);if(c.arr)return bJ(c.arr);var d={a:7,c:6,h:1,l:2,m:2,r:4,q:4,s:4,t:2,v:1,z:0},e=[];a.is(b,E)&&a.is(b[0],E)&&(e=bJ(b)),e.length||r(b).replace(Z,function(a,b,c){var f=[],g=b.toLowerCase();c.replace(_,function(a,b){b&&f.push(+b)}),g==\"m\"&&f.length>2&&(e.push([b][n](f.splice(0,2))),g=\"l\",b=b==\"m\"?\"l\":\"L\");if(g==\"r\")e.push([b][n](f));else while(f.length>=d[g]){e.push([b][n](f.splice(0,d[g])));if(!d[g])break}}),e.toString=a._path2string,c.arr=bJ(e);return e},a.parseTransformString=bv(function(b){if(!b)return null;var c={r:3,s:4,t:2,m:6},d=[];a.is(b,E)&&a.is(b[0],E)&&(d=bJ(b)),d.length||r(b).replace($,function(a,b,c){var e=[],f=v.call(b);c.replace(_,function(a,b){b&&e.push(+b)}),d.push([b][n](e))}),d.toString=a._path2string;return d});var bz=function(a){var b=bz.ps=bz.ps||{};b[a]?b[a].sleep=100:b[a]={sleep:100},setTimeout(function(){for(var c in b)b[g](c)&&c!=a&&(b[c].sleep--,!b[c].sleep&&delete b[c])});return b[a]};a.findDotsAtSegment=function(a,b,c,d,e,f,g,h,i){var j=1-i,k=A(j,3),l=A(j,2),m=i*i,n=m*i,o=k*a+l*3*i*c+j*3*i*i*e+n*g,p=k*b+l*3*i*d+j*3*i*i*f+n*h,q=a+2*i*(c-a)+m*(e-2*c+a),r=b+2*i*(d-b)+m*(f-2*d+b),s=c+2*i*(e-c)+m*(g-2*e+c),t=d+2*i*(f-d)+m*(h-2*f+d),u=j*a+i*c,v=j*b+i*d,x=j*e+i*g,y=j*f+i*h,z=90-w.atan2(q-s,r-t)*180/B;(q>s||r<t)&&(z+=180);return{x:o,y:p,m:{x:q,y:r},n:{x:s,y:t},start:{x:u,y:v},end:{x:x,y:y},alpha:z}},a.bezierBBox=function(b,c,d,e,f,g,h,i){a.is(b,\"array\")||(b=[b,c,d,e,f,g,h,i]);var j=bQ.apply(null,b);return{x:j.min.x,y:j.min.y,x2:j.max.x,y2:j.max.y,width:j.max.x-j.min.x,height:j.max.y-j.min.y}},a.isPointInsideBBox=function(a,b,c){return b>=a.x&&b<=a.x2&&c>=a.y&&c<=a.y2},a.isBBoxIntersect=function(b,c){var d=a.isPointInsideBBox;return d(c,b.x,b.y)||d(c,b.x2,b.y)||d(c,b.x,b.y2)||d(c,b.x2,b.y2)||d(b,c.x,c.y)||d(b,c.x2,c.y)||d(b,c.x,c.y2)||d(b,c.x2,c.y2)||(b.x<c.x2&&b.x>c.x||c.x<b.x2&&c.x>b.x)&&(b.y<c.y2&&b.y>c.y||c.y<b.y2&&c.y>b.y)},a.pathIntersection=function(a,b){return bH(a,b)},a.pathIntersectionNumber=function(a,b){return bH(a,b,1)},a.isPointInsidePath=function(b,c,d){var e=a.pathBBox(b);return a.isPointInsideBBox(e,c,d)&&bH(b,[[\"M\",c,d],[\"H\",e.x2+10]],1)%2==1},a._removedFactory=function(a){return function(){eve(\"raphael.log\",null,\"Raphaël: you are calling to method “\"+a+\"” of removed object\",a)}};var bI=a.pathBBox=function(a){var b=bz(a);if(b.bbox)return b.bbox;if(!a)return{x:0,y:0,width:0,height:0,x2:0,y2:0};a=bR(a);var c=0,d=0,e=[],f=[],g;for(var h=0,i=a.length;h<i;h++){g=a[h];if(g[0]==\"M\")c=g[1],d=g[2],e.push(c),f.push(d);else{var j=bQ(c,d,g[1],g[2],g[3],g[4],g[5],g[6]);e=e[n](j.min.x,j.max.x),f=f[n](j.min.y,j.max.y),c=g[5],d=g[6]}}var k=y[m](0,e),l=y[m](0,f),o=x[m](0,e),p=x[m](0,f),q={x:k,y:l,x2:o,y2:p,width:o-k,height:p-l};b.bbox=bm(q);return q},bJ=function(b){var c=bm(b);c.toString=a._path2string;return c},bK=a._pathToRelative=function(b){var c=bz(b);if(c.rel)return bJ(c.rel);if(!a.is(b,E)||!a.is(b&&b[0],E))b=a.parsePathString(b);var d=[],e=0,f=0,g=0,h=0,i=0;b[0][0]==\"M\"&&(e=b[0][1],f=b[0][2],g=e,h=f,i++,d.push([\"M\",e,f]));for(var j=i,k=b.length;j<k;j++){var l=d[j]=[],m=b[j];if(m[0]!=v.call(m[0])){l[0]=v.call(m[0]);switch(l[0]){case\"a\":l[1]=m[1],l[2]=m[2],l[3]=m[3],l[4]=m[4],l[5]=m[5],l[6]=+(m[6]-e).toFixed(3),l[7]=+(m[7]-f).toFixed(3);break;case\"v\":l[1]=+(m[1]-f).toFixed(3);break;case\"m\":g=m[1],h=m[2];default:for(var n=1,o=m.length;n<o;n++)l[n]=+(m[n]-(n%2?e:f)).toFixed(3)}}else{l=d[j]=[],m[0]==\"m\"&&(g=m[1]+e,h=m[2]+f);for(var p=0,q=m.length;p<q;p++)d[j][p]=m[p]}var r=d[j].length;switch(d[j][0]){case\"z\":e=g,f=h;break;case\"h\":e+=+d[j][r-1];break;case\"v\":f+=+d[j][r-1];break;default:e+=+d[j][r-2],f+=+d[j][r-1]}}d.toString=a._path2string,c.rel=bJ(d);return d},bL=a._pathToAbsolute=function(b){var c=bz(b);if(c.abs)return bJ(c.abs);if(!a.is(b,E)||!a.is(b&&b[0],E))b=a.parsePathString(b);if(!b||!b.length)return[[\"M\",0,0]];var d=[],e=0,f=0,g=0,h=0,i=0;b[0][0]==\"M\"&&(e=+b[0][1],f=+b[0][2],g=e,h=f,i++,d[0]=[\"M\",e,f]);var j=b.length==3&&b[0][0]==\"M\"&&b[1][0].toUpperCase()==\"R\"&&b[2][0].toUpperCase()==\"Z\";for(var k,l,m=i,o=b.length;m<o;m++){d.push(k=[]),l=b[m];if(l[0]!=S.call(l[0])){k[0]=S.call(l[0]);switch(k[0]){case\"A\":k[1]=l[1],k[2]=l[2],k[3]=l[3],k[4]=l[4],k[5]=l[5],k[6]=+(l[6]+e),k[7]=+(l[7]+f);break;case\"V\":k[1]=+l[1]+f;break;case\"H\":k[1]=+l[1]+e;break;case\"R\":var p=[e,f][n](l.slice(1));for(var q=2,r=p.length;q<r;q++)p[q]=+p[q]+e,p[++q]=+p[q]+f;d.pop(),d=d[n](by(p,j));break;case\"M\":g=+l[1]+e,h=+l[2]+f;default:for(q=1,r=l.length;q<r;q++)k[q]=+l[q]+(q%2?e:f)}}else if(l[0]==\"R\")p=[e,f][n](l.slice(1)),d.pop(),d=d[n](by(p,j)),k=[\"R\"][n](l.slice(-2));else for(var s=0,t=l.length;s<t;s++)k[s]=l[s];switch(k[0]){case\"Z\":e=g,f=h;break;case\"H\":e=k[1];break;case\"V\":f=k[1];break;case\"M\":g=k[k.length-2],h=k[k.length-1];default:e=k[k.length-2],f=k[k.length-1]}}d.toString=a._path2string,c.abs=bJ(d);return d},bM=function(a,b,c,d){return[a,b,c,d,c,d]},bN=function(a,b,c,d,e,f){var g=1/3,h=2/3;return[g*a+h*c,g*b+h*d,g*e+h*c,g*f+h*d,e,f]},bO=function(a,b,c,d,e,f,g,h,i,j){var k=B*120/180,l=B/180*(+e||0),m=[],o,p=bv(function(a,b,c){var d=a*w.cos(c)-b*w.sin(c),e=a*w.sin(c)+b*w.cos(c);return{x:d,y:e}});if(!j){o=p(a,b,-l),a=o.x,b=o.y,o=p(h,i,-l),h=o.x,i=o.y;var q=w.cos(B/180*e),r=w.sin(B/180*e),t=(a-h)/2,u=(b-i)/2,v=t*t/(c*c)+u*u/(d*d);v>1&&(v=w.sqrt(v),c=v*c,d=v*d);var x=c*c,y=d*d,A=(f==g?-1:1)*w.sqrt(z((x*y-x*u*u-y*t*t)/(x*u*u+y*t*t))),C=A*c*u/d+(a+h)/2,D=A*-d*t/c+(b+i)/2,E=w.asin(((b-D)/d).toFixed(9)),F=w.asin(((i-D)/d).toFixed(9));E=a<C?B-E:E,F=h<C?B-F:F,E<0&&(E=B*2+E),F<0&&(F=B*2+F),g&&E>F&&(E=E-B*2),!g&&F>E&&(F=F-B*2)}else E=j[0],F=j[1],C=j[2],D=j[3];var G=F-E;if(z(G)>k){var H=F,I=h,J=i;F=E+k*(g&&F>E?1:-1),h=C+c*w.cos(F),i=D+d*w.sin(F),m=bO(h,i,c,d,e,0,g,I,J,[F,H,C,D])}G=F-E;var K=w.cos(E),L=w.sin(E),M=w.cos(F),N=w.sin(F),O=w.tan(G/4),P=4/3*c*O,Q=4/3*d*O,R=[a,b],S=[a+P*L,b-Q*K],T=[h+P*N,i-Q*M],U=[h,i];S[0]=2*R[0]-S[0],S[1]=2*R[1]-S[1];if(j)return[S,T,U][n](m);m=[S,T,U][n](m).join()[s](\",\");var V=[];for(var W=0,X=m.length;W<X;W++)V[W]=W%2?p(m[W-1],m[W],l).y:p(m[W],m[W+1],l).x;return V},bP=function(a,b,c,d,e,f,g,h,i){var j=1-i;return{x:A(j,3)*a+A(j,2)*3*i*c+j*3*i*i*e+A(i,3)*g,y:A(j,3)*b+A(j,2)*3*i*d+j*3*i*i*f+A(i,3)*h}},bQ=bv(function(a,b,c,d,e,f,g,h){var i=e-2*c+a-(g-2*e+c),j=2*(c-a)-2*(e-c),k=a-c,l=(-j+w.sqrt(j*j-4*i*k))/2/i,n=(-j-w.sqrt(j*j-4*i*k))/2/i,o=[b,h],p=[a,g],q;z(l)>\"1e12\"&&(l=.5),z(n)>\"1e12\"&&(n=.5),l>0&&l<1&&(q=bP(a,b,c,d,e,f,g,h,l),p.push(q.x),o.push(q.y)),n>0&&n<1&&(q=bP(a,b,c,d,e,f,g,h,n),p.push(q.x),o.push(q.y)),i=f-2*d+b-(h-2*f+d),j=2*(d-b)-2*(f-d),k=b-d,l=(-j+w.sqrt(j*j-4*i*k))/2/i,n=(-j-w.sqrt(j*j-4*i*k))/2/i,z(l)>\"1e12\"&&(l=.5),z(n)>\"1e12\"&&(n=.5),l>0&&l<1&&(q=bP(a,b,c,d,e,f,g,h,l),p.push(q.x),o.push(q.y)),n>0&&n<1&&(q=bP(a,b,c,d,e,f,g,h,n),p.push(q.x),o.push(q.y));return{min:{x:y[m](0,p),y:y[m](0,o)},max:{x:x[m](0,p),y:x[m](0,o)}}}),bR=a._path2curve=bv(function(a,b){var c=!b&&bz(a);if(!b&&c.curve)return bJ(c.curve);var d=bL(a),e=b&&bL(b),f={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},g={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},h=function(a,b){var c,d;if(!a)return[\"C\",b.x,b.y,b.x,b.y,b.x,b.y];!(a[0]in{T:1,Q:1})&&(b.qx=b.qy=null);switch(a[0]){case\"M\":b.X=a[1],b.Y=a[2];break;case\"A\":a=[\"C\"][n](bO[m](0,[b.x,b.y][n](a.slice(1))));break;case\"S\":c=b.x+(b.x-(b.bx||b.x)),d=b.y+(b.y-(b.by||b.y)),a=[\"C\",c,d][n](a.slice(1));break;case\"T\":b.qx=b.x+(b.x-(b.qx||b.x)),b.qy=b.y+(b.y-(b.qy||b.y)),a=[\"C\"][n](bN(b.x,b.y,b.qx,b.qy,a[1],a[2]));break;case\"Q\":b.qx=a[1],b.qy=a[2],a=[\"C\"][n](bN(b.x,b.y,a[1],a[2],a[3],a[4]));break;case\"L\":a=[\"C\"][n](bM(b.x,b.y,a[1],a[2]));break;case\"H\":a=[\"C\"][n](bM(b.x,b.y,a[1],b.y));break;case\"V\":a=[\"C\"][n](bM(b.x,b.y,b.x,a[1]));break;case\"Z\":a=[\"C\"][n](bM(b.x,b.y,b.X,b.Y))}return a},i=function(a,b){if(a[b].length>7){a[b].shift();var c=a[b];while(c.length)a.splice(b++,0,[\"C\"][n](c.splice(0,6)));a.splice(b,1),l=x(d.length,e&&e.length||0)}},j=function(a,b,c,f,g){a&&b&&a[g][0]==\"M\"&&b[g][0]!=\"M\"&&(b.splice(g,0,[\"M\",f.x,f.y]),c.bx=0,c.by=0,c.x=a[g][1],c.y=a[g][2],l=x(d.length,e&&e.length||0))};for(var k=0,l=x(d.length,e&&e.length||0);k<l;k++){d[k]=h(d[k],f),i(d,k),e&&(e[k]=h(e[k],g)),e&&i(e,k),j(d,e,f,g,k),j(e,d,g,f,k);var o=d[k],p=e&&e[k],q=o.length,r=e&&p.length;f.x=o[q-2],f.y=o[q-1],f.bx=Q(o[q-4])||f.x,f.by=Q(o[q-3])||f.y,g.bx=e&&(Q(p[r-4])||g.x),g.by=e&&(Q(p[r-3])||g.y),g.x=e&&p[r-2],g.y=e&&p[r-1]}e||(c.curve=bJ(d));return e?[d,e]:d},null,bJ),bS=a._parseDots=bv(function(b){var c=[];for(var d=0,e=b.length;d<e;d++){var f={},g=b[d].match(/^([^:]*):?([\\d\\.]*)/);f.color=a.getRGB(g[1]);if(f.color.error)return null;f.color=f.color.hex,g[2]&&(f.offset=g[2]+\"%\"),c.push(f)}for(d=1,e=c.length-1;d<e;d++)if(!c[d].offset){var h=Q(c[d-1].offset||0),i=0;for(var j=d+1;j<e;j++)if(c[j].offset){i=c[j].offset;break}i||(i=100,j=e),i=Q(i);var k=(i-h)/(j-d+1);for(;d<j;d++)h+=k,c[d].offset=h+\"%\"}return c}),bT=a._tear=function(a,b){a==b.top&&(b.top=a.prev),a==b.bottom&&(b.bottom=a.next),a.next&&(a.next.prev=a.prev),a.prev&&(a.prev.next=a.next)},bU=a._tofront=function(a,b){b.top!==a&&(bT(a,b),a.next=null,a.prev=b.top,b.top.next=a,b.top=a)},bV=a._toback=function(a,b){b.bottom!==a&&(bT(a,b),a.next=b.bottom,a.prev=null,b.bottom.prev=a,b.bottom=a)},bW=a._insertafter=function(a,b,c){bT(a,c),b==c.top&&(c.top=a),b.next&&(b.next.prev=a),a.next=b.next,a.prev=b,b.next=a},bX=a._insertbefore=function(a,b,c){bT(a,c),b==c.bottom&&(c.bottom=a),b.prev&&(b.prev.next=a),a.prev=b.prev,b.prev=a,a.next=b},bY=a.toMatrix=function(a,b){var c=bI(a),d={_:{transform:p},getBBox:function(){return c}};b$(d,b);return d.matrix},bZ=a.transformPath=function(a,b){return bj(a,bY(a,b))},b$=a._extractTransform=function(b,c){if(c==null)return b._.transform;c=r(c).replace(/\\.{3}|\\u2026/g,b._.transform||p);var d=a.parseTransformString(c),e=0,f=0,g=0,h=1,i=1,j=b._,k=new cb;j.transform=d||[];if(d)for(var l=0,m=d.length;l<m;l++){var n=d[l],o=n.length,q=r(n[0]).toLowerCase(),s=n[0]!=q,t=s?k.invert():0,u,v,w,x,y;q==\"t\"&&o==3?s?(u=t.x(0,0),v=t.y(0,0),w=t.x(n[1],n[2]),x=t.y(n[1],n[2]),k.translate(w-u,x-v)):k.translate(n[1],n[2]):q==\"r\"?o==2?(y=y||b.getBBox(1),k.rotate(n[1],y.x+y.width/2,y.y+y.height/2),e+=n[1]):o==4&&(s?(w=t.x(n[2],n[3]),x=t.y(n[2],n[3]),k.rotate(n[1],w,x)):k.rotate(n[1],n[2],n[3]),e+=n[1]):q==\"s\"?o==2||o==3?(y=y||b.getBBox(1),k.scale(n[1],n[o-1],y.x+y.width/2,y.y+y.height/2),h*=n[1],i*=n[o-1]):o==5&&(s?(w=t.x(n[3],n[4]),x=t.y(n[3],n[4]),k.scale(n[1],n[2],w,x)):k.scale(n[1],n[2],n[3],n[4]),h*=n[1],i*=n[2]):q==\"m\"&&o==7&&k.add(n[1],n[2],n[3],n[4],n[5],n[6]),j.dirtyT=1,b.matrix=k}b.matrix=k,j.sx=h,j.sy=i,j.deg=e,j.dx=f=k.e,j.dy=g=k.f,h==1&&i==1&&!e&&j.bbox?(j.bbox.x+=+f,j.bbox.y+=+g):j.dirtyT=1},b_=function(a){var b=a[0];switch(b.toLowerCase()){case\"t\":return[b,0,0];case\"m\":return[b,1,0,0,1,0,0];case\"r\":return a.length==4?[b,0,a[2],a[3]]:[b,0];case\"s\":return a.length==5?[b,1,1,a[3],a[4]]:a.length==3?[b,1,1]:[b,1]}},ca=a._equaliseTransform=function(b,c){c=r(c).replace(/\\.{3}|\\u2026/g,b),b=a.parseTransformString(b)||[],c=a.parseTransformString(c)||[];var d=x(b.length,c.length),e=[],f=[],g=0,h,i,j,k;for(;g<d;g++){j=b[g]||b_(c[g]),k=c[g]||b_(j);if(j[0]!=k[0]||j[0].toLowerCase()==\"r\"&&(j[2]!=k[2]||j[3]!=k[3])||j[0].toLowerCase()==\"s\"&&(j[3]!=k[3]||j[4]!=k[4]))return;e[g]=[],f[g]=[];for(h=0,i=x(j.length,k.length);h<i;h++)h in j&&(e[g][h]=j[h]),h in k&&(f[g][h]=k[h])}return{from:e,to:f}};a._getContainer=function(b,c,d,e){var f;f=e==null&&!a.is(b,\"object\")?h.doc.getElementById(b):b;if(f!=null){if(f.tagName)return c==null?{container:f,width:f.style.pixelWidth||f.offsetWidth,height:f.style.pixelHeight||f.offsetHeight}:{container:f,width:c,height:d};return{container:1,x:b,y:c,width:d,height:e}}},a.pathToRelative=bK,a._engine={},a.path2curve=bR,a.matrix=function(a,b,c,d,e,f){return new cb(a,b,c,d,e,f)},function(b){function d(a){var b=w.sqrt(c(a));a[0]&&(a[0]/=b),a[1]&&(a[1]/=b)}function c(a){return a[0]*a[0]+a[1]*a[1]}b.add=function(a,b,c,d,e,f){var g=[[],[],[]],h=[[this.a,this.c,this.e],[this.b,this.d,this.f],[0,0,1]],i=[[a,c,e],[b,d,f],[0,0,1]],j,k,l,m;a&&a instanceof cb&&(i=[[a.a,a.c,a.e],[a.b,a.d,a.f],[0,0,1]]);for(j=0;j<3;j++)for(k=0;k<3;k++){m=0;for(l=0;l<3;l++)m+=h[j][l]*i[l][k];g[j][k]=m}this.a=g[0][0],this.b=g[1][0],this.c=g[0][1],this.d=g[1][1],this.e=g[0][2],this.f=g[1][2]},b.invert=function(){var a=this,b=a.a*a.d-a.b*a.c;return new cb(a.d/b,-a.b/b,-a.c/b,a.a/b,(a.c*a.f-a.d*a.e)/b,(a.b*a.e-a.a*a.f)/b)},b.clone=function(){return new cb(this.a,this.b,this.c,this.d,this.e,this.f)},b.translate=function(a,b){this.add(1,0,0,1,a,b)},b.scale=function(a,b,c,d){b==null&&(b=a),(c||d)&&this.add(1,0,0,1,c,d),this.add(a,0,0,b,0,0),(c||d)&&this.add(1,0,0,1,-c,-d)},b.rotate=function(b,c,d){b=a.rad(b),c=c||0,d=d||0;var e=+w.cos(b).toFixed(9),f=+w.sin(b).toFixed(9);this.add(e,f,-f,e,c,d),this.add(1,0,0,1,-c,-d)},b.x=function(a,b){return a*this.a+b*this.c+this.e},b.y=function(a,b){return a*this.b+b*this.d+this.f},b.get=function(a){return+this[r.fromCharCode(97+a)].toFixed(4)},b.toString=function(){return a.svg?\"matrix(\"+[this.get(0),this.get(1),this.get(2),this.get(3),this.get(4),this.get(5)].join()+\")\":[this.get(0),this.get(2),this.get(1),this.get(3),0,0].join()},b.toFilter=function(){return\"progid:DXImageTransform.Microsoft.Matrix(M11=\"+this.get(0)+\", M12=\"+this.get(2)+\", M21=\"+this.get(1)+\", M22=\"+this.get(3)+\", Dx=\"+this.get(4)+\", Dy=\"+this.get(5)+\", sizingmethod='auto expand')\"},b.offset=function(){return[this.e.toFixed(4),this.f.toFixed(4)]},b.split=function(){var b={};b.dx=this.e,b.dy=this.f;var e=[[this.a,this.c],[this.b,this.d]];b.scalex=w.sqrt(c(e[0])),d(e[0]),b.shear=e[0][0]*e[1][0]+e[0][1]*e[1][1],e[1]=[e[1][0]-e[0][0]*b.shear,e[1][1]-e[0][1]*b.shear],b.scaley=w.sqrt(c(e[1])),d(e[1]),b.shear/=b.scaley;var f=-e[0][1],g=e[1][1];g<0?(b.rotate=a.deg(w.acos(g)),f<0&&(b.rotate=360-b.rotate)):b.rotate=a.deg(w.asin(f)),b.isSimple=!+b.shear.toFixed(9)&&(b.scalex.toFixed(9)==b.scaley.toFixed(9)||!b.rotate),b.isSuperSimple=!+b.shear.toFixed(9)&&b.scalex.toFixed(9)==b.scaley.toFixed(9)&&!b.rotate,b.noRotation=!+b.shear.toFixed(9)&&!b.rotate;return b},b.toTransformString=function(a){var b=a||this[s]();if(b.isSimple){b.scalex=+b.scalex.toFixed(4),b.scaley=+b.scaley.toFixed(4),b.rotate=+b.rotate.toFixed(4);return(b.dx||b.dy?\"t\"+[b.dx,b.dy]:p)+(b.scalex!=1||b.scaley!=1?\"s\"+[b.scalex,b.scaley,0,0]:p)+(b.rotate?\"r\"+[b.rotate,0,0]:p)}return\"m\"+[this.get(0),this.get(1),this.get(2),this.get(3),this.get(4),this.get(5)]}}(cb.prototype);var cc=navigator.userAgent.match(/Version\\/(.*?)\\s/)||navigator.userAgent.match(/Chrome\\/(\\d+)/);navigator.vendor==\"Apple Computer, Inc.\"&&(cc&&cc[1]<4||navigator.platform.slice(0,2)==\"iP\")||navigator.vendor==\"Google Inc.\"&&cc&&cc[1]<8?k.safari=function(){var a=this.rect(-99,-99,this.width+99,this.height+99).attr({stroke:\"none\"});setTimeout(function(){a.remove()})}:k.safari=be;var cd=function(){this.returnValue=!1},ce=function(){return this.originalEvent.preventDefault()},cf=function(){this.cancelBubble=!0},cg=function(){return this.originalEvent.stopPropagation()},ch=function(){if(h.doc.addEventListener)return function(a,b,c,d){var e=o&&u[b]?u[b]:b,f=function(e){var f=h.doc.documentElement.scrollTop||h.doc.body.scrollTop,i=h.doc.documentElement.scrollLeft||h.doc.body.scrollLeft,j=e.clientX+i,k=e.clientY+f;if(o&&u[g](b))for(var l=0,m=e.targetTouches&&e.targetTouches.length;l<m;l++)if(e.targetTouches[l].target==a){var n=e;e=e.targetTouches[l],e.originalEvent=n,e.preventDefault=ce,e.stopPropagation=cg;break}return c.call(d,e,j,k)};a.addEventListener(e,f,!1);return function(){a.removeEventListener(e,f,!1);return!0}};if(h.doc.attachEvent)return function(a,b,c,d){var e=function(a){a=a||h.win.event;var b=h.doc.documentElement.scrollTop||h.doc.body.scrollTop,e=h.doc.documentElement.scrollLeft||h.doc.body.scrollLeft,f=a.clientX+e,g=a.clientY+b;a.preventDefault=a.preventDefault||cd,a.stopPropagation=a.stopPropagation||cf;return c.call(d,a,f,g)};a.attachEvent(\"on\"+b,e);var f=function(){a.detachEvent(\"on\"+b,e);return!0};return f}}(),ci=[],cj=function(a){var b=a.clientX,c=a.clientY,d=h.doc.documentElement.scrollTop||h.doc.body.scrollTop,e=h.doc.documentElement.scrollLeft||h.doc.body.scrollLeft,f,g=ci.length;while(g--){f=ci[g];if(o){var i=a.touches.length,j;while(i--){j=a.touches[i];if(j.identifier==f.el._drag.id){b=j.clientX,c=j.clientY,(a.originalEvent?a.originalEvent:a).preventDefault();break}}}else a.preventDefault();var k=f.el.node,l,m=k.nextSibling,n=k.parentNode,p=k.style.display;h.win.opera&&n.removeChild(k),k.style.display=\"none\",l=f.el.paper.getElementByPoint(b,c),k.style.display=p,h.win.opera&&(m?n.insertBefore(k,m):n.appendChild(k)),l&&eve(\"raphael.drag.over.\"+f.el.id,f.el,l),b+=e,c+=d,eve(\"raphael.drag.move.\"+f.el.id,f.move_scope||f.el,b-f.el._drag.x,c-f.el._drag.y,b,c,a)}},ck=function(b){a.unmousemove(cj).unmouseup(ck);var c=ci.length,d;while(c--)d=ci[c],d.el._drag={},eve(\"raphael.drag.end.\"+d.el.id,d.end_scope||d.start_scope||d.move_scope||d.el,b);ci=[]},cl=a.el={};for(var cm=t.length;cm--;)(function(b){a[b]=cl[b]=function(c,d){a.is(c,\"function\")&&(this.events=this.events||[],this.events.push({name:b,f:c,unbind:ch(this.shape||this.node||h.doc,b,c,d||this)}));return this},a[\"un\"+b]=cl[\"un\"+b]=function(a){var c=this.events||[],d=c.length;while(d--)if(c[d].name==b&&c[d].f==a){c[d].unbind(),c.splice(d,1),!c.length&&delete this.events;return this}return this}})(t[cm]);cl.data=function(b,c){var d=bb[this.id]=bb[this.id]||{};if(arguments.length==1){if(a.is(b,\"object\")){for(var e in b)b[g](e)&&this.data(e,b[e]);return this}eve(\"raphael.data.get.\"+this.id,this,d[b],b);return d[b]}d[b]=c,eve(\"raphael.data.set.\"+this.id,this,c,b);return this},cl.removeData=function(a){a==null?bb[this.id]={}:bb[this.id]&&delete bb[this.id][a];return this},cl.hover=function(a,b,c,d){return this.mouseover(a,c).mouseout(b,d||c)},cl.unhover=function(a,b){return this.unmouseover(a).unmouseout(b)};var cn=[];cl.drag=function(b,c,d,e,f,g){function i(i){(i.originalEvent||i).preventDefault();var j=h.doc.documentElement.scrollTop||h.doc.body.scrollTop,k=h.doc.documentElement.scrollLeft||h.doc.body.scrollLeft;this._drag.x=i.clientX+k,this._drag.y=i.clientY+j,this._drag.id=i.identifier,!ci.length&&a.mousemove(cj).mouseup(ck),ci.push({el:this,move_scope:e,start_scope:f,end_scope:g}),c&&eve.on(\"raphael.drag.start.\"+this.id,c),b&&eve.on(\"raphael.drag.move.\"+this.id,b),d&&eve.on(\"raphael.drag.end.\"+this.id,d),eve(\"raphael.drag.start.\"+this.id,f||e||this,i.clientX+k,i.clientY+j,i)}this._drag={},cn.push({el:this,start:i}),this.mousedown(i);return this},cl.onDragOver=function(a){a?eve.on(\"raphael.drag.over.\"+this.id,a):eve.unbind(\"raphael.drag.over.\"+this.id)},cl.undrag=function(){var b=cn.length;while(b--)cn[b].el==this&&(this.unmousedown(cn[b].start),cn.splice(b,1),eve.unbind(\"raphael.drag.*.\"+this.id));!cn.length&&a.unmousemove(cj).unmouseup(ck)},k.circle=function(b,c,d){var e=a._engine.circle(this,b||0,c||0,d||0);this.__set__&&this.__set__.push(e);return e},k.rect=function(b,c,d,e,f){var g=a._engine.rect(this,b||0,c||0,d||0,e||0,f||0);this.__set__&&this.__set__.push(g);return g},k.ellipse=function(b,c,d,e){var f=a._engine.ellipse(this,b||0,c||0,d||0,e||0);this.__set__&&this.__set__.push(f);return f},k.path=function(b){b&&!a.is(b,D)&&!a.is(b[0],E)&&(b+=p);var c=a._engine.path(a.format[m](a,arguments),this);this.__set__&&this.__set__.push(c);return c},k.image=function(b,c,d,e,f){var g=a._engine.image(this,b||\"about:blank\",c||0,d||0,e||0,f||0);this.__set__&&this.__set__.push(g);return g},k.text=function(b,c,d){var e=a._engine.text(this,b||0,c||0,r(d));this.__set__&&this.__set__.push(e);return e},k.set=function(b){!a.is(b,\"array\")&&(b=Array.prototype.splice.call(arguments,0,arguments.length));var c=new cG(b);this.__set__&&this.__set__.push(c);return c},k.setStart=function(a){this.__set__=a||this.set()},k.setFinish=function(a){var b=this.__set__;delete this.__set__;return b},k.setSize=function(b,c){return a._engine.setSize.call(this,b,c)},k.setViewBox=function(b,c,d,e,f){return a._engine.setViewBox.call(this,b,c,d,e,f)},k.top=k.bottom=null,k.raphael=a;var co=function(a){var b=a.getBoundingClientRect(),c=a.ownerDocument,d=c.body,e=c.documentElement,f=e.clientTop||d.clientTop||0,g=e.clientLeft||d.clientLeft||0,i=b.top+(h.win.pageYOffset||e.scrollTop||d.scrollTop)-f,j=b.left+(h.win.pageXOffset||e.scrollLeft||d.scrollLeft)-g;return{y:i,x:j}};k.getElementByPoint=function(a,b){var c=this,d=c.canvas,e=h.doc.elementFromPoint(a,b);if(h.win.opera&&e.tagName==\"svg\"){var f=co(d),g=d.createSVGRect();g.x=a-f.x,g.y=b-f.y,g.width=g.height=1;var i=d.getIntersectionList(g,null);i.length&&(e=i[i.length-1])}if(!e)return null;while(e.parentNode&&e!=d.parentNode&&!e.raphael)e=e.parentNode;e==c.canvas.parentNode&&(e=d),e=e&&e.raphael?c.getById(e.raphaelid):null;return e},k.getById=function(a){var b=this.bottom;while(b){if(b.id==a)return b;b=b.next}return null},k.forEach=function(a,b){var c=this.bottom;while(c){if(a.call(b,c)===!1)return this;c=c.next}return this},k.getElementsByPoint=function(a,b){var c=this.set();this.forEach(function(d){d.isPointInside(a,b)&&c.push(d)});return c},cl.isPointInside=function(b,c){var d=this.realPath=this.realPath||bi[this.type](this);return a.isPointInsidePath(d,b,c)},cl.getBBox=function(a){if(this.removed)return{};var b=this._;if(a){if(b.dirty||!b.bboxwt)this.realPath=bi[this.type](this),b.bboxwt=bI(this.realPath),b.bboxwt.toString=cq,b.dirty=0;return b.bboxwt}if(b.dirty||b.dirtyT||!b.bbox){if(b.dirty||!this.realPath)b.bboxwt=0,this.realPath=bi[this.type](this);b.bbox=bI(bj(this.realPath,this.matrix)),b.bbox.toString=cq,b.dirty=b.dirtyT=0}return b.bbox},cl.clone=function(){if(this.removed)return null;var a=this.paper[this.type]().attr(this.attr());this.__set__&&this.__set__.push(a);return a},cl.glow=function(a){if(this.type==\"text\")return null;a=a||{};var b={width:(a.width||10)+(+this.attr(\"stroke-width\")||1),fill:a.fill||!1,opacity:a.opacity||.5,offsetx:a.offsetx||0,offsety:a.offsety||0,color:a.color||\"#000\"},c=b.width/2,d=this.paper,e=d.set(),f=this.realPath||bi[this.type](this);f=this.matrix?bj(f,this.matrix):f;for(var g=1;g<c+1;g++)e.push(d.path(f).attr({stroke:b.color,fill:b.fill?b.color:\"none\",\"stroke-linejoin\":\"round\",\"stroke-linecap\":\"round\",\"stroke-width\":+(b.width/c*g).toFixed(3),opacity:+(b.opacity/c).toFixed(3)}));return e.insertBefore(this).translate(b.offsetx,b.offsety)};var cr={},cs=function(b,c,d,e,f,g,h,i,j){return j==null?bB(b,c,d,e,f,g,h,i):a.findDotsAtSegment(b,c,d,e,f,g,h,i,bC(b,c,d,e,f,g,h,i,j))},ct=function(b,c){return function(d,e,f){d=bR(d);var g,h,i,j,k=\"\",l={},m,n=0;for(var o=0,p=d.length;o<p;o++){i=d[o];if(i[0]==\"M\")g=+i[1],h=+i[2];else{j=cs(g,h,i[1],i[2],i[3],i[4],i[5],i[6]);if(n+j>e){if(c&&!l.start){m=cs(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n),k+=[\"C\"+m.start.x,m.start.y,m.m.x,m.m.y,m.x,m.y];if(f)return k;l.start=k,k=[\"M\"+m.x,m.y+\"C\"+m.n.x,m.n.y,m.end.x,m.end.y,i[5],i[6]].join(),n+=j,g=+i[5],h=+i[6];continue}if(!b&&!c){m=cs(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n);return{x:m.x,y:m.y,alpha:m.alpha}}}n+=j,g=+i[5],h=+i[6]}k+=i.shift()+i}l.end=k,m=b?n:c?l:a.findDotsAtSegment(g,h,i[0],i[1],i[2],i[3],i[4],i[5],1),m.alpha&&(m={x:m.x,y:m.y,alpha:m.alpha});return m}},cu=ct(1),cv=ct(),cw=ct(0,1);a.getTotalLength=cu,a.getPointAtLength=cv,a.getSubpath=function(a,b,c){if(this.getTotalLength(a)-c<1e-6)return cw(a,b).end;var d=cw(a,c,1);return b?cw(d,b).end:d},cl.getTotalLength=function(){if(this.type==\"path\"){if(this.node.getTotalLength)return this.node.getTotalLength();return cu(this.attrs.path)}},cl.getPointAtLength=function(a){if(this.type==\"path\")return cv(this.attrs.path,a)},cl.getSubpath=function(b,c){if(this.type==\"path\")return a.getSubpath(this.attrs.path,b,c)};var cx=a.easing_formulas={linear:function(a){return a},\"<\":function(a){return A(a,1.7)},\">\":function(a){return A(a,.48)},\"<>\":function(a){var b=.48-a/1.04,c=w.sqrt(.1734+b*b),d=c-b,e=A(z(d),1/3)*(d<0?-1:1),f=-c-b,g=A(z(f),1/3)*(f<0?-1:1),h=e+g+.5;return(1-h)*3*h*h+h*h*h},backIn:function(a){var b=1.70158;return a*a*((b+1)*a-b)},backOut:function(a){a=a-1;var b=1.70158;return a*a*((b+1)*a+b)+1},elastic:function(a){if(a==!!a)return a;return A(2,-10*a)*w.sin((a-.075)*2*B/.3)+1},bounce:function(a){var b=7.5625,c=2.75,d;a<1/c?d=b*a*a:a<2/c?(a-=1.5/c,d=b*a*a+.75):a<2.5/c?(a-=2.25/c,d=b*a*a+.9375):(a-=2.625/c,d=b*a*a+.984375);return d}};cx.easeIn=cx[\"ease-in\"]=cx[\"<\"],cx.easeOut=cx[\"ease-out\"]=cx[\">\"],cx.easeInOut=cx[\"ease-in-out\"]=cx[\"<>\"],cx[\"back-in\"]=cx.backIn,cx[\"back-out\"]=cx.backOut;var cy=[],cz=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){setTimeout(a,16)},cA=function(){var b=+(new Date),c=0;for(;c<cy.length;c++){var d=cy[c];if(d.el.removed||d.paused)continue;var e=b-d.start,f=d.ms,h=d.easing,i=d.from,j=d.diff,k=d.to,l=d.t,m=d.el,o={},p,r={},s;d.initstatus?(e=(d.initstatus*d.anim.top-d.prev)/(d.percent-d.prev)*f,d.status=d.initstatus,delete d.initstatus,d.stop&&cy.splice(c--,1)):d.status=(d.prev+(d.percent-d.prev)*(e/f))/d.anim.top;if(e<0)continue;if(e<f){var t=h(e/f);for(var u in i)if(i[g](u)){switch(U[u]){case C:p=+i[u]+t*f*j[u];break;case\"colour\":p=\"rgb(\"+[cB(O(i[u].r+t*f*j[u].r)),cB(O(i[u].g+t*f*j[u].g)),cB(O(i[u].b+t*f*j[u].b))].join(\",\")+\")\";break;case\"path\":p=[];for(var v=0,w=i[u].length;v<w;v++){p[v]=[i[u][v][0]];for(var x=1,y=i[u][v].length;x<y;x++)p[v][x]=+i[u][v][x]+t*f*j[u][v][x];p[v]=p[v].join(q)}p=p.join(q);break;case\"transform\":if(j[u].real){p=[];for(v=0,w=i[u].length;v<w;v++){p[v]=[i[u][v][0]];for(x=1,y=i[u][v].length;x<y;x++)p[v][x]=i[u][v][x]+t*f*j[u][v][x]}}else{var z=function(a){return+i[u][a]+t*f*j[u][a]};p=[[\"m\",z(0),z(1),z(2),z(3),z(4),z(5)]]}break;case\"csv\":if(u==\"clip-rect\"){p=[],v=4;while(v--)p[v]=+i[u][v]+t*f*j[u][v]}break;default:var A=[][n](i[u]);p=[],v=m.paper.customAttributes[u].length;while(v--)p[v]=+A[v]+t*f*j[u][v]}o[u]=p}m.attr(o),function(a,b,c){setTimeout(function(){eve(\"raphael.anim.frame.\"+a,b,c)})}(m.id,m,d.anim)}else{(function(b,c,d){setTimeout(function(){eve(\"raphael.anim.frame.\"+c.id,c,d),eve(\"raphael.anim.finish.\"+c.id,c,d),a.is(b,\"function\")&&b.call(c)})})(d.callback,m,d.anim),m.attr(k),cy.splice(c--,1);if(d.repeat>1&&!d.next){for(s in k)k[g](s)&&(r[s]=d.totalOrigin[s]);d.el.attr(r),cE(d.anim,d.el,d.anim.percents[0],null,d.totalOrigin,d.repeat-1)}d.next&&!d.stop&&cE(d.anim,d.el,d.next,null,d.totalOrigin,d.repeat)}}a.svg&&m&&m.paper&&m.paper.safari(),cy.length&&cz(cA)},cB=function(a){return a>255?255:a<0?0:a};cl.animateWith=function(b,c,d,e,f,g){var h=this;if(h.removed){g&&g.call(h);return h}var i=d instanceof cD?d:a.animation(d,e,f,g),j,k;cE(i,h,i.percents[0],null,h.attr());for(var l=0,m=cy.length;l<m;l++)if(cy[l].anim==c&&cy[l].el==b){cy[m-1].start=cy[l].start;break}return h},cl.onAnimation=function(a){a?eve.on(\"raphael.anim.frame.\"+this.id,a):eve.unbind(\"raphael.anim.frame.\"+this.id);return this},cD.prototype.delay=function(a){var b=new cD(this.anim,this.ms);b.times=this.times,b.del=+a||0;return b},cD.prototype.repeat=function(a){var b=new cD(this.anim,this.ms);b.del=this.del,b.times=w.floor(x(a,0))||1;return b},a.animation=function(b,c,d,e){if(b instanceof cD)return b;if(a.is(d,\"function\")||!d)e=e||d||null,d=null;b=Object(b),c=+c||0;var f={},h,i;for(i in b)b[g](i)&&Q(i)!=i&&Q(i)+\"%\"!=i&&(h=!0,f[i]=b[i]);if(!h)return new cD(b,c);d&&(f.easing=d),e&&(f.callback=e);return new cD({100:f},c)},cl.animate=function(b,c,d,e){var f=this;if(f.removed){e&&e.call(f);return f}var g=b instanceof cD?b:a.animation(b,c,d,e);cE(g,f,g.percents[0],null,f.attr());return f},cl.setTime=function(a,b){a&&b!=null&&this.status(a,y(b,a.ms)/a.ms);return this},cl.status=function(a,b){var c=[],d=0,e,f;if(b!=null){cE(a,this,-1,y(b,1));return this}e=cy.length;for(;d<e;d++){f=cy[d];if(f.el.id==this.id&&(!a||f.anim==a)){if(a)return f.status;c.push({anim:f.anim,status:f.status})}}if(a)return 0;return c},cl.pause=function(a){for(var b=0;b<cy.length;b++)cy[b].el.id==this.id&&(!a||cy[b].anim==a)&&eve(\"raphael.anim.pause.\"+this.id,this,cy[b].anim)!==!1&&(cy[b].paused=!0);return this},cl.resume=function(a){for(var b=0;b<cy.length;b++)if(cy[b].el.id==this.id&&(!a||cy[b].anim==a)){var c=cy[b];eve(\"raphael.anim.resume.\"+this.id,this,c.anim)!==!1&&(delete c.paused,this.status(c.anim,c.status))}return this},cl.stop=function(a){for(var b=0;b<cy.length;b++)cy[b].el.id==this.id&&(!a||cy[b].anim==a)&&eve(\"raphael.anim.stop.\"+this.id,this,cy[b].anim)!==!1&&cy.splice(b--,1);return this},eve.on(\"raphael.remove\",cF),eve.on(\"raphael.clear\",cF),cl.toString=function(){return\"Raphaël’s object\"};var cG=function(a){this.items=[],this.length=0,this.type=\"set\";if(a)for(var b=0,c=a.length;b<c;b++)a[b]&&(a[b].constructor==cl.constructor||a[b].constructor==cG)&&(this[this.items.length]=this.items[this.items.length]=a[b],this.length++)},cH=cG.prototype;cH.push=function(){var a,b;for(var c=0,d=arguments.length;c<d;c++)a=arguments[c],a&&(a.constructor==cl.constructor||a.constructor==cG)&&(b=this.items.length,this[b]=this.items[b]=a,this.length++);return this},cH.pop=function(){this.length&&delete this[this.length--];return this.items.pop()},cH.forEach=function(a,b){for(var c=0,d=this.items.length;c<d;c++)if(a.call(b,this.items[c],c)===!1)return this;return this};for(var cI in cl)cl[g](cI)&&(cH[cI]=function(a){return function(){var b=arguments;return this.forEach(function(c){c[a][m](c,b)})}}(cI));cH.attr=function(b,c){if(b&&a.is(b,E)&&a.is(b[0],\"object\"))for(var d=0,e=b.length;d<e;d++)this.items[d].attr(b[d]);else for(var f=0,g=this.items.length;f<g;f++)this.items[f].attr(b,c);return this},cH.clear=function(){while(this.length)this.pop()},cH.splice=function(a,b,c){a=a<0?x(this.length+a,0):a,b=x(0,y(this.length-a,b));var d=[],e=[],f=[],g;for(g=2;g<arguments.length;g++)f.push(arguments[g]);for(g=0;g<b;g++)e.push(this[a+g]);for(;g<this.length-a;g++)d.push(this[a+g]);var h=f.length;for(g=0;g<h+d.length;g++)this.items[a+g]=this[a+g]=g<h?f[g]:d[g-h];g=this.items.length=this.length-=b-h;while(this[g])delete this[g++];return new cG(e)},cH.exclude=function(a){for(var b=0,c=this.length;b<c;b++)if(this[b]==a){this.splice(b,1);return!0}},cH.animate=function(b,c,d,e){(a.is(d,\"function\")||!d)&&(e=d||null);var f=this.items.length,g=f,h,i=this,j;if(!f)return this;e&&(j=function(){!--f&&e.call(i)}),d=a.is(d,D)?d:j;var k=a.animation(b,c,d,j);h=this.items[--g].animate(k);while(g--)this.items[g]&&!this.items[g].removed&&this.items[g].animateWith(h,k,k);return this},cH.insertAfter=function(a){var b=this.items.length;while(b--)this.items[b].insertAfter(a);return this},cH.getBBox=function(){var a=[],b=[],c=[],d=[];for(var e=this.items.length;e--;)if(!this.items[e].removed){var f=this.items[e].getBBox();a.push(f.x),b.push(f.y),c.push(f.x+f.width),d.push(f.y+f.height)}a=y[m](0,a),b=y[m](0,b),c=x[m](0,c),d=x[m](0,d);return{x:a,y:b,x2:c,y2:d,width:c-a,height:d-b}},cH.clone=function(a){a=new cG;for(var b=0,c=this.items.length;b<c;b++)a.push(this.items[b].clone());return a},cH.toString=function(){return\"Raphaël‘s set\"},a.registerFont=function(a){if(!a.face)return a;this.fonts=this.fonts||{};var b={w:a.w,face:{},glyphs:{}},c=a.face[\"font-family\"];for(var d in a.face)a.face[g](d)&&(b.face[d]=a.face[d]);this.fonts[c]?this.fonts[c].push(b):this.fonts[c]=[b];if(!a.svg){b.face[\"units-per-em\"]=R(a.face[\"units-per-em\"],10);for(var e in a.glyphs)if(a.glyphs[g](e)){var f=a.glyphs[e];b.glyphs[e]={w:f.w,k:{},d:f.d&&\"M\"+f.d.replace(/[mlcxtrv]/g,function(a){return{l:\"L\",c:\"C\",x:\"z\",t:\"m\",r:\"l\",v:\"c\"}[a]||\"M\"})+\"z\"};if(f.k)for(var h in f.k)f[g](h)&&(b.glyphs[e].k[h]=f.k[h])}}return a},k.getFont=function(b,c,d,e){e=e||\"normal\",d=d||\"normal\",c=+c||{normal:400,bold:700,lighter:300,bolder:800}[c]||400;if(!!a.fonts){var f=a.fonts[b];if(!f){var h=new RegExp(\"(^|\\\\s)\"+b.replace(/[^\\w\\d\\s+!~.:_-]/g,p)+\"(\\\\s|$)\",\"i\");for(var i in a.fonts)if(a.fonts[g](i)&&h.test(i)){f=a.fonts[i];break}}var j;if(f)for(var k=0,l=f.length;k<l;k++){j=f[k];if(j.face[\"font-weight\"]==c&&(j.face[\"font-style\"]==d||!j.face[\"font-style\"])&&j.face[\"font-stretch\"]==e)break}return j}},k.print=function(b,d,e,f,g,h,i){h=h||\"middle\",i=x(y(i||0,1),-1);var j=r(e)[s](p),k=0,l=0,m=p,n;a.is(f,e)&&(f=this.getFont(f));if(f){n=(g||16)/f.face[\"units-per-em\"];var o=f.face.bbox[s](c),q=+o[0],t=o[3]-o[1],u=0,v=+o[1]+(h==\"baseline\"?t+ +f.face.descent:t/2);for(var w=0,z=j.length;w<z;w++){if(j[w]==\"\\n\")k=0,B=0,l=0,u+=t;else{var A=l&&f.glyphs[j[w-1]]||{},B=f.glyphs[j[w]];k+=l?(A.w||f.w)+(A.k&&A.k[j[w]]||0)+f.w*i:0,l=1}B&&B.d&&(m+=a.transformPath(B.d,[\"t\",k*n,u*n,\"s\",n,n,q,v,\"t\",(b-q)/n,(d-v)/n]))}}return this.path(m).attr({fill:\"#000\",stroke:\"none\"})},k.add=function(b){if(a.is(b,\"array\")){var c=this.set(),e=0,f=b.length,h;for(;e<f;e++)h=b[e]||{},d[g](h.type)&&c.push(this[h.type]().attr(h))}return c},a.format=function(b,c){var d=a.is(c,E)?[0][n](c):arguments;b&&a.is(b,D)&&d.length-1&&(b=b.replace(e,function(a,b){return d[++b]==null?p:d[b]}));return b||p},a.fullfill=function(){var a=/\\{([^\\}]+)\\}/g,b=/(?:(?:^|\\.)(.+?)(?=\\[|\\.|$|\\()|\\[('|\")(.+?)\\2\\])(\\(\\))?/g,c=function(a,c,d){var e=d;c.replace(b,function(a,b,c,d,f){b=b||d,e&&(b in e&&(e=e[b]),typeof e==\"function\"&&f&&(e=e()))}),e=(e==null||e==d?a:e)+\"\";return e};return function(b,d){return String(b).replace(a,function(a,b){return c(a,b,d)})}}(),a.ninja=function(){i.was?h.win.Raphael=i.is:delete Raphael;return a},a.st=cH,function(b,c,d){function e(){/in/.test(b.readyState)?setTimeout(e,9):a.eve(\"raphael.DOMload\")}b.readyState==null&&b.addEventListener&&(b.addEventListener(c,d=function(){b.removeEventListener(c,d,!1),b.readyState=\"complete\"},!1),b.readyState=\"loading\"),e()}(document,\"DOMContentLoaded\"),i.was?h.win.Raphael=a:Raphael=a,eve.on(\"raphael.DOMload\",function(){b=!0})}(),window.Raphael.svg&&function(a){var b=\"hasOwnProperty\",c=String,d=parseFloat,e=parseInt,f=Math,g=f.max,h=f.abs,i=f.pow,j=/[, ]+/,k=a.eve,l=\"\",m=\" \",n=\"http://www.w3.org/1999/xlink\",o={block:\"M5,0 0,2.5 5,5z\",classic:\"M5,0 0,2.5 5,5 3.5,3 3.5,2z\",diamond:\"M2.5,0 5,2.5 2.5,5 0,2.5z\",open:\"M6,1 1,3.5 6,6\",oval:\"M2.5,0A2.5,2.5,0,0,1,2.5,5 2.5,2.5,0,0,1,2.5,0z\"},p={};a.toString=function(){return\"Your browser supports SVG.\\nYou are running Raphaël \"+this.version};var q=function(d,e){if(e){typeof d==\"string\"&&(d=q(d));for(var f in e)e[b](f)&&(f.substring(0,6)==\"xlink:\"?d.setAttributeNS(n,f.substring(6),c(e[f])):d.setAttribute(f,c(e[f])))}else d=a._g.doc.createElementNS(\"http://www.w3.org/2000/svg\",d),d.style&&(d.style.webkitTapHighlightColor=\"rgba(0,0,0,0)\");return d},r=function(b,e){var j=\"linear\",k=b.id+e,m=.5,n=.5,o=b.node,p=b.paper,r=o.style,s=a._g.doc.getElementById(k);if(!s){e=c(e).replace(a._radial_gradient,function(a,b,c){j=\"radial\";if(b&&c){m=d(b),n=d(c);var e=(n>.5)*2-1;i(m-.5,2)+i(n-.5,2)>.25&&(n=f.sqrt(.25-i(m-.5,2))*e+.5)&&n!=.5&&(n=n.toFixed(5)-1e-5*e)}return l}),e=e.split(/\\s*\\-\\s*/);if(j==\"linear\"){var t=e.shift();t=-d(t);if(isNaN(t))return null;var u=[0,0,f.cos(a.rad(t)),f.sin(a.rad(t))],v=1/(g(h(u[2]),h(u[3]))||1);u[2]*=v,u[3]*=v,u[2]<0&&(u[0]=-u[2],u[2]=0),u[3]<0&&(u[1]=-u[3],u[3]=0)}var w=a._parseDots(e);if(!w)return null;k=k.replace(/[\\(\\)\\s,\\xb0#]/g,\"_\"),b.gradient&&k!=b.gradient.id&&(p.defs.removeChild(b.gradient),delete b.gradient);if(!b.gradient){s=q(j+\"Gradient\",{id:k}),b.gradient=s,q(s,j==\"radial\"?{fx:m,fy:n}:{x1:u[0],y1:u[1],x2:u[2],y2:u[3],gradientTransform:b.matrix.invert()}),p.defs.appendChild(s);for(var x=0,y=w.length;x<y;x++)s.appendChild(q(\"stop\",{offset:w[x].offset?w[x].offset:x?\"100%\":\"0%\",\"stop-color\":w[x].color||\"#fff\"}))}}q(o,{fill:\"url(#\"+k+\")\",opacity:1,\"fill-opacity\":1}),r.fill=l,r.opacity=1,r.fillOpacity=1;return 1},s=function(a){var b=a.getBBox(1);q(a.pattern,{patternTransform:a.matrix.invert()+\" translate(\"+b.x+\",\"+b.y+\")\"})},t=function(d,e,f){if(d.type==\"path\"){var g=c(e).toLowerCase().split(\"-\"),h=d.paper,i=f?\"end\":\"start\",j=d.node,k=d.attrs,m=k[\"stroke-width\"],n=g.length,r=\"classic\",s,t,u,v,w,x=3,y=3,z=5;while(n--)switch(g[n]){case\"block\":case\"classic\":case\"oval\":case\"diamond\":case\"open\":case\"none\":r=g[n];break;case\"wide\":y=5;break;case\"narrow\":y=2;break;case\"long\":x=5;break;case\"short\":x=2}r==\"open\"?(x+=2,y+=2,z+=2,u=1,v=f?4:1,w={fill:\"none\",stroke:k.stroke}):(v=u=x/2,w={fill:k.stroke,stroke:\"none\"}),d._.arrows?f?(d._.arrows.endPath&&p[d._.arrows.endPath]--,d._.arrows.endMarker&&p[d._.arrows.endMarker]--):(d._.arrows.startPath&&p[d._.arrows.startPath]--,d._.arrows.startMarker&&p[d._.arrows.startMarker]--):d._.arrows={};if(r!=\"none\"){var A=\"raphael-marker-\"+r,B=\"raphael-marker-\"+i+r+x+y;a._g.doc.getElementById(A)?p[A]++:(h.defs.appendChild(q(q(\"path\"),{\"stroke-linecap\":\"round\",d:o[r],id:A})),p[A]=1);var C=a._g.doc.getElementById(B),D;C?(p[B]++,D=C.getElementsByTagName(\"use\")[0]):(C=q(q(\"marker\"),{id:B,markerHeight:y,markerWidth:x,orient:\"auto\",refX:v,refY:y/2}),D=q(q(\"use\"),{\"xlink:href\":\"#\"+A,transform:(f?\"rotate(180 \"+x/2+\" \"+y/2+\") \":l)+\"scale(\"+x/z+\",\"+y/z+\")\",\"stroke-width\":(1/((x/z+y/z)/2)).toFixed(4)}),C.appendChild(D),h.defs.appendChild(C),p[B]=1),q(D,w);var F=u*(r!=\"diamond\"&&r!=\"oval\");f?(s=d._.arrows.startdx*m||0,t=a.getTotalLength(k.path)-F*m):(s=F*m,t=a.getTotalLength(k.path)-(d._.arrows.enddx*m||0)),w={},w[\"marker-\"+i]=\"url(#\"+B+\")\";if(t||s)w.d=Raphael.getSubpath(k.path,s,t);q(j,w),d._.arrows[i+\"Path\"]=A,d._.arrows[i+\"Marker\"]=B,d._.arrows[i+\"dx\"]=F,d._.arrows[i+\"Type\"]=r,d._.arrows[i+\"String\"]=e}else f?(s=d._.arrows.startdx*m||0,t=a.getTotalLength(k.path)-s):(s=0,t=a.getTotalLength(k.path)-(d._.arrows.enddx*m||0)),d._.arrows[i+\"Path\"]&&q(j,{d:Raphael.getSubpath(k.path,s,t)}),delete d._.arrows[i+\"Path\"],delete d._.arrows[i+\"Marker\"],delete d._.arrows[i+\"dx\"],delete d._.arrows[i+\"Type\"],delete d._.arrows[i+\"String\"];for(w in p)if(p[b](w)&&!p[w]){var G=a._g.doc.getElementById(w);G&&G.parentNode.removeChild(G)}}},u={\"\":[0],none:[0],\"-\":[3,1],\".\":[1,1],\"-.\":[3,1,1,1],\"-..\":[3,1,1,1,1,1],\". \":[1,3],\"- \":[4,3],\"--\":[8,3],\"- .\":[4,3,1,3],\"--.\":[8,3,1,3],\"--..\":[8,3,1,3,1,3]},v=function(a,b,d){b=u[c(b).toLowerCase()];if(b){var e=a.attrs[\"stroke-width\"]||\"1\",f={round:e,square:e,butt:0}[a.attrs[\"stroke-linecap\"]||d[\"stroke-linecap\"]]||0,g=[],h=b.length;while(h--)g[h]=b[h]*e+(h%2?1:-1)*f;q(a.node,{\"stroke-dasharray\":g.join(\",\")})}},w=function(d,f){var i=d.node,k=d.attrs,m=i.style.visibility;i.style.visibility=\"hidden\";for(var o in f)if(f[b](o)){if(!a._availableAttrs[b](o))continue;var p=f[o];k[o]=p;switch(o){case\"blur\":d.blur(p);break;case\"href\":case\"title\":case\"target\":var u=i.parentNode;if(u.tagName.toLowerCase()!=\"a\"){var w=q(\"a\");u.insertBefore(w,i),w.appendChild(i),u=w}o==\"target\"?u.setAttributeNS(n,\"show\",p==\"blank\"?\"new\":p):u.setAttributeNS(n,o,p);break;case\"cursor\":i.style.cursor=p;break;case\"transform\":d.transform(p);break;case\"arrow-start\":t(d,p);break;case\"arrow-end\":t(d,p,1);break;case\"clip-rect\":var x=c(p).split(j);if(x.length==4){d.clip&&d.clip.parentNode.parentNode.removeChild(d.clip.parentNode);var z=q(\"clipPath\"),A=q(\"rect\");z.id=a.createUUID(),q(A,{x:x[0],y:x[1],width:x[2],height:x[3]}),z.appendChild(A),d.paper.defs.appendChild(z),q(i,{\"clip-path\":\"url(#\"+z.id+\")\"}),d.clip=A}if(!p){var B=i.getAttribute(\"clip-path\");if(B){var C=a._g.doc.getElementById(B.replace(/(^url\\(#|\\)$)/g,l));C&&C.parentNode.removeChild(C),q(i,{\"clip-path\":l}),delete d.clip}}break;case\"path\":d.type==\"path\"&&(q(i,{d:p?k.path=a._pathToAbsolute(p):\"M0,0\"}),d._.dirty=1,d._.arrows&&(\"startString\"in d._.arrows&&t(d,d._.arrows.startString),\"endString\"in d._.arrows&&t(d,d._.arrows.endString,1)));break;case\"width\":i.setAttribute(o,p),d._.dirty=1;if(k.fx)o=\"x\",p=k.x;else break;case\"x\":k.fx&&(p=-k.x-(k.width||0));case\"rx\":if(o==\"rx\"&&d.type==\"rect\")break;case\"cx\":i.setAttribute(o,p),d.pattern&&s(d),d._.dirty=1;break;case\"height\":i.setAttribute(o,p),d._.dirty=1;if(k.fy)o=\"y\",p=k.y;else break;case\"y\":k.fy&&(p=-k.y-(k.height||0));case\"ry\":if(o==\"ry\"&&d.type==\"rect\")break;case\"cy\":i.setAttribute(o,p),d.pattern&&s(d),d._.dirty=1;break;case\"r\":d.type==\"rect\"?q(i,{rx:p,ry:p}):i.setAttribute(o,p),d._.dirty=1;break;case\"src\":d.type==\"image\"&&i.setAttributeNS(n,\"href\",p);break;case\"stroke-width\":if(d._.sx!=1||d._.sy!=1)p/=g(h(d._.sx),h(d._.sy))||1;d.paper._vbSize&&(p*=d.paper._vbSize),i.setAttribute(o,p),k[\"stroke-dasharray\"]&&v(d,k[\"stroke-dasharray\"],f),d._.arrows&&(\"startString\"in d._.arrows&&t(d,d._.arrows.startString),\"endString\"in d._.arrows&&t(d,d._.arrows.endString,1));break;case\"stroke-dasharray\":v(d,p,f);break;case\"fill\":var D=c(p).match(a._ISURL);if(D){z=q(\"pattern\");var F=q(\"image\");z.id=a.createUUID(),q(z,{x:0,y:0,patternUnits:\"userSpaceOnUse\",height:1,width:1}),q(F,{x:0,y:0,\"xlink:href\":D[1]}),z.appendChild(F),function(b){a._preload(D[1],function(){var a=this.offsetWidth,c=this.offsetHeight;q(b,{width:a,height:c}),q(F,{width:a,height:c}),d.paper.safari()})}(z),d.paper.defs.appendChild(z),q(i,{fill:\"url(#\"+z.id+\")\"}),d.pattern=z,d.pattern&&s(d);break}var G=a.getRGB(p);if(!G.error)delete f.gradient,delete k.gradient,!a.is(k.opacity,\"undefined\")&&a.is(f.opacity,\"undefined\")&&q(i,{opacity:k.opacity}),!a.is(k[\"fill-opacity\"],\"undefined\")&&a.is(f[\"fill-opacity\"],\"undefined\")&&q(i,{\"fill-opacity\":k[\"fill-opacity\"]});else if((d.type==\"circle\"||d.type==\"ellipse\"||c(p).charAt()!=\"r\")&&r(d,p)){if(\"opacity\"in k||\"fill-opacity\"in k){var H=a._g.doc.getElementById(i.getAttribute(\"fill\").replace(/^url\\(#|\\)$/g,l));if(H){var I=H.getElementsByTagName(\"stop\");q(I[I.length-1],{\"stop-opacity\":(\"opacity\"in k?k.opacity:1)*(\"fill-opacity\"in k?k[\"fill-opacity\"]:1)})}}k.gradient=p,k.fill=\"none\";break}G[b](\"opacity\")&&q(i,{\"fill-opacity\":G.opacity>1?G.opacity/100:G.opacity});case\"stroke\":G=a.getRGB(p),i.setAttribute(o,G.hex),o==\"stroke\"&&G[b](\"opacity\")&&q(i,{\"stroke-opacity\":G.opacity>1?G.opacity/100:G.opacity}),o==\"stroke\"&&d._.arrows&&(\"startString\"in d._.arrows&&t(d,d._.arrows.startString),\"endString\"in d._.arrows&&t(d,d._.arrows.endString,1));break;case\"gradient\":(d.type==\"circle\"||d.type==\"ellipse\"||c(p).charAt()!=\"r\")&&r(d,p);break;case\"opacity\":k.gradient&&!k[b](\"stroke-opacity\")&&q(i,{\"stroke-opacity\":p>1?p/100:p});case\"fill-opacity\":if(k.gradient){H=a._g.doc.getElementById(i.getAttribute(\"fill\").replace(/^url\\(#|\\)$/g,l)),H&&(I=H.getElementsByTagName(\"stop\"),q(I[I.length-1],{\"stop-opacity\":p}));break};default:o==\"font-size\"&&(p=e(p,10)+\"px\");var J=o.replace(/(\\-.)/g,function(a){return a.substring(1).toUpperCase()});i.style[J]=p,d._.dirty=1,i.setAttribute(o,p)}}y(d,f),i.style.visibility=m},x=1.2,y=function(d,f){if(d.type==\"text\"&&!!(f[b](\"text\")||f[b](\"font\")||f[b](\"font-size\")||f[b](\"x\")||f[b](\"y\"))){var g=d.attrs,h=d.node,i=h.firstChild?e(a._g.doc.defaultView.getComputedStyle(h.firstChild,l).getPropertyValue(\"font-size\"),10):10;if(f[b](\"text\")){g.text=f.text;while(h.firstChild)h.removeChild(h.firstChild);var j=c(f.text).split(\"\\n\"),k=[],m;for(var n=0,o=j.length;n<o;n++)m=q(\"tspan\"),n&&q(m,{dy:i*x,x:g.x}),m.appendChild(a._g.doc.createTextNode(j[n])),h.appendChild(m),k[n]=m}else{k=h.getElementsByTagName(\"tspan\");for(n=0,o=k.length;n<o;n++)n?q(k[n],{dy:i*x,x:g.x}):q(k[0],{dy:0})}q(h,{x:g.x,y:g.y}),d._.dirty=1;var p=d._getBBox(),r=g.y-(p.y+p.height/2);r&&a.is(r,\"finite\")&&q(k[0],{dy:r})}},z=function(b,c){var d=0,e=0;this[0]=this.node=b,b.raphael=!0,this.id=a._oid++,b.raphaelid=this.id,this.matrix=a.matrix(),this.realPath=null,this.paper=c,this.attrs=this.attrs||{},this._={transform:[],sx:1,sy:1,deg:0,dx:0,dy:0,dirty:1},!c.bottom&&(c.bottom=this),this.prev=c.top,c.top&&(c.top.next=this),c.top=this,this.next=null},A=a.el;z.prototype=A,A.constructor=z,a._engine.path=function(a,b){var c=q(\"path\");b.canvas&&b.canvas.appendChild(c);var d=new z(c,b);d.type=\"path\",w(d,{fill:\"none\",stroke:\"#000\",path:a});return d},A.rotate=function(a,b,e){if(this.removed)return this;a=c(a).split(j),a.length-1&&(b=d(a[1]),e=d(a[2])),a=d(a[0]),e==null&&(b=e);if(b==null||e==null){var f=this.getBBox(1);b=f.x+f.width/2,e=f.y+f.height/2}this.transform(this._.transform.concat([[\"r\",a,b,e]]));return this},A.scale=function(a,b,e,f){if(this.removed)return this;a=c(a).split(j),a.length-1&&(b=d(a[1]),e=d(a[2]),f=d(a[3])),a=d(a[0]),b==null&&(b=a),f==null&&(e=f);if(e==null||f==null)var g=this.getBBox(1);e=e==null?g.x+g.width/2:e,f=f==null?g.y+g.height/2:f,this.transform(this._.transform.concat([[\"s\",a,b,e,f]]));return this},A.translate=function(a,b){if(this.removed)return this;a=c(a).split(j),a.length-1&&(b=d(a[1])),a=d(a[0])||0,b=+b||0,this.transform(this._.transform.concat([[\"t\",a,b]]));return this},A.transform=function(c){var d=this._;if(c==null)return d.transform;a._extractTransform(this,c),this.clip&&q(this.clip,{transform:this.matrix.invert()}),this.pattern&&s(this),this.node&&q(this.node,{transform:this.matrix});if(d.sx!=1||d.sy!=1){var e=this.attrs[b](\"stroke-width\")?this.attrs[\"stroke-width\"]:1;this.attr({\"stroke-width\":e})}return this},A.hide=function(){!this.removed&&this.paper.safari(this.node.style.display=\"none\");return this},A.show=function(){!\nthis.removed&&this.paper.safari(this.node.style.display=\"\");return this},A.remove=function(){if(!this.removed&&!!this.node.parentNode){var b=this.paper;b.__set__&&b.__set__.exclude(this),k.unbind(\"raphael.*.*.\"+this.id),this.gradient&&b.defs.removeChild(this.gradient),a._tear(this,b),this.node.parentNode.tagName.toLowerCase()==\"a\"?this.node.parentNode.parentNode.removeChild(this.node.parentNode):this.node.parentNode.removeChild(this.node);for(var c in this)this[c]=typeof this[c]==\"function\"?a._removedFactory(c):null;this.removed=!0}},A._getBBox=function(){if(this.node.style.display==\"none\"){this.show();var a=!0}var b={};try{b=this.node.getBBox()}catch(c){}finally{b=b||{}}a&&this.hide();return b},A.attr=function(c,d){if(this.removed)return this;if(c==null){var e={};for(var f in this.attrs)this.attrs[b](f)&&(e[f]=this.attrs[f]);e.gradient&&e.fill==\"none\"&&(e.fill=e.gradient)&&delete e.gradient,e.transform=this._.transform;return e}if(d==null&&a.is(c,\"string\")){if(c==\"fill\"&&this.attrs.fill==\"none\"&&this.attrs.gradient)return this.attrs.gradient;if(c==\"transform\")return this._.transform;var g=c.split(j),h={};for(var i=0,l=g.length;i<l;i++)c=g[i],c in this.attrs?h[c]=this.attrs[c]:a.is(this.paper.customAttributes[c],\"function\")?h[c]=this.paper.customAttributes[c].def:h[c]=a._availableAttrs[c];return l-1?h:h[g[0]]}if(d==null&&a.is(c,\"array\")){h={};for(i=0,l=c.length;i<l;i++)h[c[i]]=this.attr(c[i]);return h}if(d!=null){var m={};m[c]=d}else c!=null&&a.is(c,\"object\")&&(m=c);for(var n in m)k(\"raphael.attr.\"+n+\".\"+this.id,this,m[n]);for(n in this.paper.customAttributes)if(this.paper.customAttributes[b](n)&&m[b](n)&&a.is(this.paper.customAttributes[n],\"function\")){var o=this.paper.customAttributes[n].apply(this,[].concat(m[n]));this.attrs[n]=m[n];for(var p in o)o[b](p)&&(m[p]=o[p])}w(this,m);return this},A.toFront=function(){if(this.removed)return this;this.node.parentNode.tagName.toLowerCase()==\"a\"?this.node.parentNode.parentNode.appendChild(this.node.parentNode):this.node.parentNode.appendChild(this.node);var b=this.paper;b.top!=this&&a._tofront(this,b);return this},A.toBack=function(){if(this.removed)return this;var b=this.node.parentNode;b.tagName.toLowerCase()==\"a\"?b.parentNode.insertBefore(this.node.parentNode,this.node.parentNode.parentNode.firstChild):b.firstChild!=this.node&&b.insertBefore(this.node,this.node.parentNode.firstChild),a._toback(this,this.paper);var c=this.paper;return this},A.insertAfter=function(b){if(this.removed)return this;var c=b.node||b[b.length-1].node;c.nextSibling?c.parentNode.insertBefore(this.node,c.nextSibling):c.parentNode.appendChild(this.node),a._insertafter(this,b,this.paper);return this},A.insertBefore=function(b){if(this.removed)return this;var c=b.node||b[0].node;c.parentNode.insertBefore(this.node,c),a._insertbefore(this,b,this.paper);return this},A.blur=function(b){var c=this;if(+b!==0){var d=q(\"filter\"),e=q(\"feGaussianBlur\");c.attrs.blur=b,d.id=a.createUUID(),q(e,{stdDeviation:+b||1.5}),d.appendChild(e),c.paper.defs.appendChild(d),c._blur=d,q(c.node,{filter:\"url(#\"+d.id+\")\"})}else c._blur&&(c._blur.parentNode.removeChild(c._blur),delete c._blur,delete c.attrs.blur),c.node.removeAttribute(\"filter\")},a._engine.circle=function(a,b,c,d){var e=q(\"circle\");a.canvas&&a.canvas.appendChild(e);var f=new z(e,a);f.attrs={cx:b,cy:c,r:d,fill:\"none\",stroke:\"#000\"},f.type=\"circle\",q(e,f.attrs);return f},a._engine.rect=function(a,b,c,d,e,f){var g=q(\"rect\");a.canvas&&a.canvas.appendChild(g);var h=new z(g,a);h.attrs={x:b,y:c,width:d,height:e,r:f||0,rx:f||0,ry:f||0,fill:\"none\",stroke:\"#000\"},h.type=\"rect\",q(g,h.attrs);return h},a._engine.ellipse=function(a,b,c,d,e){var f=q(\"ellipse\");a.canvas&&a.canvas.appendChild(f);var g=new z(f,a);g.attrs={cx:b,cy:c,rx:d,ry:e,fill:\"none\",stroke:\"#000\"},g.type=\"ellipse\",q(f,g.attrs);return g},a._engine.image=function(a,b,c,d,e,f){var g=q(\"image\");q(g,{x:c,y:d,width:e,height:f,preserveAspectRatio:\"none\"}),g.setAttributeNS(n,\"href\",b),a.canvas&&a.canvas.appendChild(g);var h=new z(g,a);h.attrs={x:c,y:d,width:e,height:f,src:b},h.type=\"image\";return h},a._engine.text=function(b,c,d,e){var f=q(\"text\");b.canvas&&b.canvas.appendChild(f);var g=new z(f,b);g.attrs={x:c,y:d,\"text-anchor\":\"middle\",text:e,font:a._availableAttrs.font,stroke:\"none\",fill:\"#000\"},g.type=\"text\",w(g,g.attrs);return g},a._engine.setSize=function(a,b){this.width=a||this.width,this.height=b||this.height,this.canvas.setAttribute(\"width\",this.width),this.canvas.setAttribute(\"height\",this.height),this._viewBox&&this.setViewBox.apply(this,this._viewBox);return this},a._engine.create=function(){var b=a._getContainer.apply(0,arguments),c=b&&b.container,d=b.x,e=b.y,f=b.width,g=b.height;if(!c)throw new Error(\"SVG container not found.\");var h=q(\"svg\"),i=\"overflow:hidden;\",j;d=d||0,e=e||0,f=f||512,g=g||342,q(h,{height:g,version:1.1,width:f,xmlns:\"http://www.w3.org/2000/svg\"}),c==1?(h.style.cssText=i+\"position:absolute;left:\"+d+\"px;top:\"+e+\"px\",a._g.doc.body.appendChild(h),j=1):(h.style.cssText=i+\"position:relative\",c.firstChild?c.insertBefore(h,c.firstChild):c.appendChild(h)),c=new a._Paper,c.width=f,c.height=g,c.canvas=h,c.clear(),c._left=c._top=0,j&&(c.renderfix=function(){}),c.renderfix();return c},a._engine.setViewBox=function(a,b,c,d,e){k(\"raphael.setViewBox\",this,this._viewBox,[a,b,c,d,e]);var f=g(c/this.width,d/this.height),h=this.top,i=e?\"meet\":\"xMinYMin\",j,l;a==null?(this._vbSize&&(f=1),delete this._vbSize,j=\"0 0 \"+this.width+m+this.height):(this._vbSize=f,j=a+m+b+m+c+m+d),q(this.canvas,{viewBox:j,preserveAspectRatio:i});while(f&&h)l=\"stroke-width\"in h.attrs?h.attrs[\"stroke-width\"]:1,h.attr({\"stroke-width\":l}),h._.dirty=1,h._.dirtyT=1,h=h.prev;this._viewBox=[a,b,c,d,!!e];return this},a.prototype.renderfix=function(){var a=this.canvas,b=a.style,c;try{c=a.getScreenCTM()||a.createSVGMatrix()}catch(d){c=a.createSVGMatrix()}var e=-c.e%1,f=-c.f%1;if(e||f)e&&(this._left=(this._left+e)%1,b.left=this._left+\"px\"),f&&(this._top=(this._top+f)%1,b.top=this._top+\"px\")},a.prototype.clear=function(){a.eve(\"raphael.clear\",this);var b=this.canvas;while(b.firstChild)b.removeChild(b.firstChild);this.bottom=this.top=null,(this.desc=q(\"desc\")).appendChild(a._g.doc.createTextNode(\"Created with Raphaël \"+a.version)),b.appendChild(this.desc),b.appendChild(this.defs=q(\"defs\"))},a.prototype.remove=function(){k(\"raphael.remove\",this),this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas);for(var b in this)this[b]=typeof this[b]==\"function\"?a._removedFactory(b):null};var B=a.st;for(var C in A)A[b](C)&&!B[b](C)&&(B[C]=function(a){return function(){var b=arguments;return this.forEach(function(c){c[a].apply(c,b)})}}(C))}(window.Raphael),window.Raphael.vml&&function(a){var b=\"hasOwnProperty\",c=String,d=parseFloat,e=Math,f=e.round,g=e.max,h=e.min,i=e.abs,j=\"fill\",k=/[, ]+/,l=a.eve,m=\" progid:DXImageTransform.Microsoft\",n=\" \",o=\"\",p={M:\"m\",L:\"l\",C:\"c\",Z:\"x\",m:\"t\",l:\"r\",c:\"v\",z:\"x\"},q=/([clmz]),?([^clmz]*)/gi,r=/ progid:\\S+Blur\\([^\\)]+\\)/g,s=/-?[^,\\s-]+/g,t=\"position:absolute;left:0;top:0;width:1px;height:1px\",u=21600,v={path:1,rect:1,image:1},w={circle:1,ellipse:1},x=function(b){var d=/[ahqstv]/ig,e=a._pathToAbsolute;c(b).match(d)&&(e=a._path2curve),d=/[clmz]/g;if(e==a._pathToAbsolute&&!c(b).match(d)){var g=c(b).replace(q,function(a,b,c){var d=[],e=b.toLowerCase()==\"m\",g=p[b];c.replace(s,function(a){e&&d.length==2&&(g+=d+p[b==\"m\"?\"l\":\"L\"],d=[]),d.push(f(a*u))});return g+d});return g}var h=e(b),i,j;g=[];for(var k=0,l=h.length;k<l;k++){i=h[k],j=h[k][0].toLowerCase(),j==\"z\"&&(j=\"x\");for(var m=1,r=i.length;m<r;m++)j+=f(i[m]*u)+(m!=r-1?\",\":o);g.push(j)}return g.join(n)},y=function(b,c,d){var e=a.matrix();e.rotate(-b,.5,.5);return{dx:e.x(c,d),dy:e.y(c,d)}},z=function(a,b,c,d,e,f){var g=a._,h=a.matrix,k=g.fillpos,l=a.node,m=l.style,o=1,p=\"\",q,r=u/b,s=u/c;m.visibility=\"hidden\";if(!!b&&!!c){l.coordsize=i(r)+n+i(s),m.rotation=f*(b*c<0?-1:1);if(f){var t=y(f,d,e);d=t.dx,e=t.dy}b<0&&(p+=\"x\"),c<0&&(p+=\" y\")&&(o=-1),m.flip=p,l.coordorigin=d*-r+n+e*-s;if(k||g.fillsize){var v=l.getElementsByTagName(j);v=v&&v[0],l.removeChild(v),k&&(t=y(f,h.x(k[0],k[1]),h.y(k[0],k[1])),v.position=t.dx*o+n+t.dy*o),g.fillsize&&(v.size=g.fillsize[0]*i(b)+n+g.fillsize[1]*i(c)),l.appendChild(v)}m.visibility=\"visible\"}};a.toString=function(){return\"Your browser doesn’t support SVG. Falling down to VML.\\nYou are running Raphaël \"+this.version};var A=function(a,b,d){var e=c(b).toLowerCase().split(\"-\"),f=d?\"end\":\"start\",g=e.length,h=\"classic\",i=\"medium\",j=\"medium\";while(g--)switch(e[g]){case\"block\":case\"classic\":case\"oval\":case\"diamond\":case\"open\":case\"none\":h=e[g];break;case\"wide\":case\"narrow\":j=e[g];break;case\"long\":case\"short\":i=e[g]}var k=a.node.getElementsByTagName(\"stroke\")[0];k[f+\"arrow\"]=h,k[f+\"arrowlength\"]=i,k[f+\"arrowwidth\"]=j},B=function(e,i){e.attrs=e.attrs||{};var l=e.node,m=e.attrs,p=l.style,q,r=v[e.type]&&(i.x!=m.x||i.y!=m.y||i.width!=m.width||i.height!=m.height||i.cx!=m.cx||i.cy!=m.cy||i.rx!=m.rx||i.ry!=m.ry||i.r!=m.r),s=w[e.type]&&(m.cx!=i.cx||m.cy!=i.cy||m.r!=i.r||m.rx!=i.rx||m.ry!=i.ry),t=e;for(var y in i)i[b](y)&&(m[y]=i[y]);r&&(m.path=a._getPath[e.type](e),e._.dirty=1),i.href&&(l.href=i.href),i.title&&(l.title=i.title),i.target&&(l.target=i.target),i.cursor&&(p.cursor=i.cursor),\"blur\"in i&&e.blur(i.blur);if(i.path&&e.type==\"path\"||r)l.path=x(~c(m.path).toLowerCase().indexOf(\"r\")?a._pathToAbsolute(m.path):m.path),e.type==\"image\"&&(e._.fillpos=[m.x,m.y],e._.fillsize=[m.width,m.height],z(e,1,1,0,0,0));\"transform\"in i&&e.transform(i.transform);if(s){var B=+m.cx,D=+m.cy,E=+m.rx||+m.r||0,G=+m.ry||+m.r||0;l.path=a.format(\"ar{0},{1},{2},{3},{4},{1},{4},{1}x\",f((B-E)*u),f((D-G)*u),f((B+E)*u),f((D+G)*u),f(B*u))}if(\"clip-rect\"in i){var H=c(i[\"clip-rect\"]).split(k);if(H.length==4){H[2]=+H[2]+ +H[0],H[3]=+H[3]+ +H[1];var I=l.clipRect||a._g.doc.createElement(\"div\"),J=I.style;J.clip=a.format(\"rect({1}px {2}px {3}px {0}px)\",H),l.clipRect||(J.position=\"absolute\",J.top=0,J.left=0,J.width=e.paper.width+\"px\",J.height=e.paper.height+\"px\",l.parentNode.insertBefore(I,l),I.appendChild(l),l.clipRect=I)}i[\"clip-rect\"]||l.clipRect&&(l.clipRect.style.clip=\"auto\")}if(e.textpath){var K=e.textpath.style;i.font&&(K.font=i.font),i[\"font-family\"]&&(K.fontFamily='\"'+i[\"font-family\"].split(\",\")[0].replace(/^['\"]+|['\"]+$/g,o)+'\"'),i[\"font-size\"]&&(K.fontSize=i[\"font-size\"]),i[\"font-weight\"]&&(K.fontWeight=i[\"font-weight\"]),i[\"font-style\"]&&(K.fontStyle=i[\"font-style\"])}\"arrow-start\"in i&&A(t,i[\"arrow-start\"]),\"arrow-end\"in i&&A(t,i[\"arrow-end\"],1);if(i.opacity!=null||i[\"stroke-width\"]!=null||i.fill!=null||i.src!=null||i.stroke!=null||i[\"stroke-width\"]!=null||i[\"stroke-opacity\"]!=null||i[\"fill-opacity\"]!=null||i[\"stroke-dasharray\"]!=null||i[\"stroke-miterlimit\"]!=null||i[\"stroke-linejoin\"]!=null||i[\"stroke-linecap\"]!=null){var L=l.getElementsByTagName(j),M=!1;L=L&&L[0],!L&&(M=L=F(j)),e.type==\"image\"&&i.src&&(L.src=i.src),i.fill&&(L.on=!0);if(L.on==null||i.fill==\"none\"||i.fill===null)L.on=!1;if(L.on&&i.fill){var N=c(i.fill).match(a._ISURL);if(N){L.parentNode==l&&l.removeChild(L),L.rotate=!0,L.src=N[1],L.type=\"tile\";var O=e.getBBox(1);L.position=O.x+n+O.y,e._.fillpos=[O.x,O.y],a._preload(N[1],function(){e._.fillsize=[this.offsetWidth,this.offsetHeight]})}else L.color=a.getRGB(i.fill).hex,L.src=o,L.type=\"solid\",a.getRGB(i.fill).error&&(t.type in{circle:1,ellipse:1}||c(i.fill).charAt()!=\"r\")&&C(t,i.fill,L)&&(m.fill=\"none\",m.gradient=i.fill,L.rotate=!1)}if(\"fill-opacity\"in i||\"opacity\"in i){var P=((+m[\"fill-opacity\"]+1||2)-1)*((+m.opacity+1||2)-1)*((+a.getRGB(i.fill).o+1||2)-1);P=h(g(P,0),1),L.opacity=P,L.src&&(L.color=\"none\")}l.appendChild(L);var Q=l.getElementsByTagName(\"stroke\")&&l.getElementsByTagName(\"stroke\")[0],T=!1;!Q&&(T=Q=F(\"stroke\"));if(i.stroke&&i.stroke!=\"none\"||i[\"stroke-width\"]||i[\"stroke-opacity\"]!=null||i[\"stroke-dasharray\"]||i[\"stroke-miterlimit\"]||i[\"stroke-linejoin\"]||i[\"stroke-linecap\"])Q.on=!0;(i.stroke==\"none\"||i.stroke===null||Q.on==null||i.stroke==0||i[\"stroke-width\"]==0)&&(Q.on=!1);var U=a.getRGB(i.stroke);Q.on&&i.stroke&&(Q.color=U.hex),P=((+m[\"stroke-opacity\"]+1||2)-1)*((+m.opacity+1||2)-1)*((+U.o+1||2)-1);var V=(d(i[\"stroke-width\"])||1)*.75;P=h(g(P,0),1),i[\"stroke-width\"]==null&&(V=m[\"stroke-width\"]),i[\"stroke-width\"]&&(Q.weight=V),V&&V<1&&(P*=V)&&(Q.weight=1),Q.opacity=P,i[\"stroke-linejoin\"]&&(Q.joinstyle=i[\"stroke-linejoin\"]||\"miter\"),Q.miterlimit=i[\"stroke-miterlimit\"]||8,i[\"stroke-linecap\"]&&(Q.endcap=i[\"stroke-linecap\"]==\"butt\"?\"flat\":i[\"stroke-linecap\"]==\"square\"?\"square\":\"round\");if(i[\"stroke-dasharray\"]){var W={\"-\":\"shortdash\",\".\":\"shortdot\",\"-.\":\"shortdashdot\",\"-..\":\"shortdashdotdot\",\". \":\"dot\",\"- \":\"dash\",\"--\":\"longdash\",\"- .\":\"dashdot\",\"--.\":\"longdashdot\",\"--..\":\"longdashdotdot\"};Q.dashstyle=W[b](i[\"stroke-dasharray\"])?W[i[\"stroke-dasharray\"]]:o}T&&l.appendChild(Q)}if(t.type==\"text\"){t.paper.canvas.style.display=o;var X=t.paper.span,Y=100,Z=m.font&&m.font.match(/\\d+(?:\\.\\d*)?(?=px)/);p=X.style,m.font&&(p.font=m.font),m[\"font-family\"]&&(p.fontFamily=m[\"font-family\"]),m[\"font-weight\"]&&(p.fontWeight=m[\"font-weight\"]),m[\"font-style\"]&&(p.fontStyle=m[\"font-style\"]),Z=d(m[\"font-size\"]||Z&&Z[0])||10,p.fontSize=Z*Y+\"px\",t.textpath.string&&(X.innerHTML=c(t.textpath.string).replace(/</g,\"&#60;\").replace(/&/g,\"&#38;\").replace(/\\n/g,\"<br>\"));var $=X.getBoundingClientRect();t.W=m.w=($.right-$.left)/Y,t.H=m.h=($.bottom-$.top)/Y,t.X=m.x,t.Y=m.y+t.H/2,(\"x\"in i||\"y\"in i)&&(t.path.v=a.format(\"m{0},{1}l{2},{1}\",f(m.x*u),f(m.y*u),f(m.x*u)+1));var _=[\"x\",\"y\",\"text\",\"font\",\"font-family\",\"font-weight\",\"font-style\",\"font-size\"];for(var ba=0,bb=_.length;ba<bb;ba++)if(_[ba]in i){t._.dirty=1;break}switch(m[\"text-anchor\"]){case\"start\":t.textpath.style[\"v-text-align\"]=\"left\",t.bbx=t.W/2;break;case\"end\":t.textpath.style[\"v-text-align\"]=\"right\",t.bbx=-t.W/2;break;default:t.textpath.style[\"v-text-align\"]=\"center\",t.bbx=0}t.textpath.style[\"v-text-kern\"]=!0}},C=function(b,f,g){b.attrs=b.attrs||{};var h=b.attrs,i=Math.pow,j,k,l=\"linear\",m=\".5 .5\";b.attrs.gradient=f,f=c(f).replace(a._radial_gradient,function(a,b,c){l=\"radial\",b&&c&&(b=d(b),c=d(c),i(b-.5,2)+i(c-.5,2)>.25&&(c=e.sqrt(.25-i(b-.5,2))*((c>.5)*2-1)+.5),m=b+n+c);return o}),f=f.split(/\\s*\\-\\s*/);if(l==\"linear\"){var p=f.shift();p=-d(p);if(isNaN(p))return null}var q=a._parseDots(f);if(!q)return null;b=b.shape||b.node;if(q.length){b.removeChild(g),g.on=!0,g.method=\"none\",g.color=q[0].color,g.color2=q[q.length-1].color;var r=[];for(var s=0,t=q.length;s<t;s++)q[s].offset&&r.push(q[s].offset+n+q[s].color);g.colors=r.length?r.join():\"0% \"+g.color,l==\"radial\"?(g.type=\"gradientTitle\",g.focus=\"100%\",g.focussize=\"0 0\",g.focusposition=m,g.angle=0):(g.type=\"gradient\",g.angle=(270-p)%360),b.appendChild(g)}return 1},D=function(b,c){this[0]=this.node=b,b.raphael=!0,this.id=a._oid++,b.raphaelid=this.id,this.X=0,this.Y=0,this.attrs={},this.paper=c,this.matrix=a.matrix(),this._={transform:[],sx:1,sy:1,dx:0,dy:0,deg:0,dirty:1,dirtyT:1},!c.bottom&&(c.bottom=this),this.prev=c.top,c.top&&(c.top.next=this),c.top=this,this.next=null},E=a.el;D.prototype=E,E.constructor=D,E.transform=function(b){if(b==null)return this._.transform;var d=this.paper._viewBoxShift,e=d?\"s\"+[d.scale,d.scale]+\"-1-1t\"+[d.dx,d.dy]:o,f;d&&(f=b=c(b).replace(/\\.{3}|\\u2026/g,this._.transform||o)),a._extractTransform(this,e+b);var g=this.matrix.clone(),h=this.skew,i=this.node,j,k=~c(this.attrs.fill).indexOf(\"-\"),l=!c(this.attrs.fill).indexOf(\"url(\");g.translate(-0.5,-0.5);if(l||k||this.type==\"image\"){h.matrix=\"1 0 0 1\",h.offset=\"0 0\",j=g.split();if(k&&j.noRotation||!j.isSimple){i.style.filter=g.toFilter();var m=this.getBBox(),p=this.getBBox(1),q=m.x-p.x,r=m.y-p.y;i.coordorigin=q*-u+n+r*-u,z(this,1,1,q,r,0)}else i.style.filter=o,z(this,j.scalex,j.scaley,j.dx,j.dy,j.rotate)}else i.style.filter=o,h.matrix=c(g),h.offset=g.offset();f&&(this._.transform=f);return this},E.rotate=function(a,b,e){if(this.removed)return this;if(a!=null){a=c(a).split(k),a.length-1&&(b=d(a[1]),e=d(a[2])),a=d(a[0]),e==null&&(b=e);if(b==null||e==null){var f=this.getBBox(1);b=f.x+f.width/2,e=f.y+f.height/2}this._.dirtyT=1,this.transform(this._.transform.concat([[\"r\",a,b,e]]));return this}},E.translate=function(a,b){if(this.removed)return this;a=c(a).split(k),a.length-1&&(b=d(a[1])),a=d(a[0])||0,b=+b||0,this._.bbox&&(this._.bbox.x+=a,this._.bbox.y+=b),this.transform(this._.transform.concat([[\"t\",a,b]]));return this},E.scale=function(a,b,e,f){if(this.removed)return this;a=c(a).split(k),a.length-1&&(b=d(a[1]),e=d(a[2]),f=d(a[3]),isNaN(e)&&(e=null),isNaN(f)&&(f=null)),a=d(a[0]),b==null&&(b=a),f==null&&(e=f);if(e==null||f==null)var g=this.getBBox(1);e=e==null?g.x+g.width/2:e,f=f==null?g.y+g.height/2:f,this.transform(this._.transform.concat([[\"s\",a,b,e,f]])),this._.dirtyT=1;return this},E.hide=function(){!this.removed&&(this.node.style.display=\"none\");return this},E.show=function(){!this.removed&&(this.node.style.display=o);return this},E._getBBox=function(){if(this.removed)return{};return{x:this.X+(this.bbx||0)-this.W/2,y:this.Y-this.H,width:this.W,height:this.H}},E.remove=function(){if(!this.removed&&!!this.node.parentNode){this.paper.__set__&&this.paper.__set__.exclude(this),a.eve.unbind(\"raphael.*.*.\"+this.id),a._tear(this,this.paper),this.node.parentNode.removeChild(this.node),this.shape&&this.shape.parentNode.removeChild(this.shape);for(var b in this)this[b]=typeof this[b]==\"function\"?a._removedFactory(b):null;this.removed=!0}},E.attr=function(c,d){if(this.removed)return this;if(c==null){var e={};for(var f in this.attrs)this.attrs[b](f)&&(e[f]=this.attrs[f]);e.gradient&&e.fill==\"none\"&&(e.fill=e.gradient)&&delete e.gradient,e.transform=this._.transform;return e}if(d==null&&a.is(c,\"string\")){if(c==j&&this.attrs.fill==\"none\"&&this.attrs.gradient)return this.attrs.gradient;var g=c.split(k),h={};for(var i=0,m=g.length;i<m;i++)c=g[i],c in this.attrs?h[c]=this.attrs[c]:a.is(this.paper.customAttributes[c],\"function\")?h[c]=this.paper.customAttributes[c].def:h[c]=a._availableAttrs[c];return m-1?h:h[g[0]]}if(this.attrs&&d==null&&a.is(c,\"array\")){h={};for(i=0,m=c.length;i<m;i++)h[c[i]]=this.attr(c[i]);return h}var n;d!=null&&(n={},n[c]=d),d==null&&a.is(c,\"object\")&&(n=c);for(var o in n)l(\"raphael.attr.\"+o+\".\"+this.id,this,n[o]);if(n){for(o in this.paper.customAttributes)if(this.paper.customAttributes[b](o)&&n[b](o)&&a.is(this.paper.customAttributes[o],\"function\")){var p=this.paper.customAttributes[o].apply(this,[].concat(n[o]));this.attrs[o]=n[o];for(var q in p)p[b](q)&&(n[q]=p[q])}n.text&&this.type==\"text\"&&(this.textpath.string=n.text),B(this,n)}return this},E.toFront=function(){!this.removed&&this.node.parentNode.appendChild(this.node),this.paper&&this.paper.top!=this&&a._tofront(this,this.paper);return this},E.toBack=function(){if(this.removed)return this;this.node.parentNode.firstChild!=this.node&&(this.node.parentNode.insertBefore(this.node,this.node.parentNode.firstChild),a._toback(this,this.paper));return this},E.insertAfter=function(b){if(this.removed)return this;b.constructor==a.st.constructor&&(b=b[b.length-1]),b.node.nextSibling?b.node.parentNode.insertBefore(this.node,b.node.nextSibling):b.node.parentNode.appendChild(this.node),a._insertafter(this,b,this.paper);return this},E.insertBefore=function(b){if(this.removed)return this;b.constructor==a.st.constructor&&(b=b[0]),b.node.parentNode.insertBefore(this.node,b.node),a._insertbefore(this,b,this.paper);return this},E.blur=function(b){var c=this.node.runtimeStyle,d=c.filter;d=d.replace(r,o),+b!==0?(this.attrs.blur=b,c.filter=d+n+m+\".Blur(pixelradius=\"+(+b||1.5)+\")\",c.margin=a.format(\"-{0}px 0 0 -{0}px\",f(+b||1.5))):(c.filter=d,c.margin=0,delete this.attrs.blur)},a._engine.path=function(a,b){var c=F(\"shape\");c.style.cssText=t,c.coordsize=u+n+u,c.coordorigin=b.coordorigin;var d=new D(c,b),e={fill:\"none\",stroke:\"#000\"};a&&(e.path=a),d.type=\"path\",d.path=[],d.Path=o,B(d,e),b.canvas.appendChild(c);var f=F(\"skew\");f.on=!0,c.appendChild(f),d.skew=f,d.transform(o);return d},a._engine.rect=function(b,c,d,e,f,g){var h=a._rectPath(c,d,e,f,g),i=b.path(h),j=i.attrs;i.X=j.x=c,i.Y=j.y=d,i.W=j.width=e,i.H=j.height=f,j.r=g,j.path=h,i.type=\"rect\";return i},a._engine.ellipse=function(a,b,c,d,e){var f=a.path(),g=f.attrs;f.X=b-d,f.Y=c-e,f.W=d*2,f.H=e*2,f.type=\"ellipse\",B(f,{cx:b,cy:c,rx:d,ry:e});return f},a._engine.circle=function(a,b,c,d){var e=a.path(),f=e.attrs;e.X=b-d,e.Y=c-d,e.W=e.H=d*2,e.type=\"circle\",B(e,{cx:b,cy:c,r:d});return e},a._engine.image=function(b,c,d,e,f,g){var h=a._rectPath(d,e,f,g),i=b.path(h).attr({stroke:\"none\"}),k=i.attrs,l=i.node,m=l.getElementsByTagName(j)[0];k.src=c,i.X=k.x=d,i.Y=k.y=e,i.W=k.width=f,i.H=k.height=g,k.path=h,i.type=\"image\",m.parentNode==l&&l.removeChild(m),m.rotate=!0,m.src=c,m.type=\"tile\",i._.fillpos=[d,e],i._.fillsize=[f,g],l.appendChild(m),z(i,1,1,0,0,0);return i},a._engine.text=function(b,d,e,g){var h=F(\"shape\"),i=F(\"path\"),j=F(\"textpath\");d=d||0,e=e||0,g=g||\"\",i.v=a.format(\"m{0},{1}l{2},{1}\",f(d*u),f(e*u),f(d*u)+1),i.textpathok=!0,j.string=c(g),j.on=!0,h.style.cssText=t,h.coordsize=u+n+u,h.coordorigin=\"0 0\";var k=new D(h,b),l={fill:\"#000\",stroke:\"none\",font:a._availableAttrs.font,text:g};k.shape=h,k.path=i,k.textpath=j,k.type=\"text\",k.attrs.text=c(g),k.attrs.x=d,k.attrs.y=e,k.attrs.w=1,k.attrs.h=1,B(k,l),h.appendChild(j),h.appendChild(i),b.canvas.appendChild(h);var m=F(\"skew\");m.on=!0,h.appendChild(m),k.skew=m,k.transform(o);return k},a._engine.setSize=function(b,c){var d=this.canvas.style;this.width=b,this.height=c,b==+b&&(b+=\"px\"),c==+c&&(c+=\"px\"),d.width=b,d.height=c,d.clip=\"rect(0 \"+b+\" \"+c+\" 0)\",this._viewBox&&a._engine.setViewBox.apply(this,this._viewBox);return this},a._engine.setViewBox=function(b,c,d,e,f){a.eve(\"raphael.setViewBox\",this,this._viewBox,[b,c,d,e,f]);var h=this.width,i=this.height,j=1/g(d/h,e/i),k,l;f&&(k=i/e,l=h/d,d*k<h&&(b-=(h-d*k)/2/k),e*l<i&&(c-=(i-e*l)/2/l)),this._viewBox=[b,c,d,e,!!f],this._viewBoxShift={dx:-b,dy:-c,scale:j},this.forEach(function(a){a.transform(\"...\")});return this};var F;a._engine.initWin=function(a){var b=a.document;b.createStyleSheet().addRule(\".rvml\",\"behavior:url(#default#VML)\");try{!b.namespaces.rvml&&b.namespaces.add(\"rvml\",\"urn:schemas-microsoft-com:vml\"),F=function(a){return b.createElement(\"<rvml:\"+a+' class=\"rvml\">')}}catch(c){F=function(a){return b.createElement(\"<\"+a+' xmlns=\"urn:schemas-microsoft.com:vml\" class=\"rvml\">')}}},a._engine.initWin(a._g.win),a._engine.create=function(){var b=a._getContainer.apply(0,arguments),c=b.container,d=b.height,e,f=b.width,g=b.x,h=b.y;if(!c)throw new Error(\"VML container not found.\");var i=new a._Paper,j=i.canvas=a._g.doc.createElement(\"div\"),k=j.style;g=g||0,h=h||0,f=f||512,d=d||342,i.width=f,i.height=d,f==+f&&(f+=\"px\"),d==+d&&(d+=\"px\"),i.coordsize=u*1e3+n+u*1e3,i.coordorigin=\"0 0\",i.span=a._g.doc.createElement(\"span\"),i.span.style.cssText=\"position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;\",j.appendChild(i.span),k.cssText=a.format(\"top:0;left:0;width:{0};height:{1};display:inline-block;position:relative;clip:rect(0 {0} {1} 0);overflow:hidden\",f,d),c==1?(a._g.doc.body.appendChild(j),k.left=g+\"px\",k.top=h+\"px\",k.position=\"absolute\"):c.firstChild?c.insertBefore(j,c.firstChild):c.appendChild(j),i.renderfix=function(){};return i},a.prototype.clear=function(){a.eve(\"raphael.clear\",this),this.canvas.innerHTML=o,this.span=a._g.doc.createElement(\"span\"),this.span.style.cssText=\"position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;\",this.canvas.appendChild(this.span),this.bottom=this.top=null},a.prototype.remove=function(){a.eve(\"raphael.remove\",this),this.canvas.parentNode.removeChild(this.canvas);for(var b in this)this[b]=typeof this[b]==\"function\"?a._removedFactory(b):null;return!0};var G=a.st;for(var H in E)E[b](H)&&!G[b](H)&&(G[H]=function(a){return function(){var b=arguments;return this.forEach(function(c){c[a].apply(c,b)})}}(H))}(window.Raphael)\n'''\n\nbackground_jpg = '\\xff\\xd8\\xff\\xe0\\x00\\x10JFIF\\x00\\x01\\x02\\x00\\x00d\\x00d\\x00\\x00\\xff\\xec\\x00\\x11Ducky\\x00\\x01\\x00\\x04\\x00\\x00\\x00d\\x00\\x00\\xff\\xee\\x00\\x0eAdobe\\x00d\\xc0\\x00\\x00\\x00\\x01\\xff\\xdb\\x00\\x84\\x00\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x02\\x02\\x02\\x02\\x02\\x02\\x02\\x02\\x02\\x02\\x02\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x02\\x01\\x01\\x02\\x02\\x02\\x01\\x02\\x02\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\x03\\xff\\xc0\\x00\\x11\\x08\\x03\\x00\\x00\\n\\x03\\x01\\x11\\x00\\x02\\x11\\x01\\x03\\x11\\x01\\xff\\xc4\\x00k\\x00\\x01\\x01\\x01\\x01\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x03\\x02\\x01\\x04\\t\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x02\\x03\\x06\\x07\\x10\\x01\\x00\\x02\\x01\\x04\\x01\\x05\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x12Q\\xf0\\x11a\\xa1q\\x91\\xd1\\xe1\\x02\\x13\\x81b\\x11\\x01\\x01\\x01\\x01\\x00\\x03\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x11\\x01\\x12!Qa\\x02\"\\xff\\xda\\x00\\x0c\\x03\\x01\\x00\\x02\\x11\\x03\\x11\\x00?\\x00\\xf9\\xc6\\xf7\\x0f\\x9e\\x80\\x00\\x0e\\xb5\\xc8\\x1c\\x8a\\x8e`\\x00\\x00\\x005\\xb15\\xa9\\x86\\xc4\\xd2c\\xad(\\x00\\x00\\xe8\\xb3@\\x9a\\xady\\xe9nz^\\x8a\\xf3\\xd1s\\xd1\\xd3H\\xc8\\x00\\x00\\xad</\\x86\\xae\\x14\\xf0x.6\\x8c\\x80\\x00\\n\\xd25\\x0b\\xe1\\xab\\x9e\\x8aF\\xa0\\xf0\\\\\\xf4\\xda2\\x03\\xa2\\xcd\\x02j\\xd5\\x8c-\\xd2\\xe9X\\xc1t\\xba\\xea \\x0e\\xed8\\x9fF\\xa7\\xd2\\xe1\\xb4\\xe2}\\t\\xf4\\xb8\\xa8\\xe6\\x00\\x006\\xd3\\xa0\\x00\\x00\\xa5\\'[7\\xcf\\xd5\\xf0Ru\\xb1\\xcf\\xd3\\xc2\\xaa\\xc8\\x0e\\xed+5f\\x9bI4\\x9a\\xb6\\xd1\\x88\\x0b\\xa6\\xd1\\x88\\x0b\\xae\\xa2\\x00\\xb5c\\x95\\xabt\\xacrR\\xebH\\x80)O\\x1d\\xaf\\x85\\xf0S\\xc7g\\x83\\xc2\\x88\\x805Yjb\\\\+$\\xc2\\xe2\\x83\\x00;Y\\xd6\\xe4XVu\\xb9\\x08\\xb8\\x80;\\xb4\\xaf?\\xa5\\x9am\\'?\\xa2k\\xd0\\xda\\x00m!4\\xdaBj\\xfbF .\\x9bF .\\xbaM@\\x9a-X\\xc1un\\x95\\x8c\\x17K\\xad\\x00\\x0bV\\x16\\xe9J\\xc1t\\xad \\x02\\xb4\\x82\\x85 \\xa3`\\x02\\xbf\\x9f=|\\x9dg\\xa7>\\xcf\\xcf\\x9e\\xbeN\\xb3\\xd1\\xda\\xac\\xb9\\x80\\xa55\\xa8_\\x0b\\xe0\\xa6\\xb5\\x07\\x83\\xc2\\x88\\x80)\\xf9\\xf8u\\x9f\\x9fA\\xf9\\xf8\\'\\xe7\\xd0\\xaa\\x005Ik\\xc0RO\\x02\\xcc\\x80;Y\\xc4\\xb53\\xd8Vq$\\xcfb\\xec\\x80\\x0b5\\x02h\\xbe\\xd1\\x88\\x16\\xe9\\xb4b\\x02\\xeb\\xa4\\xd4\\t\\xa3\\xd1O\\xae;\\x9ft\\xeb\\\\\\xba\\xfd\\x14\\xfa\\xe3\\xb9\\xf7:\\xd3\\xaf\\xd3H\\xc8\\n\\xd22\\xb7\\xe1\\xe0\\xa4d\\xbf\\x0f\\r\\xa0\\x03t\\x9cw\\x0e\\x9c\\xfe~\\x85\\'\\x1d\\xc1\\xcf\\xe7\\xe8\\xb0\\x00,\\xd4\\t\\xa2\\xfbF#\\xd0\\xba\\x1bF#\\xd0\\xba:\\x8a\\x02\\x94\\x9c\\xc3W\\x02\\x93\\x98.\\n2\\x005\\xce\\xa0s\\xa2\\xfbF!\\x95\\xbam\\x18\\x80\\xba\\xe8\\x00\\xd5\\'\\x1d\\xc7\\xbb_\\xca\\x14\\x9cw\\x1e\\xe7\\xf2,\\xca\\x80\\x00\\x0b\\xfe_\\xeb\\xaf\\x95\\xef\\xe34\\xfc\\xbf\\xd7_\\'\\x7f\\n\\xb3\\x9b \\x0b7\\xd6\\x817\\xd6\\x8a\\xd3\\x9e\\xbe]zB\\x9c\\xf5\\xf2t(\\xca\\x80\\x00\\rW\\xed\\x8e\\xe1\\xbb\\x88W\\xed\\x8e\\xe0\\xb8,\\xc2\\x80\\x00\\x03\\\\\\xa0r+H\\xe7_\\xc3\\xad\\nG:\\xfe\\x1dh\\xdb*\\x00\\x00\\rs\\xa8\\x1c\\xe8\\xdd\\'\\x85\\xeb\\x02\\x93\\xc1\\xd6\\n\\xb0\\xa0?\\xff\\xd9'\n\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/modules/inspector.py",
    "content": "'''\nInspector\n=========\n\n.. versionadded:: 1.0.9\n\n.. warning::\n\n    This module is highly experimental, use it with care.\n\nThe Inspector is a tool for finding a widget in the widget tree by clicking or\ntapping on it.\nSome keyboard shortcuts are activated:\n\n    * \"Ctrl + e\": activate / deactivate the inspector view\n    * \"Escape\": cancel widget lookup first, then hide the inspector view\n\nAvailable inspector interactions:\n\n    * tap once on a widget to select it without leaving inspect mode\n    * double tap on a widget to select and leave inspect mode (then you can\n      manipulate the widget again)\n\nSome properties can be edited live. However, due to the delayed usage of\nsome properties, it might crash if you don't handle all the cases.\n\nUsage\n-----\n\nFor normal module usage, please see the :mod:`~kivy.modules` documentation.\n\nThe Inspector, however, can also be imported and used just like a normal\npython module. This has the added advantage of being able to activate and\ndeactivate the module programmatically::\n\n    from kivy.core.window import Window\n    from kivy.app import App\n    from kivy.uix.button import Button\n    from kivy.modules import inspector\n\n    class Demo(App):\n        def build(self):\n            button = Button(text=\"Test\")\n            inspector.create_inspector(Window, button)\n            return button\n\n    Demo().run()\n\nTo remove the Inspector, you can do the following::\n\n    inspector.stop(Window, button)\n\n'''\n__all__ = ('start', 'stop', 'create_inspector')\n\nimport kivy\nkivy.require('1.0.9')\n\nimport weakref\nfrom kivy.animation import Animation\nfrom kivy.logger import Logger\nfrom kivy.uix.widget import Widget\nfrom kivy.uix.button import Button\nfrom kivy.uix.label import Label\nfrom kivy.uix.togglebutton import ToggleButton\nfrom kivy.uix.textinput import TextInput\nfrom kivy.uix.image import Image\nfrom kivy.uix.treeview import TreeViewNode\nfrom kivy.uix.gridlayout import GridLayout\nfrom kivy.uix.floatlayout import FloatLayout\nfrom kivy.uix.boxlayout import BoxLayout\nfrom kivy.uix.modalview import ModalView\nfrom kivy.graphics import Color, Rectangle, PushMatrix, PopMatrix, \\\n    Translate, Rotate, Scale\nfrom kivy.properties import ObjectProperty, BooleanProperty, ListProperty, \\\n    NumericProperty, StringProperty, OptionProperty, \\\n    ReferenceListProperty, AliasProperty, VariableListProperty\nfrom kivy.graphics.texture import Texture\nfrom kivy.clock import Clock\nfrom functools import partial\nfrom itertools import chain\nfrom kivy.lang import Builder\nfrom kivy.vector import Vector\n\nBuilder.load_string('''\n<Inspector>:\n    layout: layout\n    treeview: treeview\n    content: content\n    BoxLayout:\n        orientation: 'vertical'\n        id: layout\n        size_hint_y: None\n        height: 250\n        padding: 5\n        spacing: 5\n        top: 0\n\n        canvas:\n            Color:\n                rgb: .4, .4, .4\n            Rectangle:\n                pos: self.x, self.top\n                size: self.width, 1\n            Color:\n                rgba: .185, .18, .18, .95\n            Rectangle:\n                pos: self.pos\n                size: self.size\n\n        # Top Bar\n        BoxLayout:\n            size_hint_y: None\n            height: 50\n            spacing: 5\n            Button:\n                text: 'Move to Top'\n                on_release: root.toggle_position(args[0])\n                size_hint_x: None\n                width: 120\n\n            ToggleButton:\n                text: 'Inspect'\n                on_state: root.inspect_enabled = args[1] == 'down'\n                size_hint_x: None\n                state: 'down' if root.inspect_enabled else 'normal'\n                width: 80\n\n            Button:\n                text: 'Parent'\n                on_release:\n                    root.highlight_widget(root.widget.parent) if root.widget \\\n                            else None\n                size_hint_x: None\n                width: 80\n\n            Button:\n                text: '%r' % root.widget\n                on_release: root.show_widget_info()\n\n            Button:\n                text: 'X'\n                size_hint_x: None\n                width: 50\n                on_release: root.activated = False\n\n        # Bottom Bar\n        BoxLayout:\n            ScrollView:\n                scroll_type: ['bars', 'content']\n                bar_width: 10\n                TreeView:\n                    id: treeview\n                    size_hint_y: None\n                    hide_root: True\n                    height: self.minimum_height\n\n            ScrollView:\n                id: content\n\n<TreeViewProperty>:\n    height: max(lkey.texture_size[1], ltext.texture_size[1])\n    Label:\n        id: lkey\n        text: root.key\n        text_size: (self.width, None)\n        width: 150\n        size_hint_x: None\n    Label:\n        id: ltext\n        text: [repr(getattr(root.widget, root.key, '')), root.refresh][0]\\\n                if root.widget else ''\n        text_size: (self.width, None)\n''')\n\n\nclass TreeViewProperty(BoxLayout, TreeViewNode):\n\n    widget_ref = ObjectProperty(None, allownone=True)\n\n    def _get_widget(self):\n        wr = self.widget_ref\n        if wr is None:\n            return None\n        wr = wr()\n        if wr is None:\n            self.widget_ref = None\n            return None\n        return wr\n    widget = AliasProperty(_get_widget, None, bind=('widget_ref', ))\n\n    key = ObjectProperty(None, allownone=True)\n\n    inspector = ObjectProperty(None)\n\n    refresh = BooleanProperty(False)\n\n\nclass Inspector(FloatLayout):\n\n    widget = ObjectProperty(None, allownone=True)\n\n    layout = ObjectProperty(None)\n\n    treeview = ObjectProperty(None)\n\n    inspect_enabled = BooleanProperty(False)\n\n    activated = BooleanProperty(False)\n\n    widget_info = BooleanProperty(False)\n\n    content = ObjectProperty(None)\n\n    at_bottom = BooleanProperty(True)\n\n    def __init__(self, **kwargs):\n        super(Inspector, self).__init__(**kwargs)\n        self.avoid_bring_to_top = False\n        self.win = kwargs.get('win')\n        with self.canvas.before:\n            self.gcolor = Color(1, 0, 0, .25)\n            PushMatrix()\n            self.gtranslate = Translate(0, 0, 0)\n            self.grotate = Rotate(0, 0, 0, 1)\n            self.gscale = Scale(1.)\n            self.grect = Rectangle(size=(0, 0))\n            PopMatrix()\n        Clock.schedule_interval(self.update_widget_graphics, 0)\n\n    def on_touch_down(self, touch):\n        ret = super(Inspector, self).on_touch_down(touch)\n        if (('button' not in touch.profile or touch.button == 'left')\n                and not ret and self.inspect_enabled):\n            self.highlight_at(*touch.pos)\n            if touch.is_double_tap:\n                self.inspect_enabled = False\n                self.show_widget_info()\n            ret = True\n        return ret\n\n    def on_touch_move(self, touch):\n        ret = super(Inspector, self).on_touch_move(touch)\n        if not ret and self.inspect_enabled:\n            self.highlight_at(*touch.pos)\n            ret = True\n        return ret\n\n    def on_touch_up(self, touch):\n        ret = super(Inspector, self).on_touch_up(touch)\n        if not ret and self.inspect_enabled:\n            ret = True\n        return ret\n\n    def on_window_children(self, win, children):\n        if self.avoid_bring_to_top:\n            return\n        self.avoid_bring_to_top = True\n        win.remove_widget(self)\n        win.add_widget(self)\n        self.avoid_bring_to_top = False\n\n    def highlight_at(self, x, y):\n        widget = None\n        # reverse the loop - look at children on top first and\n        # modalviews before others\n        win_children = self.win.children\n        children = chain(\n            (c for c in reversed(win_children) if isinstance(c, ModalView)),\n            (c for c in reversed(win_children) if not isinstance(c, ModalView))\n        )\n        for child in children:\n            if child is self:\n                continue\n            widget = self.pick(child, x, y)\n            if widget:\n                break\n        self.highlight_widget(widget)\n\n    def highlight_widget(self, widget, info=True, *largs):\n        # no widget to highlight, reduce rectangle to 0, 0\n        self.widget = widget\n        if not widget:\n            self.grect.size = 0, 0\n        if self.widget_info and info:\n            self.show_widget_info()\n\n    def update_widget_graphics(self, *l):\n        if not self.activated:\n            return\n        if self.widget is None:\n            self.grect.size = 0, 0\n            return\n        gr = self.grect\n        widget = self.widget\n\n        # determine rotation\n        a = Vector(1, 0)\n        if widget is self.win:\n            b = Vector(widget.to_window(0, 0))\n            c = Vector(widget.to_window(1, 0))\n        else:\n            b = Vector(widget.to_window(*widget.to_parent(0, 0)))\n            c = Vector(widget.to_window(*widget.to_parent(1, 0))) - b\n        angle = -a.angle(c)\n\n        # determine scale\n        scale = c.length()\n\n        # apply transform\n        gr.size = widget.size\n        if widget is self.win:\n            self.gtranslate.xy = Vector(widget.to_window(0, 0))\n        else:\n            self.gtranslate.xy = Vector(widget.to_window(*widget.pos))\n        self.grotate.angle = angle\n        # fix warning about scale property deprecation\n        self.gscale.xyz = (scale,) * 3\n\n    def toggle_position(self, button):\n        to_bottom = button.text == 'Move to Bottom'\n\n        if to_bottom:\n            button.text = 'Move to Top'\n            if self.widget_info:\n                Animation(top=250, t='out_quad', d=.3).start(self.layout)\n            else:\n                Animation(top=60, t='out_quad', d=.3).start(self.layout)\n\n            bottom_bar = self.layout.children[1]\n            self.layout.remove_widget(bottom_bar)\n            self.layout.add_widget(bottom_bar)\n        else:\n            button.text = 'Move to Bottom'\n            if self.widget_info:\n                Animation(top=self.height, t='out_quad', d=.3).start(\n                    self.layout)\n            else:\n                Animation(y=self.height - 60, t='out_quad', d=.3).start(\n                    self.layout)\n\n            bottom_bar = self.layout.children[1]\n            self.layout.remove_widget(bottom_bar)\n            self.layout.add_widget(bottom_bar)\n        self.at_bottom = to_bottom\n\n    def pick(self, widget, x, y):\n        ret = None\n        # try to filter widgets that are not visible (invalid inspect target)\n        if (hasattr(widget, 'visible') and not widget.visible):\n            return ret\n        if widget.collide_point(x, y):\n            ret = widget\n            x2, y2 = widget.to_local(x, y)\n            # reverse the loop - look at children on top first\n            for child in reversed(widget.children):\n                ret = self.pick(child, x2, y2) or ret\n        return ret\n\n    def on_activated(self, instance, activated):\n        if not activated:\n            self.grect.size = 0, 0\n            if self.at_bottom:\n                anim = Animation(top=0, t='out_quad', d=.3)\n            else:\n                anim = Animation(y=self.height, t='out_quad', d=.3)\n            anim.bind(on_complete=self.animation_close)\n            anim.start(self.layout)\n            self.widget = None\n            self.widget_info = False\n        else:\n            self.win.add_widget(self)\n            Logger.info('Inspector: inspector activated')\n            if self.at_bottom:\n                Animation(top=60, t='out_quad', d=.3).start(self.layout)\n            else:\n                Animation(y=self.height - 60, t='out_quad', d=.3).start(\n                    self.layout)\n\n    def animation_close(self, instance, value):\n        if self.activated is False:\n            self.inspect_enabled = False\n            self.win.remove_widget(self)\n            self.content.clear_widgets()\n            treeview = self.treeview\n            for node in list(treeview.iterate_all_nodes())[:]:\n                node.widget_ref = None\n                treeview.remove_node(node)\n            Logger.info('Inspector: inspector deactivated')\n\n    def show_widget_info(self):\n        self.content.clear_widgets()\n        widget = self.widget\n        treeview = self.treeview\n        for node in list(treeview.iterate_all_nodes())[:]:\n            node.widget_ref = None\n            treeview.remove_node(node)\n        if not widget:\n            if self.at_bottom:\n                Animation(top=60, t='out_quad', d=.3).start(self.layout)\n            else:\n                Animation(y=self.height - 60, t='out_quad', d=.3).start(\n                    self.layout)\n            self.widget_info = False\n            return\n        self.widget_info = True\n        if self.at_bottom:\n            Animation(top=250, t='out_quad', d=.3).start(self.layout)\n        else:\n            Animation(top=self.height, t='out_quad', d=.3).start(self.layout)\n        for node in list(treeview.iterate_all_nodes())[:]:\n            treeview.remove_node(node)\n\n        keys = list(widget.properties().keys())\n        keys.sort()\n        node = None\n        wk_widget = weakref.ref(widget)\n        for key in keys:\n            text = '%s' % key\n            node = TreeViewProperty(text=text, key=key, widget_ref=wk_widget)\n            node.bind(is_selected=self.show_property)\n            try:\n                widget.bind(**{key: partial(\n                    self.update_node_content, weakref.ref(node))})\n            except:\n                pass\n            treeview.add_node(node)\n\n    def update_node_content(self, node, *l):\n        node = node()\n        if node is None:\n            return\n        node.refresh = True\n        node.refresh = False\n\n    def keyboard_shortcut(self, win, scancode, *largs):\n        modifiers = largs[-1]\n        if scancode == 101 and modifiers == ['ctrl']:\n            self.activated = not self.activated\n            if self.activated:\n                self.inspect_enabled = True\n            return True\n        elif scancode == 27:\n            if self.inspect_enabled:\n                self.inspect_enabled = False\n                return True\n            if self.activated:\n                self.activated = False\n                return True\n\n    def show_property(self, instance, value, key=None, index=-1, *l):\n        # normal call: (tree node, focus, )\n        # nested call: (widget, prop value, prop key, index in dict/list)\n        if value is False:\n            return\n\n        content = None\n        if key is None:\n            # normal call\n            nested = False\n            widget = instance.widget\n            key = instance.key\n            prop = widget.property(key)\n            value = getattr(widget, key)\n        else:\n            # nested call, we might edit subvalue\n            nested = True\n            widget = instance\n            prop = None\n\n        dtype = None\n\n        if isinstance(prop, AliasProperty) or nested:\n            # trying to resolve type dynamicly\n            if type(value) in (str, str):\n                dtype = 'string'\n            elif type(value) in (int, float):\n                dtype = 'numeric'\n            elif type(value) in (tuple, list):\n                dtype = 'list'\n\n        if isinstance(prop, NumericProperty) or dtype == 'numeric':\n            content = TextInput(text=str(value) or '', multiline=False)\n            content.bind(text=partial(\n                self.save_property_numeric, widget, key, index))\n        elif isinstance(prop, StringProperty) or dtype == 'string':\n            content = TextInput(text=value or '', multiline=True)\n            content.bind(text=partial(\n                self.save_property_text, widget, key, index))\n        elif (isinstance(prop, ListProperty) or\n              isinstance(prop, ReferenceListProperty) or\n              isinstance(prop, VariableListProperty) or\n              dtype == 'list'):\n            content = GridLayout(cols=1, size_hint_y=None)\n            content.bind(minimum_height=content.setter('height'))\n            for i, item in enumerate(value):\n                button = Button(text=repr(item), size_hint_y=None, height=44)\n                if isinstance(item, Widget):\n                    button.bind(on_release=partial(self.highlight_widget, item,\n                                                   False))\n                else:\n                    button.bind(on_release=partial(self.show_property, widget,\n                                                   item, key, i))\n                content.add_widget(button)\n        elif isinstance(prop, OptionProperty):\n            content = GridLayout(cols=1, size_hint_y=None)\n            content.bind(minimum_height=content.setter('height'))\n            for option in prop.options:\n                button = ToggleButton(\n                    text=option,\n                    state='down' if option == value else 'normal',\n                    group=repr(content.uid), size_hint_y=None,\n                    height=44)\n                button.bind(on_press=partial(\n                    self.save_property_option, widget, key))\n                content.add_widget(button)\n        elif isinstance(prop, ObjectProperty):\n            if isinstance(value, Widget):\n                content = Button(text=repr(value))\n                content.bind(on_release=partial(self.highlight_widget, value))\n            elif isinstance(value, Texture):\n                content = Image(texture=value)\n            else:\n                content = Label(text=repr(value))\n\n        elif isinstance(prop, BooleanProperty):\n            state = 'down' if value else 'normal'\n            content = ToggleButton(text=key, state=state)\n            content.bind(on_release=partial(self.save_property_boolean, widget,\n                                            key, index))\n\n        self.content.clear_widgets()\n        if content:\n            self.content.add_widget(content)\n\n    def save_property_numeric(self, widget, key, index, instance, value):\n        try:\n            if index >= 0:\n                getattr(widget, key)[index] = float(instance.text)\n            else:\n                setattr(widget, key, float(instance.text))\n        except:\n            pass\n\n    def save_property_text(self, widget, key, index, instance, value):\n        try:\n            if index >= 0:\n                getattr(widget, key)[index] = instance.text\n            else:\n                setattr(widget, key, instance.text)\n        except:\n            pass\n\n    def save_property_boolean(self, widget, key, index, instance, ):\n        try:\n            value = instance.state == 'down'\n            if index >= 0:\n                getattr(widget, key)[index] = value\n            else:\n                setattr(widget, key, value)\n        except:\n            pass\n\n    def save_property_option(self, widget, key, instance, *l):\n        try:\n            setattr(widget, key, instance.text)\n        except:\n            pass\n\n\ndef create_inspector(win, ctx, *l):\n    '''Create an Inspector instance attached to the *ctx* and bound to the\n    Windows :meth:`~kivy.core.window.WindowBase.on_keyboard` event for capturing\n    the keyboard shortcut.\n\n        :Parameters:\n            `win`: A :class:`Window <kivy.core.window.WindowBase>`\n                The application Window to bind to.\n            `ctx`: A :class:`~kivy.uix.widget.Widget` or subclass\n                The Widget to be inspected.\n\n    '''\n    # Dunno why, but if we are creating inspector within the start(), no lang\n    # rules are applied.\n    ctx.inspector = Inspector(win=win)\n    win.bind(children=ctx.inspector.on_window_children,\n             on_keyboard=ctx.inspector.keyboard_shortcut)\n\n\ndef start(win, ctx):\n    Clock.schedule_once(partial(create_inspector, win, ctx))\n\n\ndef stop(win, ctx):\n    '''Stop and unload any active Inspectors for the given *ctx*.'''\n    if hasattr(ctx, 'inspector'):\n        win.unbind(children=ctx.inspector.on_window_children,\n                   on_keyboard=ctx.inspector.keyboard_shortcut)\n        win.remove_widget(ctx.inspector)\n        del ctx.inspector\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/modules/keybinding.py",
    "content": "'''Keybinding\n==========\n\nThis module forces the mapping of some keys to functions:\n\n* F11: Rotate the Window through 0, 90, 180 and 270 degrees\n* Shift + F11: Switches between portrait and landscape on desktops\n* F12: Take a screenshot\n\nNote: this does't work if the application requests the keyboard beforehand.\n\nUsage\n-----\n\nFor normal module usage, please see the :mod:`~kivy.modules` documentation.\n\nThe Keybinding module, however, can also be imported and used just\nlike a normal python module. This has the added advantage of being\nable to activate and deactivate the module programmatically::\n\n    from kivy.app import App\n    from kivy.uix.button import Button\n    from kivy.modules import keybinding\n    from kivy.core.window import Window\n\n    class Demo(App):\n\n        def build(self):\n            button = Button(text=\"Hello\")\n            keybinding.start(Window, button)\n            return button\n\n    Demo().run()\n\nTo remove the Keybinding, you can do the following::\n\n    Keybinding.stop(Window, button)\n\n'''\n\nfrom kivy.utils import platform\n\n__all__ = ('start', 'stop')\n\n\ndef _on_keyboard_handler(instance, key, scancode, codepoint, modifiers):\n    if key == 293 and modifiers == []:  # F12\n        instance.screenshot()\n    elif key == 292 and modifiers == []:  # F11\n        instance.rotation += 90\n    elif key == 292 and modifiers == ['shift']:  # Shift + F11\n        if platform in ('win', 'linux', 'macosx'):\n            instance.rotation = 0\n            w, h = instance.size\n            w, h = h, w\n            instance.size = (w, h)\n\n\ndef start(win, ctx):\n    win.bind(on_keyboard=_on_keyboard_handler)\n\n\ndef stop(win, ctx):\n    win.unbind(on_keyboard=_on_keyboard_handler)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/modules/monitor.py",
    "content": "'''\nMonitor module\n==============\n\nThe Monitor module is a toolbar that shows the activity of your current\napplication :\n\n* FPS\n* Graph of input events\n\nUsage\n-----\n\nFor normal module usage, please see the :mod:`~kivy.modules` documentation.\n\n'''\n\n__all__ = ('start', 'stop')\n\nfrom kivy.uix.label import Label\nfrom kivy.graphics import Rectangle, Color\nfrom kivy.clock import Clock\nfrom functools import partial\n\n_statsinput = 0\n_maxinput = -1\n\n\ndef update_fps(ctx, *largs):\n    ctx.label.text = 'FPS: %f' % Clock.get_fps()\n    ctx.rectangle.texture = ctx.label.texture\n    ctx.rectangle.size = ctx.label.texture_size\n\n\ndef update_stats(ctx, *largs):\n    global _statsinput\n    ctx.stats = ctx.stats[1:] + [_statsinput]\n    _statsinput = 0\n    m = max(1., _maxinput)\n    for index, x in enumerate(ctx.stats):\n        ctx.statsr[index].size = (4, ctx.stats[index] / m * 20)\n\n\nclass StatsInput(object):\n\n    def process(self, events):\n        global _statsinput, _maxinput\n        _statsinput += len(events)\n        if _statsinput > _maxinput:\n            _maxinput = float(_statsinput)\n        return events\n\n\ndef start(win, ctx):\n    # late import to avoid breaking module loading\n    from kivy.input.postproc import kivy_postproc_modules\n    kivy_postproc_modules['fps'] = StatsInput()\n    global _ctx\n    ctx.label = Label(text='FPS: 0.0')\n    ctx.inputstats = 0\n    ctx.stats = []\n    ctx.statsr = []\n    with win.canvas.after:\n        ctx.color = Color(1, 0, 0, .5)\n        ctx.rectangle = Rectangle(pos=(0, win.height - 25),\n                                  size=(win.width, 25))\n        ctx.color = Color(1, 1, 1)\n        ctx.rectangle = Rectangle(pos=(5, win.height - 20))\n        ctx.color = Color(1, 1, 1, .5)\n        for x in range(64):\n            ctx.stats.append(0)\n            ctx.statsr.append(\n                Rectangle(pos=(win.width - 64 * 4 + x * 4, win.height - 25),\n                          size=(4, 0)))\n    Clock.schedule_interval(partial(update_fps, ctx), .5)\n    Clock.schedule_interval(partial(update_stats, ctx), 1 / 60.)\n\n\ndef stop(win, ctx):\n    win.canvas.remove(ctx.label)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/modules/recorder.py",
    "content": "'''\nRecorder module\n===============\n\n.. versionadded:: 1.1.0\n\nCreate an instance of :class:`~kivy.input.recorder.Recorder`, attach to the\nclass, and bind some keys to record / play sequences:\n\n    - F6: play the last record in a loop\n    - F7: read the latest recording\n    - F8: record input events\n\nConfiguration\n-------------\n\n:Parameters:\n    `attrs`: str, defaults to\n    :attr:`~kivy.input.recorder.Recorder.record_attrs` value.\n\n        Attributes to record from the motion event\n\n    `profile_mask`: str, defaults to\n    :attr:`~kivy.input.recorder.Recorder.record_profile_mask` value.\n\n        Mask for motion event profile. Used to filter which profile will appear\n        in the fake motion event when replayed.\n\n    `filename`: str, defaults to 'recorder.kvi'\n\n        Name of the file to record / play with\n\nUsage\n-----\n\nFor normal module usage, please see the :mod:`~kivy.modules` documentation.\n\n'''\n\n__all__ = ('start', 'stop')\n\nfrom kivy.logger import Logger\nfrom functools import partial\n\n\ndef replay(recorder, *args):\n    if recorder.play:\n        return\n    else:\n        recorder.play = True\n\n\ndef on_recorder_key(recorder, window, key, *largs):\n    if key == 289:  # F8\n        if recorder.play:\n            Logger.error('Recorder: Cannot start recording while playing.')\n            return\n        recorder.record = not recorder.record\n    elif key == 288:  # F7\n        if recorder.record:\n            Logger.error('Recorder: Cannot start playing while recording.')\n            return\n        recorder.play = not recorder.play\n    elif key == 287:  # F6\n        if recorder.play:\n            recorder.unbind(play=replay)\n        else:\n            recorder.bind(play=replay)\n            recorder.play = True\n\n\ndef start(win, ctx):\n    keys = {}\n\n    # attributes\n    value = ctx.config.get('attrs', None)\n    if value is not None:\n        keys['record_attrs'] = value.split(':')\n\n    # profile mask\n    value = ctx.config.get('profile_mask', None)\n    if value is not None:\n        keys['record_profile_mask'] = value.split(':')\n\n    # filename\n    value = ctx.config.get('filename', None)\n    if value is not None:\n        keys['filename'] = value\n\n    from kivy.input.recorder import Recorder\n    ctx.recorder = Recorder(window=win, **keys)\n    win.bind(on_key_down=partial(on_recorder_key, ctx.recorder))\n\n\ndef stop(win, ctx):\n    if hasattr(ctx, 'recorder'):\n        ctx.recorder.release()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/modules/screen.py",
    "content": "'''Screen\n======\n\nThis module changes some environement and configuration variables\nto match the density / dpi / screensize of a specific device.\n\nTo see a list of the available screenid's, just run::\n\n    python main.py -m screen\n\nTo simulate a medium-density screen such as the Motolora Droid 2::\n\n    python main.py -m screen:droid2\n\nTo simulate a high-density screen such as HTC One X, in portrait::\n\n    python main.py -m screen:onex,portrait\n\nTo simulate the iPad 2 screen::\n\n    python main.py -m screen:ipad\n\nIf the generated window is too large, you can specify a scale::\n\n    python main.py -m screen:note2,portrait,scale=.75\n\nNote that to display your contents correctly on a scaled window you\nmust consistently use units 'dp' and 'sp' throughout your app. See\n:mod:`~kiv.metrics` for more details.\n\n'''\n\nimport sys\nfrom os import environ\nfrom kivy.config import Config\nfrom kivy.logger import Logger\n\n# taken from http://en.wikipedia.org/wiki/List_of_displays_by_pixel_density\ndevices = {\n    # device: (name, width, height, dpi, density)\n    'onex': ('HTC One X', 1280, 720, 312, 2),\n    'one': ('HTC One', 1920, 1080, 468, 3),\n    'onesv': ('HTC One SV', 800, 480, 216, 1.5),\n    's3': ('Galaxy SIII', 1280, 720, 306, 2),\n    'note2': ('Galaxy Note II', 1280, 720, 267, 2),\n    'droid2': ('Motolora Droid 2', 854, 480, 240, 1.5),\n    'xoom': ('Motolora Xoom', 1280, 800, 149, 1),\n    'ipad': ('iPad (1 and 2)', 1024, 768, 132, 1),\n    'ipad3': ('iPad 3', 2048, 1536, 264, 2),\n    'iphone4': ('iPhone 4', 960, 640, 326, 2),\n    'iphone5': ('iPhone 5', 1136, 640, 326, 2),\n    'xperiae': ('Xperia E', 480, 320, 166, 1),\n    'nexus4': ('Nexus 4', 1280, 768, 320, 2),\n    'nexus7': ('Nexus 7 (2012 version)', 1280, 800, 216, 1.325),\n    'nexus7.2': ('Nexus 7 (2013 version)', 1920, 1200, 323, 2),\n}\n\n\ndef start(win, ctx):\n    pass\n\n\ndef stop(win, ctx):\n    pass\n\n\ndef apply_device(device, scale, orientation):\n    name, width, height, dpi, density = devices[device]\n    if orientation == 'portrait':\n        width, height = height, width\n    Logger.info('Screen: Apply screen settings for {0}'.format(name))\n    Logger.info('Screen: size={0}x{1} dpi={2} density={3} '\n                'orientation={4}'.format(width, height, dpi, density,\n                                         orientation))\n    try:\n        scale = float(scale)\n    except:\n        scale = 1\n    environ['KIVY_METRICS_DENSITY'] = str(density * scale)\n    environ['KIVY_DPI'] = str(dpi * scale)\n    Config.set('graphics', 'width', str(int(width * scale)))\n    # simulate with the android bar\n    # FIXME should be configurable\n    Config.set('graphics', 'height', str(int(height * scale - 25 * density)))\n    Config.set('graphics', 'fullscreen', '0')\n    Config.set('graphics', 'show_mousecursor', '1')\n\n\ndef usage(device=None):\n    if device:\n        Logger.error('Screen: The specified device ({0}) is unknown.',\n                     device)\n    print('\\nModule usage: python main.py -m screen:deviceid[,orientation]\\n')\n    print('Available devices:\\n')\n    print('{0:12} {1:<22} {2:<8} {3:<8} {4:<5} {5:<8}'.format(\n        'Device ID', 'Name', 'Width', 'Height', 'DPI', 'Density'))\n    for device, info in devices.items():\n        print('{0:12} {1:<22} {2:<8} {3:<8} {4:<5} {5:<8}'.format(\n            device, *info))\n    print('\\n')\n    print('Simulate a medium-density screen such as Motolora Droid 2:\\n')\n    print('    python main.py -m screen:droid2\\n')\n    print('Simulate a high-density screen such as HTC One X, in portrait:\\n')\n    print('    python main.py -m screen:onex,portrait\\n')\n    print('Simulate the iPad 2 screen\\n')\n    print('    python main.py -m screen:ipad\\n')\n    print('If the generated window is too large, you can specify a scale:\\n')\n    print('    python main.py -m screen:note2,portrait,scale=.75\\n')\n    sys.exit(1)\n\n\ndef configure(ctx):\n    scale = ctx.pop('scale', None)\n    orientation = 'landscape'\n    ctx.pop('landscape', None)\n    if ctx.pop('portrait', None):\n        orientation = 'portrait'\n    if not ctx:\n        return usage(None)\n    device = list(ctx.keys())[0]\n    if device not in devices:\n        return usage('')\n    apply_device(device, scale, orientation)\n\nif __name__ == \"__main__\":\n    for n in devices.values():\n        assert n[1] > n[2]\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/modules/touchring.py",
    "content": "'''\nTouchring\n=========\n\nShows rings around every touch on the surface / screen. You can use this module\nto check that you don't have any calibration issues with touches.\n\nConfiguration\n-------------\n\n:Parameters:\n    `image`: str, defaults to '<kivy>/data/images/ring.png'\n        Filename of the image to use.\n    `scale`: float, defaults to 1.\n        Scale of the image.\n    `alpha`: float, defaults to 1.\n        Opacity of the image.\n    `show_cursor`: boolean, defaults to False\n        .. versionadded:: 1.8.0\n    `cursor_image`: str, defaults to\n        'atlas://data/images/defaulttheme/slider_cursor' Image used to\n        represent the cursor if displayed\n        .. versionadded:: 1.8.0\n    `cursor_size`: tuple, defaults to (None, None)\n        Apparent size of the mouse cursor, if displayed, default value\n        will keep its real size.\n        .. versionadded:: 1.8.0\n    `cursor_offset`: tuple, defaults to (None, None)\n        Offset of the texture image. The default value will align the\n        top-left corner of the image to the mouse pos.\n        .. versionadded:: 1.8.0\n\nExample\n-------\n\nIn your configuration (`~/.kivy/config.ini`), you can add something like\nthis::\n\n    [modules]\n    touchring = image=mypointer.png,scale=.3,alpha=.7\n\n'''\n\n__all__ = ('start', 'stop')\n\nfrom kivy.core.image import Image\nfrom kivy.graphics import Color, Rectangle\n\npointer_image = None\npointer_scale = 1.0\npointer_alpha = 0.7\ncursor_image = ''\ncursor_offset = (0, 0)\ncursor_size = (None, None)\n\n\ndef _touch_down(win, touch):\n    ud = touch.ud\n    touch.scale_for_screen(win.width, win.height)\n    with win.canvas.after:\n        ud['tr.color'] = Color(1, 1, 1, pointer_alpha)\n        iw, ih = pointer_image.size\n        ud['tr.rect'] = Rectangle(\n            pos=(\n                touch.x - (pointer_image.width / 2. * pointer_scale),\n                touch.y - (pointer_image.height / 2. * pointer_scale)),\n            size=(iw * pointer_scale, ih * pointer_scale),\n            texture=pointer_image.texture)\n\n    if not ud.get('tr.grab', False):\n        ud['tr.grab'] = True\n        touch.grab(win)\n\n\ndef _touch_move(win, touch):\n    ud = touch.ud\n    ud['tr.rect'].pos = (\n        touch.x - (pointer_image.width / 2. * pointer_scale),\n        touch.y - (pointer_image.height / 2. * pointer_scale))\n\n\ndef _touch_up(win, touch):\n    if touch.grab_current is win:\n        ud = touch.ud\n        win.canvas.after.remove(ud['tr.color'])\n        win.canvas.after.remove(ud['tr.rect'])\n\n        if ud.get('tr.grab') is True:\n            touch.ungrab(win)\n            ud['tr.grab'] = False\n\n\ndef _mouse_move(win, pos, *args):\n    global cursor_size\n    if hasattr(win, '_cursor'):\n        c = win._cursor\n    else:\n        with win.canvas.after:\n            img = Image(cursor_image)\n            Color(1, 1, 1, 1, mode='rgba')\n            size = (\n                cursor_size[0] or img.texture.size[0],\n                cursor_size[1] or img.texture.size[1]\n            )\n            print(size)\n            win._cursor = c = Rectangle(texture=img.texture,\n                                        size=size)\n\n    c.pos = pos[0] + cursor_offset[0], pos[1] - c.size[1] + cursor_offset[1]\n\n\ndef start(win, ctx):\n    # XXX use ctx !\n    global pointer_image, pointer_scale, pointer_alpha, cursor_size,\\\n        cursor_image, cursor_offset\n    pointer_fn = ctx.config.get('image',\n                                'atlas://data/images/defaulttheme/ring')\n    pointer_scale = float(ctx.config.get('scale', 1.0))\n    pointer_alpha = float(ctx.config.get('alpha', 1.0))\n    pointer_image = Image(pointer_fn)\n    cursor_image = ctx.config.get(\n        'cursor_image',\n        'atlas://data/images/defaulttheme/slider_cursor')\n    cursor_size = ctx.config.get('cursor_size', (None, None))\n    if isinstance(cursor_size, str):\n        cursor_size = [int(x) for x in cursor_size.split('x')]\n\n    cursor_offset = ctx.config.get('cursor_offset', (0, 0))\n    if isinstance(cursor_offset, str):\n        cursor_offset = [int(x) for x in cursor_offset.split('x')]\n\n    win.bind(on_touch_down=_touch_down,\n             on_touch_move=_touch_move,\n             on_touch_up=_touch_up)\n\n    if ctx.config.get('show_cursor', False):\n        print('adding binding for mouse move')\n        win.bind(mouse_pos=_mouse_move)\n\n\ndef stop(win, ctx):\n    win.unbind(on_touch_down=_touch_down,\n               on_touch_move=_touch_move,\n               on_touch_up=_touch_up,\n               on_mouse_pos=_mouse_move)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/modules/webdebugger.py",
    "content": "# -*- coding: utf-8 -*-\n'''\nWeb Debugger\n============\n\n.. versionadded:: 1.2.0\n\n.. warning::\n\n    This module is highly experimental, use it with care.\n\nThis module will start a webserver and run in the background. You can\nsee how your application evolves during runtime, examine the internal\ncache etc.\n\nRun with::\n\n    python main.py -m webdebugger\n\nThen open your webbrowser on http://localhost:5000/\n\n'''\n\n__all__ = ('start', 'stop')\n\nimport os\nif 'KIVY_DOC' not in os.environ:\n    from kivy.modules._webdebugger import start, stop\nelse:\n    start = stop = lambda *x: True\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/multistroke.py",
    "content": "'''\nMultistroke gesture recognizer\n==============================\n\n.. versionadded::\n    1.9.0\n\n.. warning::\n\n    This is experimental and subject to change as long as this warning notice\n    is present.\n\nSee :file:`kivy/examples/demo/multistroke/main.py` for a complete application\nexample.\n\nConceptual Overview\n-------------------\n\nThis module implements the Protractor gesture recognition algorithm.\n\n:class:`Recognizer` is the search/database API similar to\n:class:`~kivy.gesture.GestureDatabase`. It maintains a list of\n:class:`MultistrokeGesture` objects and allows you to search for a\nuser-input gestures among them.\n\n:class:`ProgressTracker` tracks the progress of a :meth:`Recognizer.recognize`\ncall. It can be used to interact with the running recognizer task, for example\nforcing it to stop half-way, or analyzing results as they arrive.\n\n:class:`MultistrokeGesture` represents a gesture in the gesture database\n(:attr:`Recognizer.db`). It is a container for :class:`UnistrokeTemplate`\nobjects, and implements the heap permute algorithm to automatically generate\nall possible stroke orders (if desired).\n\n:class:`UnistrokeTemplate` represents a single stroke path. It's typically\ninstantiated automatically by :class:`MultistrokeGesture`, but sometimes you\nmay need to create them manually.\n\n:class:`Candidate` represents a user-input gesture that is used to search\nthe gesture database for matches. It is normally instantiated automatically\nby calling :meth:`Recognizer.recognize`.\n\nUsage examples\n--------------\n\nSee :file:`kivy/examples/demo/multistroke/main.py` for a complete application\nexample.\n\nYou can bind to events on :class:`Recognizer` to track the state of all\ncalls to :meth:`Recognizer.recognize`. The callback function will receive an\ninstance of :class:`ProgressTracker` that can be used to analyze and control\nvarious aspects of the recognition process ::\n\n    from kivy.vector import Vector\n    from kivy.multistroke import Recognizer\n\n    gdb = Recognizer()\n\n    def search_start(gdb, pt):\n        print(\"A search is starting with %d tasks\" % (pt.tasks))\n\n    def search_stop(gdb, pt):\n        # This will call max() on the result dictonary, so it's best to store\n        # it instead of calling it 3 times consecutively\n        best = pt.best\n        print(\"Search ended (%s). Best is %s (score %f, distance %f)\" % (\n            pt.status, best['name'], best['score'], best['dist'] ))\n\n    # Bind your callbacks to track all matching operations\n    gdb.bind(on_search_start=search_start)\n    gdb.bind(on_search_complete=search_stop)\n\n    # The format below is referred to as `strokes`, a list of stroke paths.\n    # Note that each path shown here consists of two points, ie a straight\n    # line; if you plot them it looks like a T, hence the name.\n    gdb.add_gesture('T', [\n        [Vector(30, 7), Vector(103, 7)],\n        [Vector(66, 7), Vector(66, 87)]])\n\n    # Now you can search for the 'T' gesture using similar data (user input).\n    # This will trigger both of the callbacks bound above.\n    gdb.recognize([\n        [Vector(45, 8), Vector(110, 12)],\n        [Vector(88, 9), Vector(85, 95)]])\n\nOn the next :class:`~kivy.clock.Clock` tick, the matching process starts\n(and, in this case, completes).\n\nTo track individual calls to :meth:`Recognizer.recognize`, use the return\nvalue (also a :class:`ProgressTracker` instance) ::\n\n    # Same as above, but keep track of progress using returned value\n    progress = gdb.recognize([\n        [Vector(45, 8), Vector(110, 12)],\n        [Vector(88, 9), Vector(85, 95)]])\n\n    progress.bind(on_progress=my_other_callback)\n    print(progress.progress) # = 0\n\n    # [ assuming a kivy.clock.Clock.tick() here ]\n\n    print(result.progress) # = 1\n\nAlgorithm details\n-----------------\n\nFor more information about the matching algorithm, see:\n\n\"Protractor: A fast and accurate gesture recognizer\" by Yang Li\n  http://yangl.org/pdf/protractor-chi2010.pdf\n\n\"$N-Protractor\" by Lisa Anthony and Jacob O. Wobbrock\n  http://depts.washington.edu/aimgroup/proj/dollar/ndollar-protractor.pdf\n\nSome of the code is derived from the JavaScript implementation here:\n  http://depts.washington.edu/aimgroup/proj/dollar/ndollar.html\n'''\n\n__all__ = ('Recognizer', 'ProgressTracker', 'MultistrokeGesture',\n           'UnistrokeTemplate', 'Candidate')\n\nimport pickle\nimport base64\nimport zlib\nfrom re import match as re_match\nfrom collections import deque\nfrom math import sqrt, pi, radians, acos, atan, atan2, pow, floor\nfrom math import sin as math_sin, cos as math_cos\nfrom kivy.vector import Vector\nfrom kivy.clock import Clock\nfrom kivy.event import EventDispatcher\nfrom kivy.properties import ListProperty\nfrom kivy.compat import PY2\nfrom io import BytesIO\n\nif not PY2:\n    xrange = range\n\n# Default number of gesture matches per frame\n# FIXME: relevant number\nDEFAULT_GPF = 10\n\n# Algorithm data\nSQUARESIZE = 250.0\nONEDTHRESHOLD = 0.25\nORIGIN = Vector(0, 0)\n\n\nclass MultistrokeError(Exception):\n    pass\n\n\n# -----------------------------------------------------------------------------\n# Recognizer\n# -----------------------------------------------------------------------------\n\nclass Recognizer(EventDispatcher):\n    ''':class:`Recognizer` provides a gesture database with matching\n    facilities.\n\n    :Events:\n        `on_search_start`\n            Fired when a new search is started using this Recognizer.\n\n        `on_search_complete`\n            Fired when a running search ends, for whatever reason.\n            (use :data:`ProgressTracker.status` to find out)\n\n    :Properties:\n        `db`\n            A :class:`ListProperty` that contains the available\n            :class:`MultistrokeGesture` objects.\n\n            :attr:`db` is a\n            :class:`~kivy.properties.ListProperty` and defaults to []\n    '''\n\n    db = ListProperty([])\n\n    def __init__(self, **kwargs):\n        super(Recognizer, self).__init__(**kwargs)\n        self.register_event_type('on_search_start')\n        self.register_event_type('on_search_complete')\n\n    def filter(self, **kwargs):\n        ''':meth:`filter` returns a subset of objects in :attr:`self.db`,\n        according to given criteria. This is used by many other methods of\n        the :class:`Recognizer`; the arguments below can for example be\n        used when calling :meth:`Recognizer.recognize` or\n        :meth:`Recognizer.export_gesture`. You normally don't need to call\n        this directly.\n\n        :Arguments:\n\n            `name`\n                Limits the returned list to gestures where\n                :attr:`MultistrokeGesture.name` matches given regular\n                expression(s). If re.match(name, MultistrokeGesture.name)\n                tests true, the gesture is included in the returned list.\n                Can be a string or an array of strings ::\n\n                    gdb = Recognizer()\n\n                    # Will match all names that start with a captial N\n                    # (ie Next, New, N, Nebraska etc, but not \"n\" or \"next\")\n                    gdb.filter(name='N')\n\n                    # exactly 'N'\n                    gdb.filter(name='N$')\n\n                    # Nebraska, teletubbies, France, fraggle, N, n, etc\n                    gdb.filter(name=['[Nn]', '(?i)T', '(?i)F'])\n\n            `priority`\n                Limits the returned list to gestures with certain\n                :attr:`MultistrokeGesture.priority` values. If specified as an\n                integer, only gestures with a lower priority are returned. If\n                specified as a list (min/max) ::\n\n                    # Max priority 50\n                    gdb.filter(priority=50)\n\n                    # Max priority 50 (same result as above)\n                    gdb.filter(priority=[0, 50])\n\n                    # Min priority 50, max 100\n                    gdb.filter(priority=[50, 100])\n\n                When this option is used, :attr:`Recognizer.db` is automatically\n                sorted according to priority, incurring extra cost. You can use\n                `force_priority_sort` to override this behavior if your gestures\n                are already sorted according to priority.\n\n            `orientation_sensitive`\n                Limits the returned list to gestures that are\n                orientation sensitive (True), gestures that are not orientation\n                sensitive (False) or None (ignore template sensitivity, this is\n                the default).\n\n            `numstrokes`\n                Limits the returned list to gestures that have the specified\n                number of strokes (in :attr:`MultistrokeGesture.strokes`).\n                Can be a single integer or a list of integers.\n\n            `numpoints`\n                Limits the returned list to gestures that have specific\n                :attr:`MultistrokeGesture.numpoints` values. This is provided\n                for flexibility, do not use it unless you understand what it\n                does. Can be a single integer or a list of integers.\n\n            `force_priority_sort`\n                Can be used to override the default sort behavior. Normally\n                :class:`MultistrokeGesture` objects are returned in priority\n                order if the `priority` option is used. Setting this to True\n                will return gestures sorted in priority order, False will\n                return in the order gestures were added. None means decide\n                automatically (the default).\n\n                .. Note ::\n                    For improved performance, you can load your gesture\n                    database in priority order and set this to False when\n                    calling :meth:`Recognizer.recognize`\n\n            `db`\n                Can be set if you want to filter a different list of objects\n                than :attr:`Recognizer.db`. You probably don't want to do this;\n                it is used internally by :meth:`import_gesture`.\n        '''\n        have_filters = False\n\n        kwargs_get = kwargs.get\n\n        name = kwargs_get('name', None)\n        if name is not None:\n            have_filters = True\n            if not isinstance(name, list):\n                name = [name]\n\n        priority = kwargs_get('priority', None)\n        min_p, max_p = None, None\n        if priority is not None:\n            have_filters = True\n            if isinstance(priority, list):\n                min_p, max_p = priority\n            elif isinstance(priority, int):\n                min_p, max_p = None, priority\n\n        numstrokes = kwargs_get('numstrokes', None)\n        if numstrokes is not None:\n            have_filters = True\n            if not isinstance(numstrokes, list):\n                numstrokes = [numstrokes]\n\n        numpoints = kwargs_get('numpoints', None)\n        if numpoints is not None:\n            have_filters = True\n            if not isinstance(numpoints, list):\n                numpoints = [numpoints]\n\n        orientation_sens = kwargs_get('orientation_sensitive', None)\n        if orientation_sens is not None:\n            have_filters = True\n\n        # Prepare a correctly sorted tasklist\n        force_priority_sort = kwargs.get('force_priority_sort', None)\n        force_sort_on = force_priority_sort and True\n        force_sort_off = (force_priority_sort is False) and True\n\n        db = kwargs.get('db', None) or self.db\n        if (force_sort_on or priority) and not force_sort_off:\n            tasklist = sorted(db, key=lambda n: n.priority)\n        else:\n            tasklist = db\n\n        # Now test each gesture in the database against filter criteria\n        out = deque()\n        if not have_filters:\n            out.extend(tasklist)\n            return out\n\n        out_append = out.append\n        for gesture in tasklist:\n\n            if (orientation_sens is not None and\n                    orientation_sens != gesture.orientation_sens):\n                continue\n\n            if numpoints and gesture.numpoints not in numpoints:\n                continue\n\n            if numstrokes and len(gesture.strokes) not in numstrokes:\n                continue\n\n            if min_p is not None and gesture.priority < min_p:\n                continue\n\n            if max_p is not None and gesture.priority > max_p:\n                return out\n\n            if name:\n                for f in name:\n                    if re_match(f, gesture.name):\n                        out_append(gesture)\n                        break\n            else:\n                out_append(gesture)\n\n        return out\n\n    def add_gesture(self, name, strokes, **kwargs):\n        '''Add a new gesture to the database. This will instantiate a new\n        :class:`MultistrokeGesture` with `strokes` and append it to self.db.\n\n        .. Note ::\n            If you already have instantiated a :class:`MultistrokeGesture`\n            object and wish to add it, append it to :attr:`Recognizer.db`\n            manually.\n        '''\n        if not strokes:\n            return False\n        self.db.append(MultistrokeGesture(name=name, strokes=strokes, **kwargs))\n        return True\n\n    def parse_gesture(self, data):\n        '''Parse data formatted by export_gesture(). Returns a list of\n        :class:`MultistrokeGesture` objects. This is used internally by\n        :meth:`import_gesture`, you normally don't need to call this\n        directly.'''\n        io = BytesIO(zlib.decompress(base64.b64decode(data)))\n\n        p = pickle.Unpickler(io)\n        multistrokes = []\n        ms_append = multistrokes.append\n        for multistroke in p.load():\n            strokes = multistroke['strokes']\n            multistroke['strokes'] = [[Vector(\n                x, y) for x, y in line] for line in strokes]\n            ms_append(MultistrokeGesture(**multistroke))\n        return multistrokes\n\n    # FIXME: use a try block, maybe shelve or something\n    def export_gesture(self, filename=None, **kwargs):\n        '''Export a list of :class:`MultistrokeGesture` objects. Outputs a\n        base64-encoded string that can be decoded to a Python list with\n        the :meth:`parse_gesture` function or imported directly to\n        :attr:`self.db` using :meth:`Recognizer.import_gesture`. If\n        `filename` is specified, the output is written to disk, otherwise\n        returned.\n\n        This method accepts optional :meth:`Recognizer.filter` arguments.\n        '''\n        io = BytesIO()\n        p = pickle.Pickler(io, protocol=0)\n        multistrokes = []\n        defaults = {'priority': 100, 'numpoints': 16, 'stroke_sens': True,\n                    'orientation_sens': False, 'angle_similarity': 30.0}\n        dkeys = defaults.keys()\n\n        for multistroke in self.filter(**kwargs):\n            m = dict(defaults)\n            m = {'name': multistroke.name}\n            for attr in dkeys:\n                m[attr] = getattr(multistroke, attr)\n            m['strokes'] = tuple([(p.x, p.y) for p in line]\n                                 for line in multistroke.strokes)\n            multistrokes.append(m)\n        p.dump(multistrokes)\n\n        if filename:\n            f = open(filename, 'wb')\n            f.write(base64.b64encode(zlib.compress(io.getvalue(), 9)))\n            f.close()\n        else:\n            return base64.b64encode(zlib.compress(io.getvalue(), 9))\n\n    # FIXME: match them all with protractor, and don't load exacts? or\n    # just compare the data or something; seems better to do this on import\n    # than on every subsequent call to recognize(). And fix it in general,\n    # too.\n    def import_gesture(self, data=None, filename=None, **kwargs):\n        '''Import a list of gestures as formatted by :meth:`export_gesture`.\n        One of `data` or `filename` must be specified.\n\n        This method accepts optional :meth:`Recognizer.filter` arguments,\n        if none are specified then all gestures in specified data are\n        imported.'''\n        if filename is not None:\n            with open(filename, \"rb\") as infile:\n                data = infile.read()\n        elif data is None:\n            raise MultistrokeError('import_gesture needs data= or filename=')\n\n        new = self.filter(db=self.parse_gesture(data), **kwargs)\n        if new:\n            self.db.extend(new)\n\n    def transfer_gesture(self, tgt, **kwargs):\n        '''Transfers :class:`MultistrokeGesture` objects from\n        :attr:`Recognizer.db` to another :class:`Recognizer` instance `tgt`.\n\n        This method accepts optional :meth:`Recognizer.filter` arguments.\n        '''\n        if hasattr(tgt, 'db') and isinstance(tgt.db, list):\n            send = self.filter(**kwargs)\n            if send:\n                tgt.db.append(None)\n                tgt.db[-1:] = send\n                return True\n\n    def prepare_templates(self, **kwargs):\n        '''This method is used to prepare :class:`UnistrokeTemplate` objects\n        within the gestures in self.db. This is useful if you want to minimize\n        punishment of lazy resampling by preparing all vectors in advance. If\n        you do this before a call to :meth:`Recognizer.export_gesture`, you\n        will have the vectors computed when you load the data later.\n\n        This method accepts optional :meth:`Recognizer.filter` arguments.\n\n        `force_numpoints`, if specified, will prepare all templates to the\n        given number of points (instead of each template's preferred n; ie\n        :data:`UnistrokeTemplate.numpoints`). You normally don't want to\n        do this.'''\n        for gesture in self.filter(**kwargs):\n            for tpl in gesture:\n                n = kwargs.get('force_numpoints', tpl.numpoints)\n                tpl.prepare(n)\n\n    def recognize(self, strokes, goodscore=None, timeout=0, delay=0, **kwargs):\n        '''Search for gestures matching `strokes`. Returns a\n        :class:`ProgressTracker` instance.\n\n        This method accepts optional :meth:`Recognizer.filter` arguments.\n\n        :Arguments:\n\n            `strokes`\n                A list of stroke paths (list of lists of\n                :class:`~kivy.vector.Vector` objects) that will be matched\n                against gestures in the database. Can also be a\n                :class:`Candidate` instance.\n\n                .. Warning ::\n\n                    If you manually supply a :class:`Candidate` that has a\n                    skip-flag, make sure that the correct filter arguments\n                    are set. Otherwise the system will attempt to load vectors\n                    that have not been computed. For example, if you set\n                    `skip_bounded` and do not set `orientation_sensitive` to\n                    False, it will raise an exception if an\n                    orientation_sensitive :class:`UnistrokeTemplate`\n                    is encountered.\n\n            `goodscore`\n                If this is set (between 0.0 - 1.0) and a gesture score is\n                equal to or higher than the specified value, the search is\n                immediately halted and the on_search_complete event is\n                fired (+ the on_complete event of the associated\n                :class:`ProgressTracker` instance). Default is None (disabled).\n\n            `timeout`\n                Specifies a timeout (in seconds) for when the search is\n                aborted and the results returned. This option applies only\n                when `max_gpf` is not 0. Default value is 0, meaning all\n                gestures in the database will be tested, no matter how long\n                it takes.\n\n            `max_gpf`\n                Specifies the maximum number of :class:`MultistrokeGesture`\n                objects that can be processed per frame. When exceeded, will\n                cause the search to halt and resume work in the next frame.\n                Setting to 0 will complete the search immediately (and block\n                the UI).\n\n                .. Warning ::\n\n                    This does not limit the number of\n                    :class:`UnistrokeTemplate` objects matched! If a single\n                    gesture has a million templates, they will all be\n                    processed in a single frame with max_gpf=1!\n\n            `delay`\n                Sets an optional delay between each run of the recognizer\n                loop. Normally, a run is scheduled for the next frame until\n                the tasklist is exhausted. If you set this, there will be an\n                additional delay between each run (specified in seconds).\n                Default is 0, resume in the next frame.\n\n            `force_numpoints`\n                forces all templates (and candidate) to be prepared to a\n                certain number of points. This can be useful for example if\n                you are evaluating templates for optimal n (do not use this\n                unless you understand what it does).\n        '''\n        GPF = kwargs.get('max_gpf', DEFAULT_GPF)\n\n        # Obtain a list of MultistrokeGesture objects matching filter arguments\n        tasklist = self.filter(**kwargs)\n\n        # Initialize the candidate and result objects\n        cand = self._candidate(strokes)\n        result = ProgressTracker(cand, len(tasklist))\n\n        # This is done to inform caller if they bind to on_complete and there\n        # is nothing to do; perhaps should just return None?\n        if not tasklist:\n            result.status = 'complete'\n            self.dispatch('on_search_complete', result)\n\n            def result_hack(dt):\n                result.dispatch('on_complete')\n            Clock.schedule_once(result_hack)\n            return result\n\n        # This callback is scheduled once per frame until completed\n        def _recognize_tick(dt):\n            start_gc = result._completed\n            stop_now = False\n\n            while not stop_now and (tasklist and not result._break_flag) and \\\n                    (not GPF or (result._completed - start_gc < GPF)):\n\n                if (timeout and\n                        Clock.get_time() - result._start_time >= timeout):\n                    result.status = 'timeout'\n                    stop_now = True\n                    break\n\n                # Get the best distance and number of matching operations done\n                gesture = tasklist.popleft()\n                tpl, d, res, mos = gesture.match_candidate(\n                    cand, **kwargs)\n\n                if tpl is not None:\n                    score = result._add_result(gesture, d, tpl, res)\n                    if goodscore is not None and score >= goodscore:\n                        result.status = 'goodscore'\n                        stop_now = True\n\n                result._match_ops += mos\n                result._completed += 1\n                result.dispatch('on_progress')\n\n            # The loop has ended. Prepare to dispatch 'complete'\n            def _dispatch():\n                result.dispatch('on_complete')\n                self.dispatch('on_search_complete', result)\n                return False\n\n            # Dispatch or reschedule another run\n            if not tasklist:\n                result.status = 'complete'\n                return _dispatch()\n            elif result._break_flag:\n                result.status = 'stop'\n                return _dispatch()\n            elif stop_now:\n                return _dispatch()\n            else:\n                Clock.schedule_once(_recognize_tick, delay)\n                return True\n        # End _recognize_tick()\n\n        self.dispatch('on_search_start', result)\n        if not GPF:\n            _recognize_tick(0)\n        else:\n            Clock.schedule_once(_recognize_tick, 0)\n\n        return result\n\n    def _candidate(self, strokes, **kwargs):\n        # recognize() helper function, do not use directly. Set up a\n        # Candidate object from arguments. Either use a specified object\n        # or make a new one from strokes and apply safe skip_* settings to\n        # use less resources.\n        if isinstance(strokes, Candidate):\n            return strokes\n\n        if (not isinstance(strokes, list) or not len(strokes) or not\n                isinstance(strokes[0], list)):\n            raise MultistrokeError('recognize() needs strokes= '\n                                   'list or Candidate')\n\n        cand = Candidate(strokes)\n        o_filter = kwargs.get('orientation_sensitive', None)\n        if o_filter is False:\n            cand.skip_bounded = True\n        elif o_filter is True:\n            cand.skip_invariant = True\n\n        return cand\n\n    # Default event handlers\n    def on_search_start(self, result):\n        pass\n\n    def on_search_complete(self, result):\n        pass\n\n\n# -----------------------------------------------------------------------------\n# ProgressTracker\n# -----------------------------------------------------------------------------\n\nclass ProgressTracker(EventDispatcher):\n    '''Represents an ongoing (or completed) search operation. Instantiated and\n    returned by the :meth:`Recognizer.recognize` method when it is called. The\n    `results` attribute is a dictionary that is  updated as the recognition\n    operation progresses.\n\n    .. Note ::\n        You do not need to instantiate this class.\n\n    :Arguments:\n        `candidate`\n            :class:`Candidate` object to be evaluated\n        `tasks`\n            Total number of gestures in tasklist (to test against)\n\n    :Events:\n        `on_progress`\n            Fired for every gesture that is processed\n        `on_result`\n            Fired when a new result is added, and it is the first match\n            for the `name` so far, or a consecutive match with better score.\n        `on_complete`\n            Fired when the search is completed, for whatever reason.\n            (use `ProgressTracker.status` to find out)\n\n    :Attributes:\n        `results`\n            A dictionary of all results (so far). The key is the name of the\n            gesture (ie :attr:`UnistrokeTemplate.name` usually inherited from\n            :class:`MultistrokeGesture`). Each item in the dictionary is a\n            dict with the following entries:\n\n                `name`\n                    Name of the matched template (redundant)\n                `score`\n                    Computed score from 1.0 (perfect match) to 0.0\n                `dist`\n                    Cosine distance from candidate to template (low=closer)\n                `gesture`\n                    The :class:`MultistrokeGesture` object that was matched\n                `best_template`\n                    Index of the best matching template (in\n                    :attr:`MultistrokeGesture.templates`)\n                `template_results`\n                    List of distances for all templates. The list index\n                    corresponds to a :class:`UnistrokeTemplate` index in\n                    gesture.templates.\n\n        `status`\n            `search`\n                Currently working\n            `stop`\n                Was stopped by the user (:meth:`stop` called)\n            `timeout`\n                A timeout occured (specified as `timeout=` to recognize())\n            `goodscore`\n                The search was stopped early because a gesture with a high\n                enough score was found (specified as `goodscore=` to\n                recognize())\n            `complete`\n                The search is complete (all gestures matching filters were\n                tested)\n    '''\n    def __init__(self, candidate, tasks, **kwargs):\n        self.status = 'search'\n        self.candidate = candidate\n        self.results = {}\n        self.tasks = tasks\n        self._start_time = Clock.get_time()\n        self._match_ops = 0\n        self._completed = 0\n        self._break_flag = False\n\n        # fired by recognize()\n        self.register_event_type('on_complete')\n        self.register_event_type('on_progress')\n\n        # fired locally\n        self.register_event_type('on_result')\n        super(ProgressTracker, self).__init__(**kwargs)\n\n    @property\n    def progress(self):\n        '''Returns the progress as a float, 0 is 0% done, 1 is 100%. This\n        is a Python property.'''\n        if not self.tasks:\n            return 1\n        return self._completed / float(self.tasks)\n\n    @property\n    def best(self):\n        '''Return the best match found by recognize() so far. It returns a\n        dictionary with three keys, 'name', 'dist' and 'score' representing\n        the template's name, distance (from candidate path) and the\n        computed score value. This is a Python property.'''\n        results = self.results  # to avoid too many self. lookups\n        if not results:\n            return {'name': None, 'dist': None, 'score': 0}\n        b = max(results, key=lambda r: results[r]['score'])\n        return {\n            'name': results[b]['name'],\n            'dist': results[b]['dist'],\n            'score': results[b]['score']\n        }\n\n    def stop(self):\n        '''Raises a stop flag that is checked by the search process. It will\n        be stopped on the next clock tick (if it is still running).'''\n        self._break_flag = True\n\n    def _add_result(self, gesture, dist, tpl, res):\n        # Add a result; used internally by the recognize() function\n        if tpl <= len(res):\n            n = gesture.templates[tpl].name\n        else:\n            return 0.\n\n        if n not in self.results or dist < self.results[n]['dist']:\n            self.results[n] = {\n                'name': n,\n                'dist': dist,\n                'gesture': gesture,\n                'best_template': tpl,\n                'template_results': res\n            }\n\n            if not dist:\n                self.results[n]['score'] = 1.0\n            else:\n                self.results[n]['score'] = 1.0 - (dist / pi)\n\n            self.dispatch('on_result', self.results[n])\n            return self.results[n]['score']\n        else:\n            return 0.\n\n    def on_complete(self):\n        pass\n\n    def on_progress(self):\n        pass\n\n    def on_result(self, result):\n        pass\n\n\n# -----------------------------------------------------------------------------\n# MultistrokeGesture\n# -----------------------------------------------------------------------------\n\nclass MultistrokeGesture(object):\n    ''':class:`MultistrokeGesture` represents a gesture. It maintains a set of\n    `strokes` and generates unistroke (ie :class:`UnistrokeTemplate`)\n    permutations that are used for evaluating candidates against this gesture\n    later.\n\n    :Arguments:\n        `name`\n            Identifies the name of the gesture - it is returned to you in the\n            results of a :meth:`Recognizer.recognize` search. You can have any\n            number of MultistrokeGesture objects with the same name; many\n            definitions of one gesture. The same name is given to all the\n            generated unistroke permutations. Required, no default.\n        `strokes`\n            A list of paths that represents the gesture. A path is a list of\n            Vector objects::\n\n                gesture = MultistrokeGesture('my_gesture', strokes=[\n                  [Vector(x1, y1), Vector(x2, y2), ...... ], # stroke 1\n                  [Vector(), Vector(), Vector(), Vector() ]  # stroke 2\n                  #, [stroke 3], [stroke 4], ...\n                ])\n\n            For template matching purposes, all the strokes are combined to a\n            single list (unistroke). You should still specify the strokes\n            individually, and set `stroke_sensitive` True (whenever possible).\n\n            Once you do this, unistroke permutations are immediately generated\n            and stored in `self.templates` for later, unless you set the\n            `permute` flag to False.\n        `priority`\n            Determines when :func:`Recognizer.recognize` will attempt to match\n            this template, lower priorities are evaluated first (only if\n            a priority `filter` is used). You should use lower priority on\n            gestures that are more likely to match. For example, set user\n            templates at lower number than generic templates. Default is 100.\n        `numpoints`\n            Determines the number of points this gesture should be resampled to\n            (for matching purposes). The default is 16.\n        `stroke_sensitive`\n            Determines if the number of strokes (paths) in this gesture is\n            required to be the same in the candidate (user input) gesture\n            during matching. If this is False, candidates will always be\n            evaluated, disregarding the number of strokes. Default is True.\n        `orientation_sensitive`\n            Determines if this gesture is orientation sensitive. If True,\n            aligns the indicative orientation with the one of eight base\n            orientations that requires least rotation. Default is True.\n        `angle_similarity`\n            This is used by the :func:`Recognizer.recognize` function when a\n            candidate is evaluated against this gesture. If the angles between\n            them are too far off, the template is considered a non-match.\n            Default is 30.0 (degrees)\n        `permute`\n            If False, do not use Heap Permute algorithm to generate different\n            stroke orders when instantiated. If you set this to False, a\n            single UnistrokeTemplate built from `strokes` is used.\n    '''\n    def __init__(self, name, strokes=None, **kwargs):\n        self.name = name\n        self.priority = kwargs.get('priority', 100)\n        self.numpoints = kwargs.get('numpoints', 16)\n        self.stroke_sens = kwargs.get('stroke_sensitive', True)\n        self.orientation_sens = kwargs.get('orientation_sensitive', True)\n        self.angle_similarity = kwargs.get('angle_similarity', 30.0)\n        self.strokes = []\n\n        if strokes is not None:\n            self.strokes = strokes\n            if kwargs.get('permute', True):\n                self.permute()\n            else:\n                self.templates = [UnistrokeTemplate(name,\n                                  points=[i for sub in strokes for i in sub],\n                                  numpoints=self.numpoints,\n                                  orientation_sensitive=self.orientation_sens)]\n\n    def angle_similarity_threshold(self):\n        return radians(self.angle_similarity)\n\n    def add_stroke(self, stroke, permute=False):\n        '''Add a stroke to the self.strokes list. If `permute` is True, the\n        :meth:`permute` method is called to generate new unistroke templates'''\n        self.strokes.append(stroke)\n        if permute:\n            self.permute()\n\n    def get_distance(self, cand, tpl, numpoints=None):\n        '''Compute the distance from this Candiate to a UnistrokeTemplate.\n        Returns the Cosine distance between the stroke paths.\n\n        `numpoints` will prepare both the UnistrokeTemplate and Candidate path\n        to n points (when neccessary), you probably don't want to do this.\n        '''\n        n = numpoints\n        if n is None or n < 2:\n            n = self.numpoints\n\n        # optimal_cosine_distance() inlined here for performance\n        v1 = tpl.get_vector(n)\n        v2 = cand.get_protractor_vector(n, tpl.orientation_sens)\n\n        a = 0.0\n        b = 0.0\n\n        for i in xrange(0, len(v1), 2):\n            a += (v1[i] * v2[i]) + (v1[i + 1] * v2[i + 1])\n            b += (v1[i] * v2[i + 1]) - (v1[i + 1] * v2[i])\n\n        angle = atan(b / a)\n\n        # If you put the below directly into math.acos(), you will get a domain\n        # error when a=1.0 and angle=0.0 (ie math_cos(angle)=1.0). It seems to\n        # be because float representation of 1.0*1.0 is >1.0 (ie 1.00000...001)\n        # and this is problematic for math.acos(). If you try math.acos(1.0*1.0)\n        # in interpreter it does not happen, only with exact match at runtime\n        result = a * math_cos(angle) + b * math_sin(angle)\n\n        # FIXME: I'm sure there is a better way to do it but..\n        if result >= 1:\n            result = 1\n        elif result <= -1:  # has not happened to me, but I leave it here.\n            result = -1\n        return acos(result)\n\n    def match_candidate(self, cand, **kwargs):\n        '''Match a given candidate against this MultistrokeGesture object. Will\n        test against all templates and report results as a list of four\n        items:\n\n            `index 0`\n                Best matching template's index (in self.templates)\n            `index 1`\n                Computed distance from the template to the candidate path\n            `index 2`\n                List of distances for all templates. The list index\n                corresponds to a :class:`UnistrokeTemplate` index in\n                self.templates.\n            `index 3`\n                Counter for the number of performed matching operations, ie\n                templates matched against the candidate\n        '''\n        best_d = float('infinity')\n        best_tpl = None\n        mos = 0\n        out = []\n\n        if (self.stroke_sens and len(self.strokes) != len(cand.strokes)):\n            return (best_tpl, best_d, out, mos)\n\n        skip_bounded = cand.skip_bounded\n        skip_invariant = cand.skip_invariant\n        get_distance = self.get_distance\n        ang_sim_threshold = self.angle_similarity_threshold()\n\n        for idx, tpl in enumerate(self.templates):\n            # Handle a theoretical case where a MultistrokeGesture is composed\n            # manually and the orientation_sensitive flag is True, and contains\n            # a UnistrokeTemplate that has orientation_sensitive=False (or vice\n            # versa). This would cause KeyError - requesing nonexistant vector.\n            if tpl.orientation_sens:\n                if skip_bounded:\n                    continue\n            elif skip_invariant:\n                continue\n\n            # Count as a match operation now, since the call to get_\n            # angle_similarity below will force vector calculation,\n            # even if it doesn't make it to get_distance\n            mos += 1\n\n            # Note: With this implementation, we always resample the candidate\n            # to *any* encountered UnistrokeTemplate numpoints here, the filter\n            # is only applied to MultistrokeGesture. See theoretical case\n            # above; should not matter normally.\n            n = kwargs.get('force_numpoints', tpl.numpoints)\n\n            # Skip if candidate/gesture angles are too far off\n            ang_sim = cand.get_angle_similarity(tpl, numpoints=n)\n            if ang_sim > ang_sim_threshold:\n                continue\n\n            # Get the distance between cand/tpl paths\n            d = get_distance(cand, tpl, numpoints=n)\n            out.append(d)\n\n            if d < best_d:\n                best_d = d\n                best_tpl = idx\n\n        return (best_tpl, best_d, out, mos)\n\n    def permute(self):\n        '''Generate all possible unistroke permutations from self.strokes and\n        save the resulting list of UnistrokeTemplate objects in self.templates.\n\n        Quote from http://faculty.washington.edu/wobbrock/pubs/gi-10.2.pdf ::\n\n            We use Heap Permute [16] (p. 179) to generate all stroke orders\n            in a multistroke gesture. Then, to generate stroke directions for\n            each order, we treat each component stroke as a dichotomous\n            [0,1] variable. There are 2^N combinations for N strokes, so we\n            convert the decimal values 0 to 2^N-1, inclusive, to binary\n            representations and regard each bit as indicating forward (0) or\n            reverse (1). This algorithm is often used to generate truth tables\n            in propositional logic.\n\n        See section 4.1: \"$N Algorithm\" of the linked paper for details.\n\n        .. Warning ::\n\n            Using heap permute for gestures with more than 3 strokes\n            can result in very large number of templates (a 9-stroke\n            gesture = 38 million templates). If you are dealing with\n            these types of gestures, you should manually compose\n            all the desired stroke orders.\n        '''\n        # Seed with index of each stroke\n        self._order = [i for i in xrange(0, len(self.strokes))]\n\n        # Prepare ._orders\n        self._orders = []\n        self._heap_permute(len(self.strokes))\n        del self._order\n\n        # Generate unistroke permutations\n        self.templates = [UnistrokeTemplate(\n            self.name,\n            points=permutation,\n            numpoints=self.numpoints,\n            orientation_sensitive=self.orientation_sens\n        ) for permutation in self._make_unistrokes()]\n        del self._orders\n\n    def _heap_permute(self, n):\n        # Heap Permute algorithm\n        self_order = self._order\n        if n == 1:\n            self._orders.append(self_order[:])\n        else:\n            i = 0\n            for i in xrange(0, n):\n                self._heap_permute(n - 1)\n                if n % 2 == 1:\n                    tmp = self_order[0]\n                    self_order[0] = self_order[n - 1]\n                    self_order[n - 1] = tmp\n                else:\n                    tmp = self_order[i]\n                    self_order[i] = self_order[n - 1]\n                    self_order[n - 1] = tmp\n\n    def _make_unistrokes(self):\n        # Create unistroke permutations from self.strokes\n        unistrokes = []\n        unistrokes_append = unistrokes.append\n        self_strokes = self.strokes\n        for r in self._orders:\n            b = 0\n            while b < pow(2, len(r)):  # use b's bits for directions\n                unistroke = []\n                unistroke_append = unistroke.append\n                for i in xrange(0, len(r)):\n                    pts = self_strokes[r[i]][:]\n                    if (b >> i) & 1 == 1:  # is b's bit at index i 1?\n                        pts.reverse()\n                    unistroke_append(None)\n                    unistroke[-1:] = pts\n\n                unistrokes_append(unistroke)\n                b += 1\n        return unistrokes\n\n\n# -----------------------------------------------------------------------------\n# UnistrokeTemplate\n# -----------------------------------------------------------------------------\n\nclass UnistrokeTemplate(object):\n    '''Represents a (uni)stroke path as a list of Vectors. Normally, this class\n    is instantiated by MultistrokeGesture and not by the programmer directly.\n    However, it is possible to manually compose UnistrokeTemplate objects.\n\n    :Arguments:\n        `name`\n            Identifies the name of the gesture. This is normally inherited from\n            the parent MultistrokeGesture object when a template is generated.\n        `points`\n            A list of points that represents a unistroke path. This is normally\n            one of the possible stroke order permutations from a\n            MultistrokeGesture.\n        `numpoints`\n            The number of points this template should (ideally) be resampled to\n            before the matching process. The default is 16, but you can use a\n            template-specific settings if that improves results.\n        `orientation_sensitive`\n            Determines if this template is orientation sensitive (True) or\n            fully rotation invariant (False). The default is True.\n\n    .. Note::\n        You will get an exception if you set a skip-flag and then attempt to\n        retrieve those vectorsa.\n    '''\n    def __init__(self, name, points=None, **kwargs):\n        self.name = name\n        self.numpoints = kwargs.get('numpoints', 16)\n        self.orientation_sens = kwargs.get('orientation_sensitive', True)\n\n        self.db = {}\n        self.points = []\n\n        if points is not None:\n            self.points = points\n\n    def add_point(self, p):\n        '''Add a point to the unistroke/path. This invalidates all previously\n        computed vectors.'''\n        self.points.append(p)\n        # All previously computed data is now void.\n        self.db = {}\n\n    # Used to lazily prepare the template\n    def _get_db_key(self, key, numpoints=None):\n        n = numpoints and numpoints or self.numpoints\n        if n not in self.db:\n            self.prepare(n)\n        return self.db[n][key]\n\n    def get_start_unit_vector(self, numpoints=None):\n        return self._get_db_key('startvector', numpoints)\n\n    def get_vector(self, numpoints=None):\n        return self._get_db_key('vector', numpoints)\n\n    def get_points(self, numpoints=None):\n        return self._get_db_key('points', numpoints)\n\n    def prepare(self, numpoints=None):\n        '''This function prepares the UnistrokeTemplate for matching given a\n        target number of points (for resample). 16 is optimal.'''\n\n        if not self.points:\n            raise MultistrokeError('prepare() called without self.points')\n\n        # How many points are we resampling to?\n        n = numpoints or self.numpoints\n        if not n or n < 2:\n            raise MultistrokeError('prepare() called with invalid numpoints')\n\n        p = resample(self.points, n)\n        radians = indicative_angle(p)\n        p = rotate_by(p, -radians)\n        p = scale_dim(p, SQUARESIZE, ONEDTHRESHOLD)\n\n        if self.orientation_sens:\n            p = rotate_by(p, +radians)  # restore\n\n        p = translate_to(p, ORIGIN)\n\n        # Now store it using the number of points in the resampled path as the\n        # dict key. On the next call to get_*, it will be returned instead of\n        # recomputed. Implicitly, you must reset self.db or call prepare() for\n        # all the keys once you manipulate self.points.\n        self.db[n] = {\n            # Compute STARTANGLEINDEX as n/8:\n            'startvector': start_unit_vector(p, (n / 8)),\n            'vector': vectorize(p, self.orientation_sens)\n        }\n\n\n# -----------------------------------------------------------------------------\n# Candidate\n# -----------------------------------------------------------------------------\n\nclass Candidate(object):\n    '''Represents a set of unistroke paths of user input, ie data to be matched\n    against a :class:`UnistrokeTemplate` object using the Protractor algorithm.\n    By default, data is precomputed to match both rotation bounded and fully\n    invariant :class:`UnistrokeTemplate` objects.\n\n    :Arguments:\n        `strokes`\n            See :data:`MultistrokeGesture.strokes` for format example. The\n            Candidate strokes are simply combined to a unistroke in the order\n            given. The idea is that this will match one of the unistroke\n            permutations in `MultistrokeGesture.templates`.\n        `numpoints`\n            The Candidate's default N; this is only for a fallback, it is not\n            normally used since n is driven by the UnistrokeTemplate we are\n            being compared to.\n        `skip_bounded`\n            If True, do not generate/store rotation bounded vectors\n        `skip_invariant`\n            If True, do not generate/store rotation invariant vectors\n\n    Note that you WILL get errors if you set a skip-flag and then attempt to\n    retrieve the data.'''\n    def __init__(self, strokes=None, numpoints=16, **kwargs):\n        self.skip_invariant = kwargs.get('skip_invariant', False)\n        self.skip_bounded = kwargs.get('skip_bounded', False)\n\n        self.numpoints = numpoints\n        self.db = {}\n        self.strokes = []\n\n        if not strokes is None:\n            self.strokes = strokes\n\n    def add_stroke(self, stroke):\n        '''Add a stroke to the candidate; this will invalidate all\n        previously computed vectors'''\n        self.points.append(stroke)\n        self.db = {}\n\n    # Used to lazily prepare the candidate\n    def _get_db_key(self, key, numpoints, orientation_sens):\n        n = numpoints and numpoints or self.numpoints\n        if n not in self.db:\n            self.prepare(n)\n\n        prefix = orientation_sens and 'bound_' or 'inv_'\n        return self.db[n][prefix + key]\n\n    def get_start_unit_vector(self, numpoints, orientation_sens):\n        '''(Internal use only) Get the start vector for this Candidate,\n        with the path resampled to `numpoints` points. This is the first\n        step in the matching process. It is compared to a\n        UnistrokeTemplate object's start vector to determine angle\n        similarity.'''\n        return self._get_db_key('startvector', numpoints, orientation_sens)\n\n    def get_protractor_vector(self, numpoints, orientation_sens):\n        '''(Internal use only) Return vector for comparing to a\n        UnistrokeTemplate with Protractor'''\n        return self._get_db_key('vector', numpoints, orientation_sens)\n\n    def get_angle_similarity(self, tpl, **kwargs):\n        '''(Internal use only) Compute the angle similarity between this\n        Candidate and a UnistrokeTemplate object. Returns a number that\n        represents the angle similarity (lower is more similar).'''\n        n = kwargs.get('numpoints', self.numpoints)\n\n        # angle_between_unit_vectors() inlined here for performance\n        v1x, v1y = self.get_start_unit_vector(n, tpl.orientation_sens)\n        v2x, v2y = tpl.get_start_unit_vector(n)\n\n        n = (v1x * v2x + v1y * v2y)\n        # FIXME: Domain error on float representation of 1.0 (exact match)\n        # (see comments in MultistrokeGesture.get_distance())\n        if n >= 1:\n            return 0.0\n        if n <= -1:\n            return pi\n        return acos(n)\n\n    def prepare(self, numpoints=None):\n        '''Prepare the Candidate vectors. self.strokes is combined to a single\n        unistroke (connected end-to-end), resampled to :attr:`numpoints` points,\n        and then the vectors are calculated and stored in self.db (for use by\n        `get_distance` and `get_angle_similarity`)'''\n        n = numpoints and numpoints or self.numpoints\n\n        # Inlined combine_strokes() for performance\n        points = [i for sub in self.strokes for i in sub]\n        points = resample(points, n)\n        radians = indicative_angle(points)\n        points = rotate_by(points, -radians)\n        points = scale_dim(points, SQUARESIZE, ONEDTHRESHOLD)\n\n        # Compute STARTANGLEINDEX as n / 8\n        angidx = n / 8\n        cand = {}\n\n        # full rotation invariance\n        if not self.skip_invariant:\n            inv_points = translate_to(points, ORIGIN)\n            cand['inv_startvector'] = start_unit_vector(inv_points, angidx)\n            cand['inv_vector'] = vectorize(inv_points, False)\n\n        # rotation bounded invariance\n        if not self.skip_bounded:\n            bound_points = rotate_by(points, +radians)  # restore\n            bound_points = translate_to(bound_points, ORIGIN)\n            cand['bound_startvector'] = start_unit_vector(bound_points, angidx)\n            cand['bound_vector'] = vectorize(bound_points, True)\n\n        self.db[n] = cand\n\n\n# -----------------------------------------------------------------------------\n# Helper functions from this point on. This is all directly related to the\n# recognition algorithm, and is almost 100% transcription from the JavaScript\n# -----------------------------------------------------------------------------\ndef resample(points, n):\n    # Resample a path to `n` points\n    if not len(points) or not n or n < 2:\n        raise MultistrokeError('resample() called with invalid arguments')\n\n    interval = path_length(points) / (n - 1)\n    D = 0.0\n    i = 1\n    newpoints = [points[0]]\n    workpoints = points[:]\n    newpoints_len = 1\n    workpoints_len = len(points)\n\n    new_append = newpoints.append\n    work_insert = workpoints.insert\n    while i < len(workpoints):\n        p1 = workpoints[i - 1]\n        p2 = workpoints[i]\n        d = distance(p1, p2)\n\n        if D + d >= interval:\n            qx = p1[0] + ((interval - D) / d) * (p2[0] - p1[0])\n            qy = p1[1] + ((interval - D) / d) * (p2[1] - p1[1])\n            q = Vector(qx, qy)\n            new_append(q)\n            work_insert(i, q)  # q is the next i\n            newpoints_len += 1\n            workpoints_len += 1\n            D = 0.0\n        else:\n            D += d\n\n        i += 1\n\n    # rounding error; insert the last point\n    if newpoints_len < n:\n        new_append(points[-1])\n\n    return newpoints\n\n\ndef indicative_angle(points):\n    cx, cy = centroid(points)\n    return atan2(cy - points[0][1], cx - points[0][0])\n\n\ndef rotate_by(points, radians):\n    # Rotate points around centroid\n    cx, cy = centroid(points)\n    cos = math_cos(radians)\n    sin = math_sin(radians)\n    newpoints = []\n    newpoints_append = newpoints.append\n\n    for i in xrange(0, len(points)):\n        qx = (points[i][0] - cx) * cos - (points[i][1] - cy) * sin + cx\n        qy = (points[i][0] - cx) * sin + (points[i][1] - cy) * cos + cy\n        newpoints_append(Vector(qx, qy))\n\n    return newpoints\n\n\ndef scale_dim(points, size, oneDratio):\n    bbox_x, bbox_y, bbox_w, bbox_h = bounding_box(points)\n\n    if bbox_h == 0 or bbox_w == 0:\n        raise MultistrokeError('scale_dim() called with invalid points')\n\n    # 1D or 2D gesture test\n    uniformly = min(bbox_w / bbox_h, bbox_h / bbox_w) <= oneDratio\n\n    if uniformly:\n        qx_size = size / max(bbox_w, bbox_h)\n        qy_size = size / max(bbox_w, bbox_h)\n    else:\n        qx_size = size / bbox_w\n        qy_size = size / bbox_h\n\n    newpoints = []\n    newpoints_append = newpoints.append\n\n    for p in points:\n        qx = p[0] * qx_size\n        qy = p[1] * qy_size\n        newpoints_append(Vector(qx, qy))\n\n    return newpoints\n\n\ndef translate_to(points, pt):\n    # Translate points around centroid\n    cx, cy = centroid(points)\n    ptx, pty = pt\n    newpoints = []\n    for p in points:\n        qx = p[0] + ptx - cx\n        qy = p[1] + pty - cy\n        newpoints.append(Vector(qx, qy))\n    return newpoints\n\n\ndef vectorize(points, use_bounded_rotation_invariance):\n    # Helper function for the Protractor algorithm\n    cos = 1.0\n    sin = 0.0\n\n    if use_bounded_rotation_invariance:\n        ang = atan2(points[0][1], points[0][0])\n        bo = (pi / 4.) * floor((ang + pi / 8.) / (pi / 4.))\n        cos = math_cos(bo - ang)\n        sin = math_sin(bo - ang)\n\n    sum = 0.0\n    vector = []\n    vector_len = 0\n    vector_append = vector.append\n\n    for px, py in points:\n        newx = px * cos - py * sin\n        newy = py * cos + px * sin\n        vector_append(newx)\n        vector_append(newy)\n        vector_len += 2\n        sum += newx ** 2 + newy ** 2\n\n    magnitude = sqrt(sum)\n    for i in xrange(0, vector_len):\n        vector[i] /= magnitude\n\n    return vector\n\n\ndef centroid(points):\n    x = 0.0\n    y = 0.0\n    points_len = len(points)\n\n    for i in xrange(0, points_len):\n        x += points[i][0]\n        y += points[i][1]\n\n    x /= points_len\n    y /= points_len\n\n    return Vector(x, y)\n\n\ndef bounding_box(points):\n    minx = float('infinity')\n    miny = float('infinity')\n    maxx = float('-infinity')\n    maxy = float('-infinity')\n\n    for px, py in points:\n        if px < minx:\n            minx = px\n        if px > maxx:\n            maxx = px\n        if py < miny:\n            miny = py\n        if py > maxy:\n            maxy = py\n\n    return (minx, miny, maxx - minx, maxy - miny)\n\n\ndef path_length(points):\n    d = 0.0\n    for i in xrange(1, len(points)):\n        d += distance(points[i - 1], points[i])\n    return d\n\n\ndef distance(p1, p2):\n    dx = p2[0] - p1[0]\n    dy = p2[1] - p1[1]\n    return sqrt(dx ** 2 + dy ** 2)\n\n\ndef start_unit_vector(points, index):\n    i = int(index)\n    vx, vy = points[i][0] - points[0][0], points[i][1] - points[0][1]\n    length = sqrt(vx ** 2 + vy ** 2)\n    return Vector(vx / length, vy / length)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/network/__init__.py",
    "content": "'''\nNetwork support\n===============\n\nKivy currently supports basic, asynchronous network requests.\nPlease refer to :class:`kivy.network.urlrequest.UrlRequest`.\n'''\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/network/urlrequest.py",
    "content": "'''\nUrl Request\n===========\n\n.. versionadded:: 1.0.8\n\nYou can use the :class:`UrlRequest` to make asynchronous requests on the\nweb and get the result when the request is completed. The spirit is the\nsame as the XHR object in Javascript.\n\nThe content is also decoded if the Content-Type is\napplication/json and the result automatically passed through json.loads.\n\n\nThe syntax to create a request::\n\n    from kivy.network.urlrequest import UrlRequest\n    req = UrlRequest(url, on_success, on_redirect, on_failure, on_error,\n                     on_progress, req_body, req_headers, chunk_size,\n                     timeout, method, decode, debug, file_path)\n\n\nOnly the first argument is mandatory: the rest are optional.\nBy default, a \"GET\" request will be sent. If the :attr:`UrlRequest.req_body` is\nnot None, a \"POST\" request will be sent. It's up to you to adjust\n:attr:`UrlRequest.req_headers` to suit your requirements and the response\nto the request will be accessible as the parameter called \"result\" on\nthe callback function of the on_success event.\n\n\nExample of fetching weather in Paris::\n\n    def got_weather(req, results):\n        for key, value in results['weather'][0].items():\n            print(key, ': ', value)\n\n    req = UrlRequest(\n        'http://api.openweathermap.org/data/2.5/weather?q=Paris,fr',\n        got_weather)\n\nExample of Posting data (adapted from httplib example)::\n\n    import urllib\n\n    def bug_posted(req, result):\n        print('Our bug is posted !')\n        print(result)\n\n    params = urllib.urlencode({'@number': 12524, '@type': 'issue',\n        '@action': 'show'})\n    headers = {'Content-type': 'application/x-www-form-urlencoded',\n              'Accept': 'text/plain'}\n    req = UrlRequest('bugs.python.org', on_success=bug_posted, req_body=params,\n            req_headers=headers)\n\nIf you want a synchronous request, you can call the wait() method.\n\n'''\n\nfrom collections import deque\nfrom threading import Thread\nfrom json import loads\nfrom time import sleep\nfrom kivy.compat import PY2\n\nif PY2:\n    from httplib import HTTPConnection\n    from urlparse import urlparse\nelse:\n    from http.client import HTTPConnection\n    from urllib.parse import urlparse\n\ntry:\n    HTTPSConnection = None\n    if PY2:\n        from httplib import HTTPSConnection\n    else:\n        from http.client import HTTPSConnection\nexcept ImportError:\n    # depending the platform, if openssl support wasn't compiled before python,\n    # this class is not available.\n    pass\n\nfrom kivy.clock import Clock\nfrom kivy.weakmethod import WeakMethod\nfrom kivy.logger import Logger\n\n\n# list to save UrlRequest and prevent GC on un-referenced objects\ng_requests = []\n\n\nclass UrlRequest(Thread):\n    '''A UrlRequest. See module documentation for usage.\n\n    .. versionchanged:: 1.5.1\n        Add `debug` parameter\n\n    .. versionchanged:: 1.0.10\n        Add `method` parameter\n\n    :Parameters:\n        `url`: str\n            Complete url string to call.\n        `on_success`: callback(request, result)\n            Callback function to call when the result has been fetched.\n        `on_redirect`: callback(request, result)\n            Callback function to call if the server returns a Redirect.\n        `on_failure`: callback(request, result)\n            Callback function to call if the server returns a Client or\n            Server Error.\n        `on_error`: callback(request, error)\n            Callback function to call if an error occurs.\n        `on_progress`: callback(request, current_size, total_size)\n            Callback function that will be called to report progression of the\n            download. `total_size` might be -1 if no Content-Length has been\n            reported in the http response.\n            This callback will be called after each `chunk_size` is read.\n        `req_body`: str, defaults to None\n            Data to sent in the request. If it's not None, a POST will be done\n            instead of a GET.\n        `req_headers`: dict, defaults to None\n            Custom headers to add to the request.\n        `chunk_size`: int, defaults to 8192\n            Size of each chunk to read, used only when `on_progress` callback\n            has been set. If you decrease it too much, a lot of on_progress\n            callbacks will be fired and will slow down your download. If you\n            want to have the maximum download speed, increase the chunk_size\n            or don't use ``on_progress``.\n        `timeout`: int, defaults to None\n            If set, blocking operations will timeout after this many seconds.\n        `method`: str, defaults to 'GET' (or 'POST' if ``body`` is specified)\n            The HTTP method to use.\n        `decode`: bool, defaults to True\n            If False, skip decoding of the response.\n        `debug`: bool, defaults to False\n            If True, it will use the Logger.debug to print information\n            about url access/progression/errors.\n        `file_path`: str, defaults to None\n            If set, the result of the UrlRequest will be written to this path\n            instead of in memory.\n\n    .. versionchanged:: 1.8.0\n\n        Parameter `decode` added.\n        Parameter `file_path` added.\n        Parameter `on_redirect` added.\n        Parameter `on_failure` added.\n\n    '''\n\n    def __init__(self, url, on_success=None, on_redirect=None,\n                 on_failure=None, on_error=None, on_progress=None,\n                 req_body=None, req_headers=None, chunk_size=8192,\n                 timeout=None, method=None, decode=True, debug=False,\n                 file_path=None):\n        super(UrlRequest, self).__init__()\n        self._queue = deque()\n        self._trigger_result = Clock.create_trigger(self._dispatch_result, 0)\n        self.daemon = True\n        self.on_success = WeakMethod(on_success) if on_success else None\n        self.on_redirect = WeakMethod(on_redirect) if on_redirect else None\n        self.on_failure = WeakMethod(on_failure) if on_failure else None\n        self.on_error = WeakMethod(on_error) if on_error else None\n        self.on_progress = WeakMethod(on_progress) if on_progress else None\n        self.decode = decode\n        self.file_path = file_path\n        self._debug = debug\n        self._result = None\n        self._error = None\n        self._is_finished = False\n        self._resp_status = None\n        self._resp_headers = None\n        self._resp_length = -1\n        self._chunk_size = chunk_size\n        self._timeout = timeout\n        self._method = method\n\n        #: Url of the request\n        self.url = url\n\n        #: Request body passed in __init__\n        self.req_body = req_body\n\n        #: Request headers passed in __init__\n        self.req_headers = req_headers\n\n        # save our request to prevent GC\n        g_requests.append(self)\n\n        self.start()\n\n    def run(self):\n        q = self._queue.appendleft\n        url = self.url\n        req_body = self.req_body\n        req_headers = self.req_headers\n\n        try:\n            result, resp = self._fetch_url(url, req_body, req_headers, q)\n            if self.decode:\n                result = self.decode_result(result, resp)\n        except Exception as e:\n            q(('error', None, e))\n        else:\n            q(('success', resp, result))\n\n        # using trigger can result in a missed on_success event\n        self._trigger_result()\n\n        # clean ourself when the queue is empty\n        while len(self._queue):\n            sleep(.1)\n            self._trigger_result()\n\n        # ok, authorize the GC to clean us.\n        if self in g_requests:\n            g_requests.remove(self)\n\n    def _fetch_url(self, url, body, headers, q):\n        # Parse and fetch the current url\n        trigger = self._trigger_result\n        chunk_size = self._chunk_size\n        report_progress = self.on_progress is not None\n        timeout = self._timeout\n        file_path = self.file_path\n\n        if self._debug:\n            Logger.debug('UrlRequest: {0} Fetch url <{1}>'.format(\n                id(self), url))\n            Logger.debug('UrlRequest: {0} - body: {1}'.format(\n                id(self), body))\n            Logger.debug('UrlRequest: {0} - headers: {1}'.format(\n                id(self), headers))\n\n        # parse url\n        parse = urlparse(url)\n\n        # translate scheme to connection class\n        cls = self.get_connection_for_scheme(parse.scheme)\n\n        # correctly determine host/port\n        port = None\n        host = parse.netloc.split(':')\n        if len(host) > 1:\n            port = int(host[1])\n        host = host[0]\n\n        # create connection instance\n        args = {}\n        if timeout is not None:\n            args['timeout'] = timeout\n        req = cls(host, port, **args)\n\n        # reconstruct path to pass on the request\n        path = parse.path\n        if parse.params:\n            path += ';' + parse.params\n        if parse.query:\n            path += '?' + parse.query\n        if parse.fragment:\n            path += '#' + parse.fragment\n\n        # send request\n        method = self._method\n        if method is None:\n            method = 'GET' if body is None else 'POST'\n        req.request(method, path, body, headers or {})\n\n        # read header\n        resp = req.getresponse()\n\n        # read content\n        if report_progress or file_path is not None:\n            try:\n                total_size = int(resp.getheader('content-length'))\n            except:\n                total_size = -1\n\n            # before starting the download, send a fake progress to permit the\n            # user to initialize his ui\n            if report_progress:\n                q(('progress', resp, (0, total_size)))\n\n            def get_chunks(fd=None):\n                bytes_so_far = 0\n                result = b''\n                while 1:\n                    chunk = resp.read(chunk_size)\n                    if not chunk:\n                        break\n\n                    if fd:\n                        fd.write(chunk)\n                    else:\n                        result += chunk\n\n                    bytes_so_far += len(chunk)\n                    # report progress to user\n                    if report_progress:\n                        q(('progress', resp, (bytes_so_far, total_size)))\n                        trigger()\n                return bytes_so_far, result\n\n            if file_path is not None:\n                with open(file_path, 'wb') as fd:\n                    bytes_so_far, result = get_chunks(fd)\n            else:\n                bytes_so_far, result = get_chunks()\n\n            # ensure that restults are dispatched for the last chunk,\n            # avoid trigger\n            if report_progress:\n                q(('progress', resp, (bytes_so_far, total_size)))\n                trigger()\n        else:\n            result = resp.read()\n            try:\n                if isinstance(result, bytes):\n                    result = result.decode('utf-8')\n            except UnicodeDecodeError:\n                # if it's an image? decoding would not work\n                pass\n        req.close()\n\n        # return everything\n        return result, resp\n\n    def get_connection_for_scheme(self, scheme):\n        '''Return the Connection class for a particular scheme.\n        This is an internal function that can be expanded to support custom\n        schemes.\n\n        Actual supported schemes: http, https.\n        '''\n        if scheme == 'http':\n            return HTTPConnection\n        elif scheme == 'https' and HTTPSConnection is not None:\n            return HTTPSConnection\n        else:\n            raise Exception('No class for scheme %s' % scheme)\n\n    def decode_result(self, result, resp):\n        '''Decode the result fetched from url according to his Content-Type.\n        Currently supports only application/json.\n        '''\n        # Entry to decode url from the content type.\n        # For example, if the content type is a json, it will be automatically\n        # decoded.\n        content_type = resp.getheader('Content-Type', None)\n        if content_type is not None:\n            ct = content_type.split(';')[0]\n            if ct == 'application/json':\n                try:\n                    return loads(result)\n                except:\n                    return result\n        return result\n\n    def _dispatch_result(self, dt):\n        while True:\n            # Read the result pushed on the queue, and dispatch to the client\n            try:\n                result, resp, data = self._queue.pop()\n            except IndexError:\n                return\n            if resp:\n                # XXX usage of dict can be dangerous if multiple headers\n                # are set even if it's invalid. But it look like it's ok\n                # ?  http://stackoverflow.com/questions/2454494/..\n                # ..urllib2-multiple-set-cookie-headers-in-response\n                self._resp_headers = dict(resp.getheaders())\n                self._resp_status = resp.status\n            if result == 'success':\n                status_class = resp.status // 100\n\n                if status_class in (1, 2):\n                    if self._debug:\n                        Logger.debug('UrlRequest: {0} Download finished with'\n                                     ' {1} datalen'.format(id(self),\n                                                           len(data)))\n                    self._is_finished = True\n                    self._result = data\n                    if self.on_success:\n                        func = self.on_success()\n                        if func:\n                            func(self, data)\n\n                elif status_class == 3:\n                    if self._debug:\n                        Logger.debug('UrlRequest: {} Download '\n                                     'redirected'.format(id(self)))\n                    self._is_finished = True\n                    self._result = data\n                    if self.on_redirect:\n                        func = self.on_redirect()\n                        if func:\n                            func(self, data)\n\n                elif status_class in (4, 5):\n                    if self._debug:\n                        Logger.debug('UrlRequest: {} Download failed with '\n                                     'http error {}'.format(id(self),\n                                                            resp.status))\n                    self._is_finished = True\n                    self._result = data\n                    if self.on_failure:\n                        func = self.on_failure()\n                        if func:\n                            func(self, data)\n\n            elif result == 'error':\n                if self._debug:\n                    Logger.debug('UrlRequest: {0} Download error '\n                                 '<{1}>'.format(id(self), data))\n                self._is_finished = True\n                self._error = data\n                if self.on_error:\n                    func = self.on_error()\n                    if func:\n                        func(self, data)\n\n            elif result == 'progress':\n                if self._debug:\n                    Logger.debug('UrlRequest: {0} Download progress '\n                                 '{1}'.format(id(self), data))\n                if self.on_progress:\n                    func = self.on_progress()\n                    if func:\n                        func(self, data[0], data[1])\n\n            else:\n                assert(0)\n\n    @property\n    def is_finished(self):\n        '''Return True if the request has finished, whether it's a\n        success or a failure.\n        '''\n        return self._is_finished\n\n    @property\n    def result(self):\n        '''Return the result of the request.\n        This value is not determined until the request is finished.\n        '''\n        return self._result\n\n    @property\n    def resp_headers(self):\n        '''If the request has been completed, return a dictionary containing\n        the headers of the response. Otherwise, it will return None.\n        '''\n        return self._resp_headers\n\n    @property\n    def resp_status(self):\n        '''Return the status code of the response if the request is complete,\n        otherwise return None.\n        '''\n        return self._resp_status\n\n    @property\n    def error(self):\n        '''Return the error of the request.\n        This value is not determined until the request is completed.\n        '''\n        return self._error\n\n    @property\n    def chunk_size(self):\n        '''Return the size of a chunk, used only in \"progress\" mode (when\n        on_progress callback is set.)\n        '''\n        return self._chunk_size\n\n    def wait(self, delay=0.5):\n        '''Wait for the request to finish (until :attr:`resp_status` is not\n        None)\n\n        .. note::\n            This method is intended to be used in the main thread, and the\n            callback will be dispatched from the same thread\n            from which you're calling.\n\n        .. versionadded:: 1.1.0\n        '''\n        while self.resp_status is None:\n            self._dispatch_result(delay)\n            sleep(delay)\n\n\nif __name__ == '__main__':\n\n    from pprint import pprint\n\n    def on_success(req, result):\n        pprint('Got the result:')\n        pprint(result)\n\n    def on_error(req, error):\n        pprint('Got an error:')\n        pprint(error)\n\n    req = UrlRequest('http://en.wikipedia.org/w/api.php?format'\n        '=json&action=query&titles=Kivy&prop=revisions&rvprop=content',\n        on_success, on_error)\n    while not req.is_finished:\n        sleep(1)\n        Clock.tick()\n\n    print('result =', req.result)\n    print('error =', req.error)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/parser.py",
    "content": "'''\nParser utilities\n================\n\nHelper functions used for CSS parsing.\n'''\n\n__all__ = ('parse_color', 'parse_int', 'parse_float',\n           'parse_string', 'parse_bool', 'parse_int2',\n           'parse_float4', 'parse_filename')\n\nimport re\nfrom kivy.logger import Logger\nfrom kivy.resources import resource_find\n\n\nclass ColorException(Exception):\n    pass\n\n\ndef parse_filename(filename):\n    '''Parse a filename and search for it using `resource_find()`.\n    If found, the resource path is returned, otherwise return the unmodified\n    filename (as specified by the caller).'''\n    filename = parse_string(filename)\n    result = resource_find(filename)\n    if result is None:\n        Logger.error('Resource: unable to find <%s>' % filename)\n    return result or filename\n\n\ndef color_error(text):\n    # show warning and return a sane value\n    Logger.warning(text)\n    return (0, 0, 0, 1)\n\n\ndef parse_color(text):\n    '''Parse a string to a kivy color. Supported formats:\n\n        * rgb(r, g, b)\n        * rgba(r, g, b, a)\n        * aaa\n        * rrggbb\n\n    For hexadecimal values, you case also use:\n\n        * #aaa\n        * #rrggbb\n    '''\n    value = [1, 1, 1, 1]\n    if text.startswith('rgb'):\n        res = re.match('rgba?\\((.*)\\)', text)\n        if res:\n            try:\n                # default r/g/b values to 1 if greater than 255 else x/255\n                value = [1 if int(x) > 255. else (int(x) / 255.)\n                         for x in re.split(',\\ ?', res.groups()[0])]\n                if len(value) < 3:\n                    #in case of invalid input like rgb()/rgb(r)/rgb(r, g)\n                    raise ValueError\n            except ValueError:\n                return color_error('ColorParser: Invalid color for %r' % text)\n            except AttributeError:\n                return color_error('ColorParser: Invalid color for %r' % text)\n        else:\n            return color_error('ColorParser: Invalid color for %r' % text)\n        if len(value) == 3:\n            value.append(1.)\n    elif len(text):\n        res = text\n        if text[0] == '#':\n            res = text[1:]\n        lres = len(res)\n        if lres == 3 or lres == 4:\n            res = ''.join([x + x for x in res])\n        elif lres != 6 and lres != 8:\n            #raise ColorException('Invalid color format for %r' % text)\n            return color_error(\n                'ColorParser: Invalid color format for %r' % text)\n        try:\n            value = [int(res[i:i + 2], 16) / 255.\n                     for i in range(0, len(res), 2)]\n        except ValueError:\n            return color_error('ColorParser: Invalid color for %r' % text)\n        if lres == 6:\n            value.append(1.)\n    return value\n\n\ndef parse_bool(text):\n    '''Parse a string to a boolean, ignoring case. \"true\"/\"1\" is True,\n    \"false\"/\"0\" is False. Anything else throws an exception.'''\n    if text.lower() in ('true', '1'):\n        return True\n    elif text.lower() in ('false', '0'):\n        return False\n    raise Exception('Invalid boolean: %s' % text)\n\n\ndef parse_string(text):\n    '''Parse a string to a string (removing single and double quotes)'''\n    if len(text) >= 2 and text[0] in ('\"', \"'\") and text[-1] in ('\"', \"'\"):\n        text = text[1:-1]\n    return text.strip()\n\n\ndef parse_int2(text):\n    '''Parse a string to a list of exactly 2 integers.\n\n        >>> print(parse_int2(\"12 54\"))\n        12, 54\n\n    '''\n    texts = [x for x in text.split(' ') if x.strip() != '']\n    value = list(map(parse_int, texts))\n    if len(value) < 1:\n        raise Exception('Invalid int2 format: %s' % text)\n    elif len(value) == 1:\n        return [value[0], value[0]]\n    elif len(value) > 2:\n        raise Exception('Too many values in %s: %s' % (text, str(value)))\n    return value\n\n\ndef parse_float4(text):\n    '''Parse a string to a list of exactly 4 floats.\n\n        >>> parse_float4('54 87. 35 0')\n        54, 87., 35, 0\n\n    '''\n    texts = [x for x in text.split(' ') if x.strip() != '']\n    value = list(map(parse_float, texts))\n    if len(value) < 1:\n        raise Exception('Invalid float4 format: %s' % text)\n    elif len(value) == 1:\n        return [value[0] for x in range(4)]\n    elif len(value) == 2:\n        return [value[0], value[1], value[0], value[1]]\n    elif len(value) == 3:\n        # ambigous case!\n        return [value[0], value[1], value[0], value[2]]\n    elif len(value) > 4:\n        raise Exception('Too many values in %s' % text)\n    return value\n\n\nparse_int = int\nparse_float = float\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/properties.pxd",
    "content": "from kivy._event cimport EventDispatcher, EventObservers\n\ncdef class PropertyStorage:\n    cdef object value\n    cdef EventObservers observers\n    cdef object numeric_fmt\n    cdef long bnum_min\n    cdef long bnum_max\n    cdef float bnum_f_min\n    cdef float bnum_f_max\n    cdef int bnum_use_min\n    cdef int bnum_use_max\n    cdef list options\n    cdef tuple properties\n    cdef int stop_event\n    cdef object getter\n    cdef object setter\n    cdef int alias_initial\n\ncdef class Property:\n    cdef str _name\n    cdef int allownone\n    cdef int force_dispatch\n    cdef object errorvalue\n    cdef object errorhandler\n    cdef int errorvalue_set\n    cdef public object defaultvalue\n    cdef init_storage(self, EventDispatcher obj, PropertyStorage storage)\n    cpdef link(self, EventDispatcher obj, str name)\n    cpdef link_deps(self, EventDispatcher obj, str name)\n    cpdef bind(self, EventDispatcher obj, observer)\n    cpdef fast_bind(self, EventDispatcher obj, observer, tuple largs=*, dict kwargs=*)\n    cpdef unbind(self, EventDispatcher obj, observer)\n    cpdef fast_unbind(self, EventDispatcher obj, observer, tuple largs=*, dict kwargs=*)\n    cpdef unbind_uid(self, EventDispatcher obj, object uid)\n    cdef compare_value(self, a, b)\n    cpdef set(self, EventDispatcher obj, value)\n    cpdef get(self, EventDispatcher obj)\n    cdef check(self, EventDispatcher obj, x)\n    cdef convert(self, EventDispatcher obj, x)\n    cpdef dispatch(self, EventDispatcher obj)\n\ncdef class NumericProperty(Property):\n    cdef float parse_str(self, EventDispatcher obj, value)\n    cdef float parse_list(self, EventDispatcher obj, value, ext)\n\ncdef class StringProperty(Property):\n    pass\n\ncdef class ListProperty(Property):\n    pass\n\ncdef class DictProperty(Property):\n    cdef public int rebind\n\ncdef class ObjectProperty(Property):\n    cdef object baseclass\n    cdef public int rebind\n\ncdef class BooleanProperty(Property):\n    pass\n\ncdef class BoundedNumericProperty(Property):\n    cdef int use_min\n    cdef int use_max\n    cdef long min\n    cdef long max\n    cdef float f_min\n    cdef float f_max\n\ncdef class OptionProperty(Property):\n    cdef list options\n\ncdef class ReferenceListProperty(Property):\n    cdef list properties\n    cpdef trigger_change(self, EventDispatcher obj, value)\n    cpdef setitem(self, EventDispatcher obj, key, value)\n\ncdef class AliasProperty(Property):\n    cdef object getter\n    cdef object setter\n    cdef list bind_objects\n    cdef int use_cache\n    cdef public int rebind\n    cpdef trigger_change(self, EventDispatcher obj, value)\n\ncdef class VariableListProperty(Property):\n    cdef public int length\n    cdef _convert_numeric(self, EventDispatcher obj, x)\n    cdef float parse_str(self, EventDispatcher obj, value)\n    cdef float parse_list(self, EventDispatcher obj, value, ext)\n\ncdef class ConfigParserProperty(Property):\n    cdef object config\n    cdef object section\n    cdef object key\n    cdef object val_type\n    cdef object verify\n    cdef object obj\n    cdef object last_value  # last string config value\n    cdef object config_name\n    cpdef _edit_setting(self, section, key, value)\n    cdef inline object _parse_str(self, object value)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/resources.py",
    "content": "'''\nResources management\n====================\n\nResource management can be a pain if you have multiple paths and projects. Kivy\noffers 2 functions for searching for specific resources across a list of\npaths.\n'''\n\n__all__ = ('resource_find', 'resource_add_path', 'resource_remove_path')\n\nfrom os.path import join, dirname, exists\nfrom kivy import kivy_data_dir\nfrom kivy.utils import platform\nfrom kivy.logger import Logger\nimport sys\nimport kivy\n\nresource_paths = ['.', dirname(sys.argv[0])]\nif platform == 'ios':\n    resource_paths += [join(dirname(sys.argv[0]), 'YourApp')]\nresource_paths += [dirname(kivy.__file__), join(kivy_data_dir, '..')]\n\n\ndef resource_find(filename):\n    '''Search for a resource in the list of paths.\n    Use resource_add_path to add a custom path to the search.\n    '''\n    if not filename:\n        return None\n    if filename[:8] == 'atlas://':\n        return filename\n    if exists(filename):\n        return filename\n    for path in reversed(resource_paths):\n        output = join(path, filename)\n        if exists(output):\n            return output\n    return None\n\n\ndef resource_add_path(path):\n    '''Add a custom path to search in.\n    '''\n    if path in resource_paths:\n        return\n    Logger.debug('Resource: add <%s> in path list' % path)\n    resource_paths.append(path)\n\n\ndef resource_remove_path(path):\n    '''Remove a search path.\n\n    .. versionadded:: 1.0.8\n    '''\n    if path not in resource_paths:\n        return\n    Logger.debug('Resource: remove <%s> from path list' % path)\n    resource_paths.remove(path)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/setupconfig.py",
    "content": "# Autogenerated file for Kivy configuration\nPY3 = 0\nCYTHON_MIN = '0.20'\nCYTHON_MAX = '0.23'\nCYTHON_BAD = ''\nUSE_RPI = 0\nUSE_OPENGL_ES2 = 1\nUSE_OPENGL_DEBUG = 0\nUSE_GLEW = 0\nUSE_SDL2 = 1\nUSE_IOS = 0\nUSE_MESAGL = 0\nUSE_X11 = 0\nUSE_GSTREAMER = 1\nUSE_AVFOUNDATION = 0\nUSE_OSX_FRAMEWORKS = 0\nDEBUG = False\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/storage/__init__.py",
    "content": "'''\nStorage\n=======\n\n.. versionadded:: 1.7.0\n\n.. warning::\n\n    This module is still experimental, and the API is subject to change in a\n    future version.\n\nUsage\n-----\n\nThe idea behind the Storage module is to be able to load/store any number of\nkey/value pairs via an indexed key. The default model is abstract so you\ncannot use it directly. We provide some implementations such as:\n\n- :class:`kivy.storage.dictstore.DictStore`: use a python dict as a store\n- :class:`kivy.storage.jsonstore.JsonStore`: use a JSON file as a store\n- :class:`kivy.storage.redistore.RedisStore`: use a `Redis <http://redis.io>`_\n  database with `redis-py <https://github.com/andymccurdy/redis-py>`_\n\n\n\nExamples\n--------\n\nFor example, let's use a JsonStore::\n\n    from kivy.storage.jsonstore import JsonStore\n\n    store = JsonStore('hello.json')\n\n    # put some values\n    store.put('tito', name='Mathieu', org='kivy')\n    store.put('tshirtman', name='Gabriel', age=27)\n\n    # using the same index key erases all previously added key/value pairs\n    store.put('tito', name='Mathieu', age=30)\n\n    # get a value using a index key and key\n    print('tito is', store.get('tito')['age'])\n\n    # or guess the key/entry for a part of the key\n    for item in store.find(name='Gabriel'):\n        print('tshirtmans index key is', item[0])\n        print('his key value pairs are', str(item[1]))\n\nBecause the data is persistant, you can check later to see if the key exists::\n\n    from kivy.storage.jsonstore import JsonStore\n\n    store = JsonStore('hello.json')\n    if store.exists('tito'):\n        print('tite exists:', store.get('tito'))\n        store.delete('tito')\n\n\nSynchronous / Asynchronous API\n------------------------------\n\nAll the standard methods (:meth:`~AbstractStore.get`,\n:meth:`~AbstractStore.put` , :meth:`~AbstractStore.exists`,\n:meth:`~AbstractStore.delete`, :meth:`~AbstractStore.find`) have an\nasynchronous version.\n\nFor example, the *get* method has a `callback` parameter. If set, the\n`callback` will be used to return the result to the user when available:\nthe request will be asynchronous. If the `callback` is None, then the\nrequest will be synchronous and the result will be returned directly.\n\n\nWithout callback (Synchronous API)::\n\n    entry = mystore.get('tito')\n    print('tito =', entry)\n\nWith callback (Asynchronous API)::\n\n    def my_callback(store, key, entry):\n        print('the key', key, 'have', entry)\n    mystore.get('plop', callback=my_callback)\n\n\nThe callback signature is (for almost all methods) `callback(store, key,\nresult)`::\n\n#. `store` is the `Store` instance currently used.\n#. `key` is the key to search for.\n#. `entry` is the result of the lookup for the `key`.\n\n\nSynchronous container type\n--------------------------\n\nThe storage API emulates the container type for the synchronous API::\n\n    store = JsonStore('hello.json')\n\n    # original: store.get('tito')\n    store['tito']\n\n    # original: store.put('tito', name='Mathieu')\n    store['tito'] = {'name': 'Mathieu'}\n\n    # original: store.delete('tito')\n    del store['tito']\n\n    # original: store.count()\n    len(store)\n\n    # original: store.exists('tito')\n    'tito' in store\n\n    # original: for key in store.keys()\n    for key in store:\n        pass\n\n'''\n\nfrom kivy.clock import Clock\nfrom kivy.event import EventDispatcher\nfrom functools import partial\n\n\nclass AbstractStore(EventDispatcher):\n    '''Abstract class used to implement a Store\n    '''\n\n    def __init__(self, **kwargs):\n        super(AbstractStore, self).__init__(**kwargs)\n        self.store_load()\n\n    def exists(self, key):\n        '''Check if a key exists in the store.\n        '''\n        return self.store_exists(key)\n\n    def async_exists(self, callback, key):\n        '''Asynchronous version of :meth:`exists`.\n\n        :Callback arguments:\n            `store`: :class:`AbstractStore` instance\n                Store instance\n            `key`: string\n                Name of the key to search for\n            `result`: boo\n                Result of the query, None if any error\n        '''\n        self._schedule(self.store_exists_async,\n                       key=key, callback=callback)\n\n    def get(self, key):\n        '''Get the key/value pairs stored at `key`. If the key is not found, a\n        `KeyError` exception will be thrown.\n        '''\n        return self.store_get(key)\n\n    def async_get(self, callback, key):\n        '''Asynchronous version of :meth:`get`.\n\n        :Callback arguments:\n            `store`: :class:`AbstractStore` instance\n                Store instance\n            `key`: string\n                Name of the key to search for\n            `result`: dict\n                Result of the query, None if any error\n        '''\n        self._schedule(self.store_get_async, key=key, callback=callback)\n\n    def put(self, key, **values):\n        '''Put new key/value pairs (given in *values*) into the storage. Any\n        existing key/value pairs will be removed.\n        '''\n        need_sync = self.store_put(key, values)\n        if need_sync:\n            self.store_sync()\n        return need_sync\n\n    def async_put(self, callback, key, **values):\n        '''Asynchronous version of :meth:`put`.\n\n        :Callback arguments:\n            `store`: :class:`AbstractStore` instance\n                Store instance\n            `key`: string\n                Name of the key to search for\n            `result`: bool\n                Indicate True if the storage has been updated, or False if\n                nothing has been done (no changes). None if any error.\n        '''\n        self._schedule(self.store_put_async,\n                       key=key, value=values, callback=callback)\n\n    def delete(self, key):\n        '''Delete a key from the storage. If the key is not found, a `KeyError`\n        exception will be thrown.'''\n        need_sync = self.store_delete(key)\n        if need_sync:\n            self.store_sync()\n        return need_sync\n\n    def async_delete(self, callback, key):\n        '''Asynchronous version of :meth:`delete`.\n\n        :Callback arguments:\n            `store`: :class:`AbstractStore` instance\n                Store instance\n            `key`: string\n                Name of the key to search for\n            `result`: bool\n                Indicate True if the storage has been updated, or False if\n                nothing has been done (no changes). None if any error.\n        '''\n        self._schedule(self.store_delete_async, key=key,\n                       callback=callback)\n\n    def find(self, **filters):\n        '''Return all the entries matching the filters. The entries are\n        returned through a generator as a list of (key, entry) pairs\n        where *entry* is a dict of key/value pairs ::\n\n            for key, entry in store.find(name='Mathieu'):\n                print('key:', key, ', entry:', entry)\n\n        Because it's a generator, you cannot directly use it as a list. You can\n        do::\n\n            # get all the (key, entry) availables\n            entries = list(store.find(name='Mathieu'))\n            # get only the entry from (key, entry)\n            entries = list((x[1] for x in store.find(name='Mathieu')))\n        '''\n        return self.store_find(filters)\n\n    def async_find(self, callback, **filters):\n        '''Asynchronous version of :meth:`find`.\n\n        The callback will be called for each entry in the result.\n\n        :Callback arguments:\n            `store`: :class:`AbstractStore` instance\n                Store instance\n            `key`: string\n                Name of the key to search for, or None if we reach the end of\n                the results\n            `result`: bool\n                Indicate True if the storage has been updated, or False if\n                nothing has been done (no changes). None if any error.\n        '''\n        self._schedule(self.store_find_async,\n                       callback=callback, filters=filters)\n\n    def keys(self):\n        '''Return a list of all the keys in the storage.\n        '''\n        return self.store_keys()\n\n    def async_keys(self, callback):\n        '''Asynchronously return all the keys in the storage.\n        '''\n        self._schedule(self.store_keys_async, callback=callback)\n\n    def count(self):\n        '''Return the number of entries in the storage.\n        '''\n        return self.store_count()\n\n    def async_count(self, callback):\n        '''Asynchronously return the number of entries in the storage.\n        '''\n        self._schedule(self.store_count_async, callback=callback)\n\n    def clear(self):\n        '''Wipe the whole storage.\n        '''\n        return self.store_clear()\n\n    def async_clear(self, callback):\n        '''Asynchronous version of :meth:`clear`.\n        '''\n        self._schedule(self.store_clear_async, callback=callback)\n\n    #\n    # Operators\n    #\n\n    def __setitem__(self, key, values):\n        if not isinstance(values, dict):\n            raise Exception('Only dict are accepted for the store[key] = dict')\n        self.put(key, **values)\n\n    def __getitem__(self, key):\n        return self.get(key)\n\n    def __delitem__(self, key):\n        return self.keys()\n\n    def __contains__(self, key):\n        return self.exists(key)\n\n    def __len__(self):\n        return self.count()\n\n    def __iter__(self):\n        for key in self.keys():\n            yield key\n\n    #\n    # Used for implementation\n    #\n\n    def store_load(self):\n        pass\n\n    def store_sync(self):\n        pass\n\n    def store_get(self, key):\n        raise NotImplemented()\n\n    def store_put(self, key, value):\n        raise NotImplemented()\n\n    def store_exists(self, key):\n        raise NotImplemented()\n\n    def store_delete(self, key):\n        raise NotImplemented()\n\n    def store_find(self, filters):\n        return []\n\n    def store_keys(self):\n        return []\n\n    def store_count(self):\n        return len(self.store_keys())\n\n    def store_clear(self):\n        for key in self.store_keys():\n            self.store_delete(key)\n\n    def store_get_async(self, key, callback):\n        try:\n            value = self.store_get(key)\n            callback(self, key, value)\n        except KeyError:\n            callback(self, key, None)\n\n    def store_put_async(self, key, value, callback):\n        try:\n            value = self.store_put(key, value)\n            callback(self, key, value)\n        except:\n            callback(self, key, None)\n\n    def store_exists_async(self, key, callback):\n        try:\n            value = self.store_exists(key)\n            callback(self, key, value)\n        except:\n            callback(self, key, None)\n\n    def store_delete_async(self, key, callback):\n        try:\n            value = self.store_delete(key)\n            callback(self, key, value)\n        except:\n            callback(self, key, None)\n\n    def store_find_async(self, filters, callback):\n        for key, entry in self.store_find(filters):\n            callback(self, filters, key, entry)\n        callback(self, filters, None, None)\n\n    def store_count_async(self, callback):\n        try:\n            value = self.store_count()\n            callback(self, value)\n        except:\n            callback(self, 0)\n\n    def store_keys_async(self, callback):\n        try:\n            keys = self.store_keys()\n            callback(self, keys)\n        except:\n            callback(self, [])\n\n    def store_clear_async(self, callback):\n        self.store_clear()\n        callback(self)\n\n    #\n    # Privates\n    #\n\n    def _schedule(self, cb, **kwargs):\n        # XXX not entirely sure about the best value (0 or -1).\n        Clock.schedule_once(partial(cb, **kwargs), 0)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/storage/dictstore.py",
    "content": "'''\nDictionary store\n=================\n\nUse a Python dictionary as a store.\n'''\n\n__all__ = ('DictStore', )\n\ntry:\n    import cPickle as pickle\nexcept ImportError:\n    import pickle\n\nfrom os.path import exists\nfrom kivy.compat import iteritems\nfrom kivy.storage import AbstractStore\n\n\nclass DictStore(AbstractStore):\n    '''Store implementation using a pickled `dict`.\n    See the :mod:`kivy.storage` module documentation for more information.\n    '''\n    def __init__(self, filename, data=None, **kwargs):\n        if isinstance(filename, dict):\n            # backward compatibility, first argument was a dict.\n            self.filename = None\n            self._data = filename\n        else:\n            self.filename = filename\n            self._data = data or {}\n        self._is_changed = True\n        super(DictStore, self).__init__(**kwargs)\n\n    def store_load(self):\n        if self.filename is None:\n            return\n        if not exists(self.filename):\n            return\n        with open(self.filename, 'rb') as fd:\n            data = fd.read()\n            if data:\n                self._data = pickle.loads(data)\n\n    def store_sync(self):\n        if self.filename is None:\n            return\n        if not self._is_changed:\n            return\n\n        with open(self.filename, 'wb') as fd:\n            pickle.dump(self._data, fd)\n\n        self._is_changed = False\n\n    def store_exists(self, key):\n        return key in self._data\n\n    def store_get(self, key):\n        return self._data[key]\n\n    def store_put(self, key, value):\n        self._data[key] = value\n        self._is_changed = True\n        return True\n\n    def store_delete(self, key):\n        del self._data[key]\n        self._is_changed = True\n        return True\n\n    def store_find(self, filters):\n        for key, values in iteritems(self._data):\n            found = True\n            for fkey, fvalue in iteritems(filters):\n                if fkey not in values:\n                    found = False\n                    break\n                if values[fkey] != fvalue:\n                    found = False\n                    break\n            if found:\n                yield key, values\n\n    def store_count(self):\n        return len(self._data)\n\n    def store_keys(self):\n        return self._data.keys()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/storage/jsonstore.py",
    "content": "'''\nJSON store\n==========\n\nCan be used to save/load key-value pairs from a json file.\n'''\n\n__all__ = ('JsonStore', )\n\n\nfrom os.path import exists\nfrom kivy.compat import iteritems\nfrom kivy.storage import AbstractStore\nfrom json import loads, dump\n\n\nclass JsonStore(AbstractStore):\n    '''Store implementation using a json file for storing the keys-value pairs.\n    See the :mod:`kivy.storage` module documentation for more information.\n    '''\n    def __init__(self, filename, **kwargs):\n        self.filename = filename\n        self._data = {}\n        self._is_changed = True\n        super(JsonStore, self).__init__(**kwargs)\n\n    def store_load(self):\n        if not exists(self.filename):\n            return\n        with open(self.filename) as fd:\n            data = fd.read()\n            if len(data) == 0:\n                return\n            self._data = loads(data)\n\n    def store_sync(self):\n        if self._is_changed is False:\n            return\n        with open(self.filename, 'w') as fd:\n            dump(self._data, fd)\n        self._is_changed = False\n\n    def store_exists(self, key):\n        return key in self._data\n\n    def store_get(self, key):\n        return self._data[key]\n\n    def store_put(self, key, value):\n        self._data[key] = value\n        self._is_changed = True\n        return True\n\n    def store_delete(self, key):\n        del self._data[key]\n        self._is_changed = True\n        return True\n\n    def store_find(self, filters):\n        for key, values in iteritems(self._data):\n            found = True\n            for fkey, fvalue in iteritems(filters):\n                if fkey not in values:\n                    found = False\n                    break\n                if values[fkey] != fvalue:\n                    found = False\n                    break\n            if found:\n                yield key, values\n\n    def store_count(self):\n        return len(self._data)\n\n    def store_keys(self):\n        return self._data.keys()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/storage/redisstore.py",
    "content": "'''\nRedis Store\n===========\n\nStore implementation using Redis. You must have redis-py installed.\n\nUsage example::\n\n    from kivy.storage.redisstore import RedisStore\n\n    params = dict(host='localhost', port=6379, db=14)\n    store = RedisStore(params)\n\nAll the key-value pairs will be stored with a prefix 'store' by default.\nYou can instanciate the storage with another prefix like this::\n\n\n    from kivy.storage.redisstore import RedisStore\n\n    params = dict(host='localhost', port=6379, db=14)\n    store = RedisStore(params, prefix='mystore2')\n\nThe params dictionary will be passed to the redis.StrictRedis class.\n\nSee `redis-py <https://github.com/andymccurdy/redis-py>`_.\n'''\n\n__all__ = ('RedisStore', )\n\nimport os\nfrom json import loads, dumps\nfrom kivy.properties import StringProperty\nfrom kivy.storage import AbstractStore\n\n# don't import redis during the documentation generation\nif 'KIVY_DOC' not in os.environ:\n    import redis\n\n\nclass RedisStore(AbstractStore):\n    '''Store implementation using a Redis database.\n    See the :mod:`kivy.storage` module documentation for more informations.\n    '''\n\n    prefix = StringProperty('store')\n\n    def __init__(self, redis_params, **kwargs):\n        self.redis_params = redis_params\n        self.r = None\n        super(RedisStore, self).__init__(**kwargs)\n\n    def store_load(self):\n        self.r = redis.StrictRedis(**self.redis_params)\n\n    def store_sync(self):\n        pass\n\n    def store_exists(self, key):\n        key = self.prefix + '.d.' + key\n        value = self.r.exists(key)\n        return value\n\n    def store_get(self, key):\n        key = self.prefix + '.d.' + key\n        if not self.r.exists(key):\n            raise KeyError(key)\n        result = self.r.hgetall(key)\n        for k in result.keys():\n            result[k] = loads(result[k])\n        return result\n\n    def store_put(self, key, values):\n        key = self.prefix + '.d.' + key\n        pipe = self.r.pipeline()\n        pipe.delete(key)\n        for k, v in values.iteritems():\n            pipe.hset(key, k, dumps(v))\n        pipe.execute()\n        return True\n\n    def store_delete(self, key):\n        key = self.prefix + '.d.' + key\n        if not self.r.exists(key):\n            raise KeyError(key)\n        return self.r.delete(key)\n\n    def store_keys(self):\n        l = len(self.prefix + '.d.')\n        return [x[l:] for x in self.r.keys(self.prefix + '.d.*')]\n\n    def store_find(self, filters):\n        fkeys = filters.keys()\n        fvalues = filters.values()\n        for key in self.store_keys():\n            skey = self.prefix + '.d.' + key\n            svalues = self.r.hmget(skey, fkeys)\n            if None in svalues:\n                continue\n            svalues = [loads(x) for x in svalues]\n            if fvalues != svalues:\n                continue\n            yield key, self.r.hgetall(skey)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/support.py",
    "content": "'''\nSupport\n=======\n\nActivate other frameworks/toolkits inside the kivy event loop.\n\n'''\n\n__all__ = ('install_gobject_iteration', 'install_twisted_reactor',\n           'uninstall_twisted_reactor', 'install_android')\n\n\ndef install_gobject_iteration():\n    '''Import and install gobject context iteration inside our event loop.\n    This is used as soon as gobject is used (like gstreamer).\n    '''\n\n    from kivy.clock import Clock\n\n    try:\n        from gi.repository import GObject as gobject\n    except ImportError:\n        import gobject\n\n    if hasattr(gobject, '_gobject_already_installed'):\n        # already installed, don't do it twice.\n        return\n\n    gobject._gobject_already_installed = True\n\n    # get gobject mainloop / context\n    loop = gobject.MainLoop()\n    gobject.threads_init()\n    context = loop.get_context()\n\n    # schedule the iteration each frame\n    def _gobject_iteration(*largs):\n        # XXX we need to loop over context here, otherwise, we might have a lag\n        loop = 0\n        while context.pending() and loop < 10:\n            context.iteration(False)\n            loop += 1\n    Clock.schedule_interval(_gobject_iteration, 0)\n\n\n# -----------------------------------------------------------------------------\n# Android support\n# -----------------------------------------------------------------------------\n\ng_android_redraw_count = 0\n\n\ndef _android_ask_redraw(*largs):\n    # after wakeup, we need to redraw more than once, otherwise we get a\n    # black screen\n    global g_android_redraw_count\n    from kivy.core.window import Window\n    Window.canvas.ask_update()\n    g_android_redraw_count -= 1\n    if g_android_redraw_count < 0:\n        return False\n\n\ndef install_android():\n    '''Install hooks for the android platform.\n\n    * Automatically sleep when the device is paused.\n    * Automatically kill the application when the return key is pressed.\n    '''\n    try:\n        import android\n    except ImportError:\n        print('Android lib is missing, cannot install android hooks')\n        return\n\n    from kivy.clock import Clock\n    from kivy.logger import Logger\n    import pygame\n\n    Logger.info('Support: Android install hooks')\n\n    # Init the library\n    android.init()\n    android.map_key(android.KEYCODE_MENU, pygame.K_MENU)\n    android.map_key(android.KEYCODE_BACK, pygame.K_ESCAPE)\n\n    # Check if android should be paused or not.\n    # If pause is requested, just leave the app.\n    def android_check_pause(*largs):\n        # do nothing until android asks for it.\n        if not android.check_pause():\n            return\n\n        from kivy.app import App\n        from kivy.base import stopTouchApp\n        from kivy.logger import Logger\n        from kivy.core.window import Window\n        global g_android_redraw_count\n\n        # try to get the current running application\n        Logger.info('Android: Must go into sleep mode, check the app')\n        app = App.get_running_app()\n\n        # no running application, stop our loop.\n        if app is None:\n            Logger.info('Android: No app running, stop everything.')\n            stopTouchApp()\n            return\n\n        # try to go to pause mode\n        if app.dispatch('on_pause'):\n            Logger.info('Android: App paused, now wait for resume.')\n\n            # app goes in pause mode, wait.\n            android.wait_for_resume()\n\n            # is it a stop or resume ?\n            if android.check_stop():\n                # app must stop\n                Logger.info('Android: Android wants to close our app.')\n                stopTouchApp()\n            else:\n                # app resuming now !\n                Logger.info('Android: Android has resumed, resume the app.')\n                app.dispatch('on_resume')\n                Window.canvas.ask_update()\n                g_android_redraw_count = 25  # 5 frames/seconds for 5 seconds\n                Clock.unschedule(_android_ask_redraw)\n                Clock.schedule_interval(_android_ask_redraw, 1 / 5)\n                Logger.info('Android: App resume completed.')\n\n        # app doesn't support pause mode, just stop it.\n        else:\n            Logger.info('Android: App doesn\\'t support pause mode, stop.')\n            stopTouchApp()\n\n    Clock.schedule_interval(android_check_pause, 0)\n\n\n_twisted_reactor_stopper = None\n_twisted_reactor_work = None\n\n\ndef install_twisted_reactor(**kwargs):\n    '''Installs a threaded twisted reactor, which will schedule one\n    reactor iteration before the next frame only when twisted needs\n    to do some work.\n\n    Any arguments or keyword arguments passed to this function will be\n    passed on the the threadedselect reactors interleave function. These\n    are the arguments one would usually pass to twisted's reactor.startRunning.\n\n    Unlike the default twisted reactor, the installed reactor will not handle\n    any signals unless you set the 'installSignalHandlers' keyword argument\n    to 1 explicitly. This is done to allow kivy to handle the signals as\n    usual unless you specifically want the twisted reactor to handle the\n    signals (e.g. SIGINT).\n\n    .. note::\n        Twisted is not included in iOS build by default. To use it on iOS,\n        put the twisted distribution (and zope.interface dependency) in your\n        application directory.\n    '''\n    import twisted\n\n    # prevent installing more than once\n    if hasattr(twisted, '_kivy_twisted_reactor_installed'):\n        return\n    twisted._kivy_twisted_reactor_installed = True\n\n    # don't let twisted handle signals, unless specifically requested\n    kwargs.setdefault('installSignalHandlers', 0)\n\n    # install threaded-select reactor, to use with own event loop\n    from twisted.internet import _threadedselect\n    _threadedselect.install()\n\n    # now we can import twisted reactor as usual\n    from twisted.internet import reactor\n    from twisted.internet.error import ReactorNotRunning\n\n    from collections import deque\n    from kivy.base import EventLoop\n    from kivy.logger import Logger\n    from kivy.clock import Clock\n\n    # will hold callbacks to twisted callbacks\n    q = deque()\n\n    # twisted will call the wake function when it needs to do work\n    def reactor_wake(twisted_loop_next):\n        '''Wakeup the twisted reactor to start processing the task queue\n        '''\n\n        Logger.trace(\"Support: twisted wakeup call to schedule task\")\n        q.append(twisted_loop_next)\n\n    # called every frame, to process the reactors work in main thread\n    def reactor_work(*args):\n        '''Process the twisted reactor task queue\n        '''\n        Logger.trace(\"Support: processing twisted task queue\")\n        while len(q):\n            q.popleft()()\n    global _twisted_reactor_work\n    _twisted_reactor_work = reactor_work\n\n    # start the reactor, by telling twisted how to wake, and process\n    def reactor_start(*args):\n        '''Start the twisted reactor main loop\n        '''\n        Logger.info(\"Support: Starting twisted reactor\")\n        reactor.interleave(reactor_wake, **kwargs)\n        Clock.schedule_interval(reactor_work, 0)\n\n    # make sure twisted reactor is shutdown if eventloop exists\n    def reactor_stop(*args):\n        '''Shutdown the twisted reactor main loop\n        '''\n        if reactor.threadpool:\n            Logger.info(\"Support: Stooping twisted threads\")\n            reactor.threadpool.stop()\n        Logger.info(\"Support: Shutting down twisted reactor\")\n        reactor._mainLoopShutdown()\n        try:\n            reactor.stop()\n        except ReactorNotRunning:\n            pass\n\n        import sys\n        sys.modules.pop('twisted.internet.reactor', None)\n\n    global _twisted_reactor_stopper\n    _twisted_reactor_stopper = reactor_stop\n\n    # start and stop the reactor along with kivy EventLoop\n    Clock.schedule_once(reactor_start, 0)\n    EventLoop.bind(on_stop=reactor_stop)\n\n\ndef uninstall_twisted_reactor():\n    '''Uninstalls the Kivy's threaded Twisted Reactor. No more Twisted\n    tasks will run after this got called. Use this to clean the\n    `twisted.internet.reactor` .\n\n    .. versionadded:: 1.9.0\n    '''\n\n    import twisted\n\n    # prevent uninstalling more than once\n    if not hasattr(twisted, '_kivy_twisted_reactor_installed'):\n        return\n\n    from kivy.base import EventLoop\n\n    global _twisted_reactor_stopper\n    _twisted_reactor_stopper()\n    EventLoop.unbind(on_stop=_twisted_reactor_stopper)\n\n    del twisted._kivy_twisted_reactor_installed\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/tools/__init__.py",
    "content": ""
  },
  {
    "path": "tickeys/kivy_32/kivy/tools/benchmark.py",
    "content": "'''\nBenchmark\n=========\n\n'''\n\nfrom __future__ import print_function\n\nbenchmark_version = '1'\n\nimport os\nimport sys\nimport json\nimport kivy\nimport gc\nfrom time import clock, time, ctime\nfrom random import randint\n\nfrom kivy.uix.label import Label\nfrom kivy.uix.button import Button\nfrom kivy.uix.widget import Widget\nfrom kivy.graphics import RenderContext\nfrom kivy.input.motionevent import MotionEvent\nfrom kivy.cache import Cache\nfrom kivy.clock import Clock\nfrom kivy.compat import PY2\n\nif not PY2:\n    xrange = range\n\nclockfn = time\nif sys.platform == 'win32':\n    clockfn = clock\n\n\nclass FakeMotionEvent(MotionEvent):\n    pass\n\n\nclass bench_widget_creation:\n    '''Widget: creation (10000 Widget)'''\n\n    def run(self):\n        o = []\n        for x in range(10000):\n            o.append(Widget())\n\n\nclass bench_widget_creation_with_root:\n    '''Widget: creation (10000 Widget + 1 root)'''\n\n    def run(self):\n        o = Widget()\n        for x in range(10000):\n            o.add_widget(Widget())\n\n\nclass bench_widget_draw:\n    '''Widget: empty drawing (10000 Widget + 1 root)'''\n\n    def __init__(self):\n        self.ctx = RenderContext()\n        self.root = root = Widget()\n        for x in range(10000):\n            root.add_widget(Widget())\n        self.ctx.add(self.root.canvas)\n\n    def run(self):\n        self.ctx.draw()\n\n\nclass bench_widget_dispatch:\n    '''Widget: event dispatch (1000 on_update in 10*1000 Widget)'''\n\n    def __init__(self):\n        root = Widget()\n        for x in range(10):\n            parent = Widget()\n            for y in range(1000):\n                parent.add_widget(Widget())\n            root.add_widget(parent)\n        self.root = root\n\n    def run(self):\n        touch = FakeMotionEvent('fake', 1, [])\n        self.root.dispatch('on_touch_down', touch)\n        self.root.dispatch('on_touch_move', touch)\n        self.root.dispatch('on_touch_up', touch)\n\n\nclass bench_label_creation:\n    '''Core: label creation (10000 * 10 a-z)'''\n\n    def __init__(self):\n        labels = []\n        for x in range(10000):\n            label = [chr(randint(ord('a'), ord('z'))) for x in range(10)]\n            labels.append(''.join(label))\n        self.labels = labels\n\n    def run(self):\n        o = []\n        for x in self.labels:\n            o.append(Label(text=x))\n\n\nclass bench_button_creation:\n    '''Core: button creation (10000 * 10 a-z)'''\n\n    def __init__(self):\n        labels = []\n        for x in xrange(10000):\n            button = map(lambda x: chr(randint(ord('a'), ord('z'))), xrange(10))\n            labels.append(''.join(button))\n        self.labels = labels\n\n    def run(self):\n        o = []\n        for x in self.labels:\n            o.append(Button(text=x))\n\n\nclass bench_label_creation_with_tick:\n    '''Core: label creation (10000 * 10 a-z), with Clock.tick'''\n\n    def __init__(self):\n        labels = []\n        for x in range(10000):\n            label = [chr(randint(ord('a'), ord('z'))) for x in range(10)]\n            labels.append(''.join(label))\n        self.labels = labels\n\n    def run(self):\n        o = []\n        for x in self.labels:\n            o.append(Label(text=x))\n        # tick for texture creation\n        Clock.tick()\n\n\nclass bench_button_creation_with_tick:\n    '''Core: button creation (10000 * 10 a-z), with Clock.tick'''\n\n    def __init__(self):\n        labels = []\n        for x in xrange(10000):\n            button = map(lambda x: chr(randint(ord('a'), ord('z'))), xrange(10))\n            labels.append(''.join(button))\n        self.labels = labels\n\n    def run(self):\n        o = []\n        for x in self.labels:\n            o.append(Button(text=x))\n        # tick for texture creation\n        Clock.tick()\n\n\nif __name__ == '__main__':\n\n    report = []\n    report_newline = True\n\n    def log(s, newline=True):\n        global report_newline\n        if not report_newline:\n            report[-1] = '%s %s' % (report[-1], s)\n        else:\n            report.append(s)\n        if newline:\n            print(s)\n            report_newline = True\n        else:\n            print(s, end=' ')\n            report_newline = False\n        sys.stdout.flush()\n\n    clock_total = 0\n    benchs = list(globals().keys())\n    benchs.sort()\n    benchs = [globals()[x] for x in benchs if x.startswith('bench_')]\n\n    log('')\n    log('=' * 70)\n    log('Kivy Benchmark v%s' % benchmark_version)\n    log('=' * 70)\n    log('')\n    log('System informations')\n    log('-------------------')\n\n    log('OS platform     : %s' % sys.platform)\n    log('Python EXE      : %s' % sys.executable)\n    log('Python Version  : %s' % sys.version)\n    log('Python API      : %s' % sys.api_version)\n    log('Kivy Version    : %s' % kivy.__version__)\n    log('Install path    : %s' % os.path.dirname(kivy.__file__))\n    log('Install date    : %s' % ctime(os.path.getctime(kivy.__file__)))\n\n    log('')\n    log('OpenGL informations')\n    log('-------------------')\n\n    from kivy.core.gl import glGetString, GL_VENDOR, GL_RENDERER, GL_VERSION\n    log('GL Vendor: %s' % glGetString(GL_VENDOR))\n    log('GL Renderer: %s' % glGetString(GL_RENDERER))\n    log('GL Version: %s' % glGetString(GL_VERSION))\n    log('')\n\n    log('Benchmark')\n    log('---------')\n\n    for x in benchs:\n        # clean cache to prevent weird case\n        for cat in Cache._categories:\n            Cache.remove(cat)\n\n        # force gc before next test\n        gc.collect()\n\n        log('%2d/%-2d %-60s' % (benchs.index(x) + 1,\n            len(benchs), x.__doc__), False)\n        try:\n            sys.stderr.write('.')\n            test = x()\n        except Exception as e:\n            log('failed %s' % str(e))\n            import traceback\n            traceback.print_exc()\n            continue\n\n        clock_start = clockfn()\n\n        try:\n            sys.stderr.write('.')\n            test.run()\n            clock_end = clockfn() - clock_start\n            log('%.6f' % clock_end)\n        except Exception as e:\n            log('failed %s' % str(e))\n            continue\n\n        clock_total += clock_end\n\n    log('')\n    log('Result: %.6f' % clock_total)\n    log('')\n\ntry:\n    reply = input(\n        'Do you want to send benchmark to gist.github.com (Y/n) : ')\nexcept EOFError:\n    sys.exit(0)\n\nif reply.lower().strip() in ('', 'y'):\n    print('Please wait while sending the benchmark...')\n\n    try:\n        import requests\n    except ImportError:\n        print(\"`requests` module not found, no benchmark posted.\")\n        sys.exit(1)\n\n    payload = {\n        'public': True, 'files': {\n            'benchmark.txt': {\n                'content': '\\n'.join(report)}}}\n\n    r = requests.post('https://api.github.com/gists', data=json.dumps(payload))\n\n    print()\n    print()\n    print('REPORT posted at {0}'.format(r.json['html_url']))\n    print()\n    print()\nelse:\n    print('No benchmark posted.')\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/tools/extensions/__init__.py",
    "content": ""
  },
  {
    "path": "tickeys/kivy_32/kivy/tools/extensions/make-kivyext.py",
    "content": "#!/usr/bin/env python\n\"\"\"\n    make-kivyext\n    ~~~~~~~~~~~~~\n\n    Little helper script that helps creating new Kivy extensions.\n    To use it, just run it::\n\n        python make-kivyext.py\n\n    :copyright: (c) 2011: Adjusted by the Kivy Authors,\n                    2010: Courtesy of Armin Ronacher\n                          (Originally developed for flask.pocoo.org)\n    :license: BSD, see LICENSE for more details.\n\"\"\"\n\nimport re\nimport os\nimport sys\nimport getpass\nfrom datetime import datetime\nfrom urllib.parse import quote\n\n\n_sep_re = re.compile(r'[\\s.,;_-]+')\n\n\nFILE_HEADER_TEMPLATE = '''\\\n# -*- coding: utf-8 -*-\n\"\"\"\n    %(module)s\n    %(moduledecor)s\n\n    Please describe your extension here...\n\n    :copyright: (c) %(year)s by %(name)s.\n\"\"\"\n'''\n\nSETUP_PY_TEMPLATE = '''\\\n\"\"\"\n%(name)s\n%(namedecor)s\n\nTo create a Kivy *.kex extension file for this extension, run this file like\nso::\n\n    python setup.py create_package\n\nThat will turn your current Kivy extension development folder into a *.kex Kivy\nextension file that you can just drop in one of the extensions/ directories\nsupported by Kivy.\n\"\"\"\nfrom distutils.core import setup\nfrom distutils.cmd import Command\n\nimport %(extname)s\nlong_desc = %(extname)s.__doc__\n\n\nimport os\nfrom os.path import join\nfrom shutil import copy\nfrom subprocess import call\nimport sys\n\n\nclass PackageBuild(Command):\n    description = 'Create Extension Package'\n    user_options = []\n\n    def run(self):\n        # Call this file and make a distributable .zip file that has our desired\n        # folder structure\n        call([sys.executable, 'setup.py', 'install', '--root', 'output/',\n            '--install-lib', '/', '--install-platlib', '/', '--install-data',\n            '/%(extname)s/data', 'bdist', '--formats=zip'])\n        files = os.listdir('dist')\n        if not os.path.isdir('kexfiles'):\n            os.mkdir('kexfiles')\n        for file in files:\n            # Simply copy & replace...\n            copy(join('dist', file), join('kexfiles', file[:-3] + \"kex\"))\n        print('The extension files are now available in kexfiles/')\n\n    def initialize_options(self):\n        pass\n\n    def finalize_options(self):\n        pass\n\n\ncmdclass = {'create_package': PackageBuild}\n\n\nsetup(\n    name='%(name)s',\n    version='0.1',\n    url='<enter URL here>',\n    license='<specify license here>',\n    author='%(author)s',\n    author_email='%(email)s',\n    description='<enter short description here>',\n    long_description=long_desc,\n    packages=['%(extname)s'],\n    cmdclass=cmdclass,\n    classifiers=[\n        # Add your own classifiers here\n        'Development Status :: 4 - Beta',\n        'Intended Audience :: Developers',\n        'Operating System :: OS Independent',\n        'Programming Language :: Python',\n        'Topic :: Software Development :: Libraries :: Python Modules'\n    ]\n)\n'''\n\n\ndef prompt(name, default=None):\n    prompt = name + (default and ' [%s]' % default or '')\n    prompt += name.endswith('?') and ' ' or ': '\n    while True:\n        rv = input(prompt)\n        if rv:\n            return rv\n        if default is not None:\n            return default\n\n\ndef prompt_bool(name, default=False):\n    while True:\n        rv = prompt(name + '?', default and 'Y' or 'N')\n        if not rv:\n            return default\n        if rv.lower() in ('y', 'yes', '1', 'on', 'true', 't'):\n            return True\n        elif rv.lower() in ('n', 'no', '0', 'off', 'false', 'f'):\n            return False\n\n\ndef prompt_choices(name, choices):\n    while True:\n        rv = prompt(name + '? - (%s)' % ', '.join(choices), choices[0])\n        rv = rv.lower()\n        if not rv:\n            return choices[0]\n        if rv in choices:\n            if rv == 'none':\n                return None\n            else:\n                return rv\n\n\ndef guess_package(name):\n    \"\"\"Guess the package name\"\"\"\n    words = [x.lower() for x in _sep_re.split(name)]\n    return '_'.join(words) or None\n\n\nclass Extension(object):\n\n    def __init__(self, name, shortname, author, email, output_folder):\n        self.name = name\n        self.shortname = shortname\n        self.author = author\n        self.email = email\n        self.output_folder = output_folder\n\n    def make_folder(self):\n        root = os.path.join(self.output_folder, self.shortname)\n        os.makedirs(root)\n        os.mkdir(os.path.join(root, 'data'))\n\n    def create_files(self):\n        decor = '~' * len(self.shortname)\n        with open(os.path.join(self.output_folder, self.shortname,\n                               '__init__.py'), 'w') as f:\n            f.write(FILE_HEADER_TEMPLATE % dict(\n                module=self.shortname,\n                moduledecor=decor,\n                year=datetime.utcnow().year,\n                name=self.author,\n            ))\n        with open(os.path.join(self.output_folder, 'setup.py'), 'w') as f:\n            f.write(SETUP_PY_TEMPLATE % dict(\n                name=self.name,\n                namedecor='~' * len(self.name),\n                urlname=quote(self.name),\n                author=self.author,\n                extname=self.shortname,\n                email=self.email,\n            ))\n\n\ndef main():\n    if len(sys.argv) not in (1, 2):\n        print('usage: make-kivyext.py [output-folder]')\n        return\n    msg = 'Welcome to the Kivy Extension Creator Wizard'\n    print(msg)\n    print('~' * len(msg))\n\n    name = prompt('Extension Name (human readable)')\n    shortname = prompt('Extension Name (for filesystem)', guess_package(name))\n    author = prompt('Author', default=getpass.getuser())\n    email = prompt('EMail', default='')\n\n    output_folder = len(sys.argv) == 2 and sys.argv[1] or shortname + '-dev'\n    while 1:\n        folder = prompt('Output folder', default=output_folder)\n        if os.path.isfile(folder):\n            print('Error: output folder is a file')\n        elif os.path.isdir(folder) and os.listdir(folder):\n            if prompt_bool('Warning: output folder is not empty. Continue'):\n                break\n        else:\n            break\n    output_folder = os.path.abspath(folder)\n\n    ext = Extension(name, shortname, author, email, output_folder)\n    ext.make_folder()\n    ext.create_files()\n    msg = '''\n    Congratulations!\n    Your initial Kivy extension code skeleton has been created in:\n        %(output_folder)s\n    The next step is to look at the files that have been created and to\n    populate the placeholder values. Obviously you will also need to add the\n    actual extension code.\n    ''' % dict(output_folder=output_folder)\n    print(msg)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/tools/generate-icons.py",
    "content": "#!/usr/bin/env python\n'''\nIcon generator\n==============\n\nThis tool will help you to generate all the icons wanted for Google Play Store,\nApp Store, Amazon store.\n'''\n\nimport sys\nfrom PIL import Image\nfrom os.path import exists, join, realpath, basename, dirname\nfrom os import makedirs\nfrom argparse import ArgumentParser\n\n\nclass Converter(object):\n\n    converters = {\n        'appstore': {\n            'directory_name': 'ios',\n            'sizes': [\n                ('App store high resolution', '{}-appstore-1024.png', 1024),\n                ('App store normal resolution', '{}-appstore-512.png', 512),\n                # iOS 7\n                ('iPhone (iOS 7)', '{}-60.png', 120),\n                ('iPhone @2 (iOS 7)', '{}-60@2x.png', 120),\n                ('iPad (iOS 7)', '{}-76.png', 76),\n                ('iPad @2 (iOS 7)', '{}-60@2x.png', 152),\n                # iOS 6.1 and earlier\n                ('iPhone (iOS >= 6.1)', '{}-57.png', 57),\n                ('iPhone @2 (iOS >= 6.1)', '{}-57@2x.png', 114),\n                ('iPad (iOS >= 6.1)', '{}-72.png', 72),\n                ('iPad @2 (iOS >= 6.1)', '{}-72@2x.png', 114),\n                # iTunes artwork (ad-hoc)\n                ('iTunes Artwork (ad-hoc)', 'iTunesArtwork', 512),\n                ('iTunes Artwork @2 (ad-hoc)', 'iTunesArtwork@2x', 1024),\n            ]},\n        'playstore': {\n            'directory_name': 'android',\n            'sizes': [\n                ('Google Play icon', '{}-googleplay-512.png', 512),\n                ('Launcher icon MDPI', '{}-48.png', 48),\n                ('Launcher icon HDPI', '{}-72.png', 72),\n                ('Launcher icon XHDPI', '{}-96.png', 96),\n                ('Launcher icon XXHDPI', '{}-144.png', 48),\n                ('Launcher icon XXXHDPI', '{}-192.png', 192),\n            ]},\n        'amazonstore': {\n            'directory_name': 'amazon',\n            'sizes': [\n                ('Small icon', '{}-114.png', 114),\n                ('Large icon', '{}-512.png', 512),\n            ]}}\n\n    def run(self):\n        parser = ArgumentParser(\n                description='Generate icons for various stores')\n        parser.add_argument('--dir', type=str, default=None,\n                help=('Output directory to generate all the icons,'\n                      'defaults to the directory of the source icon'))\n        parser.add_argument('--force', type=bool, default=False,\n                help=('Generate all icons even if the source is not perfect.'))\n        parser.add_argument('icon', type=str,\n                help='Base icon (must be 1024x1024 or 512x512)')\n\n        args = parser.parse_args()\n        if not exists(args.icon):\n            print('Error: No such icon file')\n            sys.exit(1)\n\n        # ensure the destination directory will be set\n        if args.dir is None:\n            args.dir = dirname(args.icon)\n\n        # read the source image, and do some quality checks\n        base_fn = basename(args.icon).rsplit('.', 1)[0]\n        source = Image.open(args.icon)\n        self.ensure_quality(source, args.force)\n\n        for directory_name, sizeinfo in self.iterate():\n            description, pattern_fn, size = sizeinfo\n            print('Generate {}: {}x{}'.format(description, size, size))\n            dest_dir = realpath(join(args.dir, directory_name))\n            if not exists(dest_dir):\n                makedirs(dest_dir)\n            icon_fn = join(dest_dir, pattern_fn.format('Icon'))\n            self.convert_to(source, icon_fn, size)\n\n    def convert_to(self, source, icon_fn, size):\n        dest = source.resize((size, size))\n        dest.save(icon_fn, 'png')\n\n    def ensure_quality(self, image, force=False):\n        messages = []\n        w, h = image.size\n        if w != h:\n            messages.append('Width and height should be the same')\n        if w not in (512, 1024):\n            messages.append(\n                'Source image is recommended to be 1024 (512 minimum)')\n        if not messages:\n            return\n\n        print('Quality check failed')\n        for message in messages:\n            print('- {}'.format(message))\n        if not force:\n            sys.exit(1)\n\n    def iterate(self):\n        for store, infos in Converter.converters.items():\n            for size in infos['sizes']:\n                yield infos['directory_name'], size\n\n\nif __name__ == '__main__':\n    Converter().run()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/tools/highlight/__init__.py",
    "content": ""
  },
  {
    "path": "tickeys/kivy_32/kivy/tools/highlight/kivy-mode.el",
    "content": ";;; kivy-mode.el --- Emacs major mode for editing Kivy files\n;;\n;; Author: Dean Serenevy <dean@serenevy.net>\n;; Version: 0.1.0\n;;\n;; This document borrowed heavily from yaml-mode.el by Yoshiki Kurihara and\n;; Marshall Vandegrift.\n;;\n;; This file is not part of Emacs\n\n\n;; This file is free software; you can redistribute it and/or modify it\n;; under the terms of the GNU General Public License as published by the\n;; Free Software Foundation; version 3.\n\n;; This file is distributed in the hope that it will be useful, but WITHOUT\n;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\n;; more details.\n\n;; You should have received a copy of the GNU General Public License along\n;; with GNU Emacs; see the file COPYING. If not, write to the Free Software\n;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,\n;; USA.\n\n;;; Installation:\n\n;; To install, just drop this file into a directory in your `load-path' and\n;; (optionally) byte-compile it. To automatically handle files ending in\n;; '.kv', add something like:\n;;\n;;    (require 'kivy-mode)\n;;    (add-to-list 'auto-mode-alist '(\"\\\\.kv$\" . kivy-mode))\n;;\n;; to your .emacs file.\n;;\n;; Unlike python-mode, this mode follows the Emacs convention of not\n;; binding the ENTER key to `newline-and-indent'. To get this behavior, add\n;; the key definition to `kivy-mode-hook':\n;;\n;;    (add-hook 'kivy-mode-hook\n;;     '(lambda ()\n;;        (define-key kivy-mode-map \"\\C-m\" 'newline-and-indent)))\n\n\n;; User definable variables\n\n(defgroup kivy nil\n  \"Support for the kivy user interface definition format\"\n  :group 'languages\n  :prefix \"kivy-\")\n\n(defcustom kivy-mode-hook nil\n  \"*Hook run by `kivy-mode'.\"\n  :type 'hook\n  :group 'kivy)\n\n(defcustom kivy-indent-offset 4\n  \"*Amount of offset per level of indentation.\"\n  :type 'integer\n  :group 'kivy)\n\n(defcustom kivy-backspace-function 'backward-delete-char-untabify\n  \"*Function called by `kivy-electric-backspace' when deleting backwards.\"\n  :type 'function\n  :group 'kivy)\n\n(defface kivy-tab-face\n  '((((class color)) (:background \"red\" :foreground \"red\" :bold t))\n    (t (:reverse-video t)))\n  \"Face to use for highlighting tabs in kivy files.\"\n  :group 'faces\n  :group 'kivy)\n\n(defcustom kivy-imenu-generic-expression\n  '((nil  \"^\\\\([<>a-zA-Z_-]+\\\\):\"          1))\n  \"The imenu regex to parse an outline of the kivy file.\"\n  :type 'string\n  :group 'kivy)\n\n\n;; Constants\n\n(defconst kivy-mode-version \"0.1.0\" \"Version of `kivy-mode.'\")\n\n(defconst kivy-blank-line-re \"^ *$\"\n  \"Regexp matching a line containing only (valid) whitespace.\")\n\n(defconst kivy-comment-re \"\\\\(?:^\\\\|\\\\s-+\\\\)\\\\(#.*\\\\)\"\n  \"Regexp matching a line containing a kivy comment or delimiter.\")\n\n(defconst kivy-directive-re \"^\\\\(?:#:\\\\)\\\\(\\\\w+ +.*\\\\)\"\n  \"Regexp matching a line contatining a kivy directive.\")\n\n(defconst kivy-tag-re \"^ *id: *\\\\([^ \\n]+\\\\)$\"\n  \"Rexexp matching a kivy tag.\")\n\n(defconst kivy-bare-scalar-re\n  \"\\\\(?:[^-:,#!\\n{\\\\[ ]\\\\|[^#!\\n{\\\\[ ]\\\\S-\\\\)[^#\\n]*?\"\n  \"Rexexp matching a kivy bare scalar.\")\n\n(defconst kivy-hash-key-re\n  (concat \"^ *\"\n          \"\\\\(\" kivy-bare-scalar-re \"\\\\) *:\"\n          \"\\\\(?: +\\\\|$\\\\)\")\n  \"Regexp matching a single kivy hash key.\")\n\n(defconst kivy-nested-map-re\n  (concat \".*: *$\")\n  \"Regexp matching a line beginning a kivy nested structure.\")\n\n(defconst kivy-constant-scalars-re\n  (concat \"\\\\(?:^\\\\|\\\\(?::\\\\|-\\\\|,\\\\|{\\\\|\\\\[\\\\) +\\\\) *\"\n          (regexp-opt\n           '(\"True\" \"False\" \"None\") t)\n          \" *$\")\n  \"Regexp matching certain scalar constants in scalar context\")\n\n\n\n;; Mode setup\n\n(defvar kivy-mode-map ()\n  \"Keymap used in `kivy-mode' buffers.\")\n(if kivy-mode-map\n    nil\n  (setq kivy-mode-map (make-sparse-keymap))\n  (define-key kivy-mode-map [backspace] 'kivy-electric-backspace)\n  (define-key kivy-mode-map \"\\C-c<\" 'kivy-indent-shift-left)\n  (define-key kivy-mode-map \"\\C-c>\" 'kivy-indent-shift-right)\n  )\n\n(defvar kivy-mode-syntax-table nil\n  \"Syntax table in use in kivy-mode buffers.\")\n(if kivy-mode-syntax-table\n    nil\n  (setq kivy-mode-syntax-table (make-syntax-table))\n  (modify-syntax-entry ?\\' \"\\\"\" kivy-mode-syntax-table)\n  (modify-syntax-entry ?\\\" \"\\\"\" kivy-mode-syntax-table)\n  (modify-syntax-entry ?# \"<\" kivy-mode-syntax-table)\n  (modify-syntax-entry ?\\n \">\" kivy-mode-syntax-table)\n  (modify-syntax-entry ?\\\\ \"\\\\\" kivy-mode-syntax-table)\n  (modify-syntax-entry ?- \"_\" kivy-mode-syntax-table)\n  (modify-syntax-entry ?_ \"w\" kivy-mode-syntax-table)\n  )\n\n\n;;;###autoload\n(add-to-list 'auto-mode-alist '(\"\\\\.kv$\" . kivy-mode))\n\n\n;;;###autoload\n(define-derived-mode kivy-mode fundamental-mode \"kivy\"\n  \"Simple mode to edit kivy.\n\n\\\\{kivy-mode-map}\"\n  (set (make-local-variable 'comment-start) \"# \")\n  (set (make-local-variable 'comment-start-skip) \"#+ *\")\n  (set (make-local-variable 'indent-line-function) 'kivy-indent-line)\n  (set (make-local-variable 'font-lock-defaults)\n       '(kivy-font-lock-keywords\n         nil nil nil nil\n         (font-lock-syntactic-keywords))))\n\n\n;; Font-lock support\n\n(defvar kivy-font-lock-keywords\n  (list\n   (cons kivy-comment-re '(1 font-lock-comment-face))\n   (cons kivy-constant-scalars-re '(1 font-lock-constant-face))\n   (cons kivy-tag-re '(1 font-lock-function-name-face))\n   (cons kivy-hash-key-re '(1 font-lock-variable-name-face t))\n   (cons kivy-directive-re '(1 font-lock-builtin-face))\n   '(\"^[\\t]+\" 0 'kivy-tab-face t))\n  \"Additional expressions to highlight in kivy mode.\")\n\n(defvar kivy-font-lock-syntactic-keywords\n  (list '())\n  \"Additional syntax features to highlight in kivy mode.\")\n\n\n;; Indentation and electric keys\n\n(defun kivy-compute-indentation ()\n  \"Calculate the maximum sensible indentation for the current line.\"\n  (save-excursion\n    (beginning-of-line)\n    (forward-line -1)\n    (while (and (looking-at kivy-blank-line-re)\n                (> (point) (point-min)))\n      (forward-line -1))\n    (+ (current-indentation)\n       (if (looking-at kivy-nested-map-re) kivy-indent-offset 0)\n       )))\n\n(defun kivy-indent-line ()\n  \"Indent the current line.\nThe first time this command is used, the line will be indented to the\nmaximum sensible indentation.  Each immediately subsequent usage will\nback-dent the line by `kivy-indent-offset' spaces.  On reaching column\n0, it will cycle back to the maximum sensible indentation.\"\n  (interactive \"*\")\n  (let ((ci (current-indentation))\n        (cc (current-column))\n        (need (kivy-compute-indentation)))\n    (save-excursion\n      (beginning-of-line)\n      (delete-horizontal-space)\n      (if (and (equal last-command this-command) (/= ci 0))\n          (indent-to (* (/ (- ci 1) kivy-indent-offset) kivy-indent-offset))\n        (indent-to need)))\n    (if (< (current-column) (current-indentation))\n        (forward-to-indentation 0))))\n\n(defun kivy-electric-backspace (arg)\n  \"Delete characters or back-dent the current line.\nIf invoked following only whitespace on a line, will back-dent to the\nimmediately previous multiple of `kivy-indent-offset' spaces.\"\n  (interactive \"*p\")\n  (if (or (/= (current-indentation) (current-column)) (bolp))\n      (funcall kivy-backspace-function arg)\n    (let ((ci (current-column)))\n      (beginning-of-line)\n      (delete-horizontal-space)\n      (indent-to (* (/ (- ci (* arg kivy-indent-offset))\n                       kivy-indent-offset)\n                    kivy-indent-offset)))))\n\n\n(defun kivy-set-imenu-generic-expression ()\n  (make-local-variable 'imenu-generic-expression)\n  (make-local-variable 'imenu-create-index-function)\n  (setq imenu-create-index-function 'imenu-default-create-index-function)\n  (setq imenu-generic-expression kivy-imenu-generic-expression))\n\n(add-hook 'kivy-mode-hook 'kivy-set-imenu-generic-expression)\n(add-hook 'kivy-mode-hook\n          '(lambda ()\n             (setq indent-tabs-mode 'nil)))\n\n\n(defun kivy-mode-version ()\n  \"Diplay version of `kivy-mode'.\"\n  (interactive)\n  (message \"kivy-mode %s\" kivy-mode-version)\n  kivy-mode-version)\n\n(defun kivy-indent-shift-left (start end &optional count)\n  \"Shift lines contained in region START END by COUNT columns to the left.\nCOUNT defaults to `kivy-indent-offset'.  If region isn't\nactive, the current line is shifted.  The shifted region includes\nthe lines in which START and END lie.  An error is signaled if\nany lines in the region are indented less than COUNT columns.\"\n  (interactive\n   (if mark-active\n       (list (region-beginning) (region-end) current-prefix-arg)\n     (list (line-beginning-position) (line-end-position) current-prefix-arg)))\n  (if count\n      (setq count (prefix-numeric-value count))\n    (setq count kivy-indent-offset))\n  (when (> count 0)\n    (let ((deactivate-mark nil))\n      (save-excursion\n        (goto-char start)\n        (while (< (point) end)\n          (if (and (< (current-indentation) count)\n                   (not (looking-at \"[ \\t]*$\")))\n              (error \"Can't shift all lines enough\"))\n          (forward-line))\n        (indent-rigidly start end (- count))))))\n\n(defun kivy-indent-shift-right (start end &optional count)\n  \"Shift lines contained in region START END by COUNT columns to the left.\nCOUNT defaults to `kivy-indent-offset'.  If region isn't\nactive, the current line is shifted.  The shifted region includes\nthe lines in which START and END lie.\"\n  (interactive\n   (if mark-active\n       (list (region-beginning) (region-end) current-prefix-arg)\n     (list (line-beginning-position) (line-end-position) current-prefix-arg)))\n  (let ((deactivate-mark nil))\n    (if count\n        (setq count (prefix-numeric-value count))\n      (setq count kivy-indent-offset))\n    (indent-rigidly start end count)))\n\n(provide 'kivy-mode)\n\n;;; kivy-mode.el ends here\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/tools/highlight/kivy.vim",
    "content": "\" Vim syntax file\n\" Language:\tKivy\n\" Maintainer:\tGeorge Sebastian <11george.s@gmail.com>\n\" Last Change:\t2011 May 1\n\n\" For version 5.x: Clear all syntax items.\n\" For version 6.x: Quit when a syntax file was already loaded.\nif version < 600\n  syntax clear\nelseif exists(\"b:current_syntax\")\n  finish\nendif\n\nsyn match kivyPreProc       /#:.*/\nsyn match kivyComment       /#.*/\nsyn match kivyRule          /<\\I\\i*\\(,\\s*\\I\\i*\\)*>:/\nsyn match kivyAttribute     /\\<\\I\\i*\\>/ nextgroup=kivyValue\n\nsyn include @pyth $VIMRUNTIME/syntax/python.vim\nsyn region kivyValue start=\":\" end=/$/  contains=@pyth skipwhite\n\nsyn region kivyAttribute matchgroup=kivyIdent start=/[\\a_][\\a\\d_]*:/ end=/$/ contains=@pyth skipwhite\n\nif version >= 508 || !exists(\"did_python_syn_inits\")\n  if version <= 508\n    let did_python_syn_inits = 1\n    command -nargs=+ HiLink hi link <args>\n  else\n    command -nargs=+ HiLink hi def link <args>\n  endif\n\n    HiLink kivyPreproc      PreProc\n    HiLink kivyComment      Comment\n    HiLink kivyRule         Function\n    HiLink kivyIdent        Statement\n    HiLink kivyAttribute    Label\n  delcommand HiLink\nendif\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/tools/packaging/README.txt",
    "content": "The files in the win32 and osx subdirectories are \nsource and resource files that are used in the respective \nportable packaged versions of kivy for each OS.  Here, they\nare under version controll.  \n\nsetup.py copies these files into the portable distribution \npackage that is created when you launch \n'setup.py build_portable'\n\n\nFor example the win32 dir has the READMEand bat file which \nsets up the ENV variables and launches the python interpreter.\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/tools/packaging/__init__.py",
    "content": ""
  },
  {
    "path": "tickeys/kivy_32/kivy/tools/packaging/factory.py",
    "content": "from __future__ import print_function\n\n__all__ = ('FactoryBuild', )\n\nfrom distutils.cmd import Command\nimport fnmatch\nimport os\nimport kivy\nimport types\n\nignore_list = (\n    'kivy.lib',\n    'kivy.input.providers',\n    'kivy.input.postproc',\n    'kivy.modules',\n    'kivy.tools',\n    'kivy.parser',\n    'kivy.tests',\n)\n\n\nclass FactoryBuild(Command):\n    description = 'Build the factory relation file (for factory.py)'\n    user_options = []\n\n    def initialize_options(self):\n        pass\n\n    def finalize_options(self):\n        pass\n\n    def run(self):\n        print('--------------------------------------------')\n        print('Building factory relation file')\n        print('--------------------------------------------')\n\n        root_dir = os.path.dirname(kivy.__file__)\n        filename = os.path.join(root_dir, 'factory_registers.py')\n        with open(filename, 'w') as fd:\n            fd.close()\n\n        # ensure we don't have any thing like doc running\n        symbols = []\n        for root, dirnames, filenames in os.walk(root_dir):\n            if not root.startswith(root_dir):\n                raise Exception('Directory should start with the kivy'\n                                'directory')\n            root = 'kivy' + root[len(root_dir):].replace(os.path.sep, '.')\n            for filename in fnmatch.filter(filenames, '*.[ps][yo]'):\n                module = '%s.%s' % (root, filename[:-3])\n\n                # check ignore list first\n                ignore = False\n                for ignore in ignore_list:\n                    if module.startswith(ignore):\n                        ignore = True\n                        break\n                if ignore is True:\n                    #print('<<< ignored (ignore list)')\n                    continue\n\n                # special case, core providers\n                if root.startswith('kivy.core.'):\n                    if not root.endswith('__init__.py'):\n                        #print('<<< ignored (not a __init__.py)')\n                        continue\n\n                print('>>>', module, '::', end=' ')\n\n                try:\n                    m = __import__(name=module, fromlist='.')\n                except Exception as e:\n                    print()\n                    print('ERROR:', e)\n                    continue\n                if not hasattr(m, '__all__'):\n                    print()\n                    continue\n                for symbol in getattr(m, '__all__'):\n                    if symbol.startswith('_'):\n                        continue\n                    attr = getattr(m, symbol)\n                    if type(attr) not in (type, type):\n                        continue\n                    symbols.append((symbol, module))\n                    print(symbol, end=' ')\n                print()\n\n        print()\n        print('--------------------------------------------')\n        print('Found %d symbols, generating file' % len(symbols))\n        print('--------------------------------------------')\n\n        filename = os.path.join(root_dir, 'factory_registers.py')\n        with open(filename, 'w') as fd:\n            fd.write('# Auto-generated file by setup.py build_factory\\n')\n            fd.write('\\n')\n            fd.write('from kivy.factory import Factory\\n')\n            fd.write('\\n')\n            fd.write('r = Factory.register\\n')\n            for x in symbols:\n                fd.write(\"r('%s', module='%s')\\n\" % x)\n\n        print('File written at', filename)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/tools/packaging/osx/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>English</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>Kivy</string>\n\t<key>CFBundleDocumentTypes</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>CFBundleTypeExtensions</key>\n\t\t\t<array>\n\t\t\t\t<string>*</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeOSTypes</key>\n\t\t\t<array>\n\t\t\t\t<string>****</string>\n\t\t\t\t<string>fold</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeRole</key>\n\t\t\t<string>Viewer</string>\n\t\t</dict>\n\t</array>\n\t<key>CFBundleExecutable</key>\n\t<string>Kivy</string>\n\t<key>CFBundleGetInfoString</key>\n\t<string>Kivy {{__VERSION__}} Copyright {{__YEAR__}} Kivy Maintainers</string>\n\t<key>CFBundleIconFile</key>\n\t<string>appIcon.icns</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>org.kivy</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>Kivy</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>{{__VERSION__}}</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>LSEnvironment</key>\n\t<dict/>\n\t<key>LSHasLocalizedDisplayName</key>\n\t<false/>\n\t<key>LSMinimumSystemVersion</key>\n\t<string>10.6</string>\n\t<key>LSUIElement</key>\n\t<false/>\n\t<key>NSAppleScriptEnabled</key>\n\t<false/>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Kivy {{__VERSION__}} Copyright {{__YEAR__}} Kivy Maintainers</string>\n\t<key>NSMainNibFile</key>\n\t<string>MainMenu</string>\n\t<key>NSPrincipalClass</key>\n\t<string>NSApplication</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/tools/packaging/osx/InfoPlist.strings",
    "content": "CFBundleName = \"Kivy\";\nCFBundleShortVersionString = \"{{__VERSION__}}\";\nCFBundleGetInfoString = \"Kivy version {{__VERSION__}} Copyright {{__YEAR__}} Kivy Maintainers\";\nNSHumanReadableCopyright = \"Copyright {{__YEAR__}} Kivy Maintainers.\";\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/tools/packaging/osx/kivy.sh",
    "content": "#!/bin/bash\nSCRIPT_PATH=\"${BASH_SOURCE[0]}\";\nif([ -h \"${SCRIPT_PATH}\" ]) then\n  while([ -h \"${SCRIPT_PATH}\" ]) do SCRIPT_PATH=`readlink \"${SCRIPT_PATH}\"`; done\nfi\nSCRIPT_PATH=`dirname ${SCRIPT_PATH}`\n\nexport PYTHONPATH=${SCRIPT_PATH}/kivy:${SCRIPT_PATH}/lib/sitepackages:$PYTHONPATH\nexport DYLD_FALLBACK_LIBRARY_PATH=${SCRIPT_PATH}/lib:$DYLD_FALLBACK_LIBRARY_PATH\nexport LD_PRELOAD_PATH=${SCRIPT_PATH}/lib:$LD_PRELOAD_PATH\nexport GST_PLUGIN_PATH=${SCRIPT_PATH}/lib/gst-plugins:$GST_PLUGIN_PATH\nexport GST_PLUGIN_SCANNER=${SCRIPT_PATH}/lib/bin/gst-plugin-scanner\nexport GST_REGISTRY_FORK=\"no\"\n\nexec $(python -c \"import os, sys; print(os.path.normpath(sys.prefix))\")/bin/python2.7 \"$@\"\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/tools/packaging/pyinstaller_hooks/__init__.py",
    "content": "from os.path import dirname, join\nfrom functools import partial\n\ncurdir = dirname(__file__)\n\n\ndef install_hooks(sym, hookspath=None):\n\n    _hookspath = [curdir]\n    if hookspath is not None:\n        _hookspath += hookspath\n\n    sym['rthooks']['kivy'] = [join(curdir, 'rt-hook-kivy.py')]\n    sym['Analysis'] = partial(sym['Analysis'], hookspath=_hookspath)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/tools/packaging/pyinstaller_hooks/hook-kivy.py",
    "content": "'''\nKivy hook for PyInstaller\n=========================\n\nKivy load itself in a complete dynamic way. PyImported don't see most of the\nimport cause of the Factory and Core.\nIn addition, the data and missing module are not copied automatically.\n\nWith this hook, everything needed for running kivy is correctly copied.\n\nCheck kivy documentation about how to use these hook for packaging application.\n'''\n\nimport kivy\nfrom kivy.factory import Factory\n\n\ndef get_modules():\n    return [x.get('module', None) for x in Factory.classes.values()]\n\n\ndatas = [\n    (kivy.kivy_data_dir, 'kivy_install'),\n    (kivy.kivy_modules_dir, 'kivy_install'),\n    (kivy.kivy_exts_dir, 'kivy_install'),\n]\n\n# extensions\n_kivy_modules = [\n\n    # sdl2\n\n    # pygame\n    'pygame.event',\n    'pygame.video',\n    'pygame.image',\n    'pygame.display',\n    'pygame',\n\n    # external modules\n    'kivy.cache',\n    'kivy.atlas',\n    'kivy.network',\n    'kivy.network.urlrequest',\n    'kivy.lib.osc',\n    'kivy.lib.osc.OSC',\n    'kivy.lib.osc.oscAPI',\n    'kivy.lib.mtdev',\n    'kivy.lib.sdl2',\n    'kivy.factory_registers',\n    'kivy.input.recorder',\n    'kivy.input.providers',\n    'kivy.input.providers.tuio',\n    'kivy.input.providers.mouse',\n    'kivy.input.providers.wm_common',\n    'kivy.input.providers.wm_touch',\n    'kivy.input.providers.wm_pen',\n    'kivy.input.providers.hidinput',\n    'kivy.input.providers.linuxwacom',\n    'kivy.input.providers.mactouch',\n    'kivy.input.providers.mouse',\n    'kivy.input.providers.mtdev',\n\n    # compiled modules\n    'kivy.event',\n    'kivy.graphics.buffer',\n    'kivy.graphics.c_opengl_debug',\n    'kivy.graphics.compiler',\n    'kivy.graphics.context_instructions',\n    'kivy.graphics.fbo',\n    'kivy.graphics.instructions',\n    'kivy.graphics.opengl',\n    'kivy.graphics.opengl_utils',\n    'kivy.graphics.shader',\n    'kivy.graphics.stenctil_instructions',\n    'kivy.graphics.texture',\n    'kivy.graphics.transformation',\n    'kivy.graphics.vbo',\n    'kivy.graphics.vertex',\n    'kivy.graphics.vertex_instructions',\n    'kivy.properties',\n\n    # core\n    'kivy.core.audio.audio_gstplayer',\n    'kivy.core.audio.audio_pygst',\n    'kivy.core.audio.audio_sdl',\n    'kivy.core.audio.audio_pygame',\n    'kivy.core.camera.camera_avfoundation',\n    'kivy.core.camera.camera_pygst',\n    'kivy.core.camera.camera_opencv',\n    'kivy.core.camera.camera_videocapture',\n    'kivy.core.clipboard.clipboard_sdl2',\n    'kivy.core.clipboard.clipboard_android',\n    'kivy.core.clipboard.clipboard_pygame',\n    'kivy.core.clipboard.clipboard_dummy',\n    'kivy.core.image.img_imageio',\n    'kivy.core.image.img_tex',\n    'kivy.core.image.img_dds',\n    'kivy.core.image.img_sdl2',\n    'kivy.core.image.img_pygame',\n    'kivy.core.image.img_pil',\n    'kivy.core.image.img_gif',\n    'kivy.core.spelling.spelling_enchant',\n    'kivy.core.spelling.spelling_osxappkit',\n    'kivy.core.text.text_sdl2',\n    'kivy.core.text.text_pygame',\n    'kivy.core.text.text_sdlttf',\n    'kivy.core.text.text_pil',\n    'kivy.core.video.video_gstplayer',\n    'kivy.core.video.video_pygst',\n    'kivy.core.video.video_ffmpeg',\n    'kivy.core.video.video_pyglet',\n    'kivy.core.video.video_null',\n    'kivy.core.window.window_sdl2',\n    'kivy.core.window.window_egl_rpi',\n    'kivy.core.window.window_pygame',\n    'kivy.core.window.window_sdl',\n    'kivy.core.window.window_x11',\n]\n\nhiddenimports = _kivy_modules + get_modules()\nhiddenimports = list(set(hiddenimports))\n\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/tools/packaging/pyinstaller_hooks/rt-hook-kivy.py",
    "content": "from os.path import join, dirname\nfrom os import environ, chdir, putenv\nimport sys\n\nroot = 'kivy_install'\nif hasattr(sys, '_MEIPASS'):\n    # PyInstaller >= 1.6\n    chdir(sys._MEIPASS)\n    root = join(sys._MEIPASS, root)\nelif '_MEIPASS2' in environ:\n    # PyInstaller < 1.6 (tested on 1.5 only)\n    chdir(environ['_MEIPASS2'])\n    root = join(environ['_MEIPASS2'], root)\nelse:\n    chdir(dirname(sys.argv[0]))\n    root = join(dirname(sys.argv[0]), root)\n\n\nsys.path += [join(root, '_libs')]\n\nif sys.platform == 'darwin':\n    sitepackages = join(root, '..', 'sitepackages')\n    sys.path += [sitepackages, join(sitepackages, 'gst-0.10')]\n    putenv('GST_REGISTRY_FORK', 'no')\n\nenviron['GST_PLUGIN_PATH'] = join(root, '..', 'gst-plugins')\nenviron['KIVY_DATA_DIR'] = join(root, 'data')\nenviron['KIVY_EXTS_DIR'] = join(root, 'extensions')\nenviron['KIVY_MODULES_DIR'] = join(root, 'modules')\nenviron['KIVY_EMBED'] = '1'\n\n# Monkey-patch pygame to get around an issue with Pygame window icon and\n# PyInstaller 2.1. See kivy issue #1638\nimport pygame.pkgdata\n_original_getResource = pygame.pkgdata.getResource\n\n\ndef getResource(identifier, *args, **kwargs):\n    if identifier == 'pygame_icon.tiff':\n        raise IOError()\n    return _original_getResource(identifier, *args, **kwargs)\npygame.pkgdata.getResource = getResource\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/tools/packaging/win32/README.txt",
    "content": "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\nREAD THIS FIRST\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\nThis version of Kivy is a portable win32 version, 32 bits. (it work also for\n64 bits Windows.) This means everything you need to run kivy (including \npython and all other dependencies etc) are included.\n\nThis README only addresses the things specific to the portable version of kivy.  \nFor general information on how to get started, where to find the documentation \nand configuration see the README file in the kivy directory about Kivy.\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n\nRunning portable Kivy\n=====================\n\nThe same directory that has this README file in it, contains a file called kivy.bat\nrunning this kivy.bat file will set up the environment for kivy and starts the \npython interpreter with any arguments you passed\n\nExample\n~~~~~~~\n\nIf you open a command line and go to the directory (or add it to your PATH) \nYou can run the following:\n\nkivy test.py -w  <-- will run test.py as a python script with kivy ready to use\n\n\nRun a Kivy application without going to the command line\n========================================================\n\nThree options :\n\n1. You can drag your python script on top the kivy.bat file and it will launch\n\n2. If you right click on your python script (.py ending or whatever you named it), \nyou can select properties and select an application to open this type of file with.\nNavigate to the folder that includes this README and select the kivy.bat file.  \nNow all you have to do is double click (check do this always for this file type \nto make this the default)\n\n3. Install the Python Launcher for Windows. (Comes with Python 3.3 -- See Python PEP-397)\n* in each of your main.py files, add a first line of:\n   #!/usr/bin/kivy\n* create a file named C:\\Windows\\py.ini containing something like:\n   [commands]\n   kivy=\"c:\\<path>\\<to>\\<your>\\kivy.bat\"\n\nIf you already have Python installed\n====================================\n\nThe portable Kivy version shouldn't cause any conflicts and cooperate fairly well \n(at least if it's Python 2.7, otherwise some modules might cause problems if there\nis entries on PYTHONPATH)\n\n\nInstall Kivy as a standard python module\n========================================\n\nPlease refer to the install instructions in the complete README :\n* Inside the kivy folder inside this one\n* Kivy documentation at http://kivy.org/docs/\n\n\nInstall development environment inside your current shell\n=========================================================\n\nIf you want to develop with Kivy's python, you may just want to load the\nenvironment, and stay in your console. Inside a git bash / mingsys console, you\ncan type :\n\n  source /path/to/kivyenv.sh\n\nAnd it will load the whole enviroment of Kivy. This will give you an access to:\n\n  * Python binaries (python, pythonw, easy_install, pip)\n  * Cython binaries (cython)\n  * Gstreamer binaries (gst-inspect, gst-launch, ...)\n  * Pre-configured PYTHONPATH for gst and Kivy\n\nPlease note that if you already have a Python installed on your system, it will be\nnot used.\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/tools/report.py",
    "content": "'''\nReport tool\n===========\n\nThis tool is a helper for users. It can be used to dump information\nfor help during the debugging process.\n\n'''\n\nimport os\nimport sys\nimport time\nfrom time import ctime\nfrom configparser import ConfigParser\nfrom io import StringIO\n\nimport kivy\n\nreport = []\nreport_dict = {}  # One key value pair for each title.\n\n\ndef title(t):\n    report.append('')\n    report.append('=' * 80)\n    report.append(t)\n    report.append('=' * 80)\n    report.append('')\n\n# This method sends report to gist(Different file in a single gist) and\n# returns the URL\n\n\ndef send_report(dict_report):\n    import requests\n    import json\n\n    gist_report = {\n        \"description\": \"Report\",\n        \"public\": \"true\",\n        \"files\": {\n            \"Global.txt\": {\n                \"content\": \"\\n\".join(dict_report['Global']),\n                \"type\": 'text'\n            },\n            \"OpenGL.txt\": {\n                \"content\": \"\\n\".join(dict_report['OpenGL']),\n                \"type\": 'text'\n\n            },\n            \"Core selection.txt\": {\n                \"content\": \"\\n\".join(dict_report['Core']),\n                \"type\": 'text'\n            },\n            \"Libraries.txt\": {\n                \"content\": \"\\n\".join(dict_report['Libraries']),\n                \"type\": 'text'\n            },\n            \"Configuration.txt\": {\n                \"content\": \"\\n\".join(dict_report['Configuration']),\n                \"type\": 'text'\n            },\n            \"Input Availablity.txt\": {\n                \"content\": \"\\n\".join(dict_report['InputAvailablity']),\n                \"type\": 'text'\n            },\n            \"Environ.txt\": {\n                \"content\": \"\\n\".join(dict_report['Environ']),\n                \"type\": 'text'\n            },\n            \"Options.txt\": {\n                \"content\": \"\\n\".join(dict_report['Options']),\n                \"type\": 'text'\n            },\n        }\n    }\n    report_json = json.dumps(gist_report)\n    response = requests.post(\"https://api.github.com/gists\", report_json)\n    return json.loads(response.text)['html_url']\n\n# ----------------------------------------------------------\n# Start output debugging\n# ----------------------------------------------------------\n\ntitle('Global')\nreport.append('OS platform     : %s' % sys.platform)\nreport.append('Python EXE      : %s' % sys.executable)\nreport.append('Python Version  : %s' % sys.version)\nreport.append('Python API      : %s' % sys.api_version)\nreport.append('Kivy Version    : %s' % kivy.__version__)\nreport.append('Install path    : %s' % os.path.dirname(kivy.__file__))\nreport.append('Install date    : %s' % ctime(os.path.getctime(kivy.__file__)))\nreport_dict['Global'] = report\nreport = []\n\ntitle('OpenGL')\nfrom kivy.core import gl\nfrom kivy.core.window import Window\nreport.append('GL Vendor: %s' % gl.glGetString(gl.GL_VENDOR))\nreport.append('GL Renderer: %s' % gl.glGetString(gl.GL_RENDERER))\nreport.append('GL Version: %s' % gl.glGetString(gl.GL_VERSION))\next = gl.glGetString(gl.GL_EXTENSIONS)\nif ext is None:\n    report.append('GL Extensions: %s' % ext)\nelse:\n    report.append('GL Extensions:')\n    for x in ext.split():\n        report.append('\\t%s' % x)\nWindow.close()\nreport_dict['OpenGL'] = report\nreport = []\n\ntitle('Core selection')\nfrom kivy.core.audio import SoundLoader\nreport.append('Audio  = %s' % SoundLoader._classes)\nfrom kivy.core.camera import Camera\nreport.append('Camera = %s' % Camera)\nfrom kivy.core.image import ImageLoader\nreport.append('Image  = %s' % ImageLoader.loaders)\nfrom kivy.core.text import Label\nreport.append('Text   = %s' % Label)\nfrom kivy.core.video import Video\nreport.append('Video  = %s' % Video)\nreport.append('Window = %s' % Window)\nreport_dict['Core'] = report\nreport = []\n\ntitle('Libraries')\n\n\ndef testimport(libname):\n    try:\n        l = __import__(libname)\n        report.append('%-20s exist at %s' % (libname, l.__file__))\n    except ImportError:\n        report.append('%-20s is missing' % libname)\n\nfor x in (\n    'gst',\n    'pygame',\n    'pygame.midi',\n    'pyglet',\n    'videocapture',\n    'squirtle',\n    'PIL',\n    'opencv',\n    'opencv.cv',\n    'opencv.highgui',\n    'cython'):\n    testimport(x)\nreport_dict['Libraries'] = report\nreport = []\n\ntitle('Configuration')\ns = StringIO()\nfrom kivy.config import Config\nConfigParser.write(Config, s)\nreport.extend(s.getvalue().split('\\n'))\nreport_dict['Configuration'] = report\nreport = []\n\ntitle('Input availability')\nfrom kivy.input.factory import MotionEventFactory\nfor x in MotionEventFactory.list():\n    report.append(x)\nreport_dict['InputAvailablity'] = report\nreport = []\n\n'''\ntitle('Log')\nfor x in pymt_logger_history.history:\n    report.append(x.message)\n'''\n\ntitle('Environ')\nfor k, v in os.environ.items():\n    report.append('%s = %s' % (k, v))\nreport_dict['Environ'] = report\nreport = []\n\ntitle('Options')\nfor k, v in kivy.kivy_options.items():\n    report.append('%s = %s' % (k, v))\nreport_dict['Options'] = report\nreport = []\n\n# Prints the entire Output\nprint('\\n'.join(report_dict['Global'] + report_dict['OpenGL'] +\n                report_dict['Core'] + report_dict['Libraries'] +\n                report_dict['Configuration'] +\n                report_dict['InputAvailablity'] +\n                report_dict['Environ'] + report_dict['Options']))\nprint()\nprint()\n\ntry:\n    reply = input(\n        'Do you accept to send report to https://gist.github.com/ (Y/n) : ')\nexcept EOFError:\n    sys.exit(0)\n\nif reply.lower().strip() in ('', 'y'):\n    print('Please wait while sending the report...')\n\n    paste_url = send_report(report_dict)\n\n    print()\n    print()\n    print('REPORT posted at %s' % paste_url)\n    print()\n    print()\nelse:\n    print('No report posted.')\n\n# On windows system, the console leave directly after the end\n# of the dump. That's not cool if we want get report url\ninput('Enter any key to leave.')\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/tools/stub-gl-debug.py",
    "content": "from __future__ import print_function\n\na = '''cdef void   glActiveTexture (cgl.GLenum texture)\ncdef void   glAttachShader (cgl.GLuint program, cgl.GLuint shader)\ncdef void   glBindAttribLocation (cgl.GLuint program, cgl.GLuint index,  cgl.GLchar* name)\ncdef void   glBindBuffer (cgl.GLenum target, cgl.GLuint buffer)\ncdef void   glBindFramebuffer (cgl.GLenum target, cgl.GLuint framebuffer)\ncdef void   glBindRenderbuffer (cgl.GLenum target, cgl.GLuint renderbuffer)\ncdef void   glBindTexture (cgl.GLenum target, cgl.GLuint texture)\ncdef void   glBlendColor (cgl.GLclampf red, cgl.GLclampf green, cgl.GLclampf blue, cgl.GLclampf alpha)\ncdef void   glBlendEquation (cgl.GLenum mode)\ncdef void   glBlendEquationSeparate (cgl.GLenum modeRGB, cgl.GLenum modeAlpha)\ncdef void   glBlendFunc (cgl.GLenum sfactor, cgl.GLenum dfactor)\ncdef void   glBlendFuncSeparate (cgl.GLenum srcRGB, cgl.GLenum dstRGB, cgl.GLenum srcAlpha, cgl.GLenum dstAlpha)\ncdef void   glBufferData (cgl.GLenum target, cgl.GLsizeiptr size,  cgl.GLvoid* data, cgl.GLenum usage)\ncdef void   glBufferSubData (cgl.GLenum target, cgl.GLintptr offset, cgl.GLsizeiptr size,  cgl.GLvoid* data)\ncdef cgl.GLenum glCheckFramebufferStatus (cgl.GLenum target)\ncdef void   glClear (cgl.GLbitfield mask)\ncdef void   glClearColor (cgl.GLclampf red, cgl.GLclampf green, cgl.GLclampf blue, cgl.GLclampf alpha)\ncdef void   glClearDepthf (cgl.GLclampf depth)\ncdef void   glClearStencil (cgl.GLint s)\ncdef void   glColorMask (cgl.GLboolean red, cgl.GLboolean green, cgl.GLboolean blue, cgl.GLboolean alpha)\ncdef void   glCompileShader (cgl.GLuint shader)\ncdef void   glCompressedTexImage2D (cgl.GLenum target, cgl.GLint level, cgl.GLenum internalformat, cgl.GLsizei width, cgl.GLsizei height, cgl.GLint border, cgl.GLsizei imageSize,  cgl.GLvoid* data)\ncdef void   glCompressedTexSubImage2D (cgl.GLenum target, cgl.GLint level, cgl.GLint xoffset, cgl.GLint yoffset, cgl.GLsizei width, cgl.GLsizei height, cgl.GLenum format, cgl.GLsizei imageSize,  cgl.GLvoid* data)\ncdef void   glCopyTexImage2D (cgl.GLenum target, cgl.GLint level, cgl.GLenum internalformat, cgl.GLint x, cgl.GLint y, cgl.GLsizei width, cgl.GLsizei height, cgl.GLint border)\ncdef void   glCopyTexSubImage2D (cgl.GLenum target, cgl.GLint level, cgl.GLint xoffset, cgl.GLint yoffset, cgl.GLint x, cgl.GLint y, cgl.GLsizei width, cgl.GLsizei height)\ncdef cgl.GLuint glCreateProgram ()\ncdef cgl.GLuint glCreateShader (cgl.GLenum type)\ncdef void   glCullFace (cgl.GLenum mode)\ncdef void   glDeleteBuffers (cgl.GLsizei n,  cgl.GLuint* buffers)\ncdef void   glDeleteFramebuffers (cgl.GLsizei n,  cgl.GLuint* framebuffers)\ncdef void   glDeleteProgram (cgl.GLuint program)\ncdef void   glDeleteRenderbuffers (cgl.GLsizei n,  cgl.GLuint* renderbuffers)\ncdef void   glDeleteShader (cgl.GLuint shader)\ncdef void   glDeleteTextures (cgl.GLsizei n,  cgl.GLuint* textures)\ncdef void   glDepthFunc (cgl.GLenum func)\ncdef void   glDepthMask (cgl.GLboolean flag)\ncdef void   glDepthRangef (cgl.GLclampf zNear, cgl.GLclampf zFar)\ncdef void   glDetachShader (cgl.GLuint program, cgl.GLuint shader)\ncdef void   glDisable (cgl.GLenum cap)\ncdef void   glDisableVertexAttribArray (cgl.GLuint index)\ncdef void   glDrawArrays (cgl.GLenum mode, cgl.GLint first, cgl.GLsizei count)\ncdef void   glDrawElements (cgl.GLenum mode, cgl.GLsizei count, cgl.GLenum type,  cgl.GLvoid* indices)\ncdef void   glEnable (cgl.GLenum cap)\ncdef void   glEnableVertexAttribArray (cgl.GLuint index)\ncdef void   glFinish ()\ncdef void   glFlush ()\ncdef void   glFramebufferRenderbuffer (cgl.GLenum target, cgl.GLenum attachment, cgl.GLenum renderbuffertarget, cgl.GLuint renderbuffer)\ncdef void   glFramebufferTexture2D (cgl.GLenum target, cgl.GLenum attachment, cgl.GLenum textarget, cgl.GLuint texture, cgl.GLint level)\ncdef void   glFrontFace (cgl.GLenum mode)\ncdef void   glGenBuffers (cgl.GLsizei n, cgl.GLuint* buffers)\ncdef void   glGenerateMipmap (cgl.GLenum target)\ncdef void   glGenFramebuffers (cgl.GLsizei n, cgl.GLuint* framebuffers)\ncdef void   glGenRenderbuffers (cgl.GLsizei n, cgl.GLuint* renderbuffers)\ncdef void   glGenTextures (cgl.GLsizei n, cgl.GLuint* textures)\ncdef void   glGetActiveAttrib (cgl.GLuint program, cgl.GLuint index, cgl.GLsizei bufsize, cgl.GLsizei* length, cgl.GLint* size, cgl.GLenum* type, cgl.GLchar* name)\ncdef void   glGetActiveUniform (cgl.GLuint program, cgl.GLuint index, cgl.GLsizei bufsize, cgl.GLsizei* length, cgl.GLint* size, cgl.GLenum* type, cgl.GLchar* name)\ncdef void   glGetAttachedShaders (cgl.GLuint program, cgl.GLsizei maxcount, cgl.GLsizei* count, cgl.GLuint* shaders)\ncdef int    glGetAttribLocation (cgl.GLuint program,  cgl.GLchar* name)\ncdef void   glGetBooleanv (cgl.GLenum pname, cgl.GLboolean* params)\ncdef void   glGetBufferParameteriv (cgl.GLenum target, cgl.GLenum pname, cgl.GLint* params)\ncdef cgl.GLenum glGetError ()\ncdef void   glGetFloatv (cgl.GLenum pname, cgl.GLfloat* params)\ncdef void   glGetFramebufferAttachmentParameteriv (cgl.GLenum target, cgl.GLenum attachment, cgl.GLenum pname, cgl.GLint* params)\ncdef void   glGetIntegerv (cgl.GLenum pname, cgl.GLint* params)\ncdef void   glGetProgramiv (cgl.GLuint program, cgl.GLenum pname, cgl.GLint* params)\ncdef void   glGetProgramInfoLog (cgl.GLuint program, cgl.GLsizei bufsize, cgl.GLsizei* length, cgl.GLchar* infolog)\ncdef void   glGetRenderbufferParameteriv (cgl.GLenum target, cgl.GLenum pname, cgl.GLint* params)\ncdef void   glGetShaderiv (cgl.GLuint shader, cgl.GLenum pname, cgl.GLint* params)\ncdef void   glGetShaderInfoLog (cgl.GLuint shader, cgl.GLsizei bufsize, cgl.GLsizei* length, cgl.GLchar* infolog)\n#cdef void   glGetShaderPrecisionFormat (cgl.GLenum shadertype, cgl.GLenum precisiontype, cgl.GLint* range, cgl.GLint* precision)\ncdef void   glGetShaderSource (cgl.GLuint shader, cgl.GLsizei bufsize, cgl.GLsizei* length, cgl.GLchar* source)\ncdef   cgl.GLubyte*  glGetString (cgl.GLenum name)\ncdef void   glGetTexParameterfv (cgl.GLenum target, cgl.GLenum pname, cgl.GLfloat* params)\ncdef void   glGetTexParameteriv (cgl.GLenum target, cgl.GLenum pname, cgl.GLint* params)\ncdef void   glGetUniformfv (cgl.GLuint program, cgl.GLint location, cgl.GLfloat* params)\ncdef void   glGetUniformiv (cgl.GLuint program, cgl.GLint location, cgl.GLint* params)\ncdef int    glGetUniformLocation (cgl.GLuint program,  cgl.GLchar* name)\ncdef void   glGetVertexAttribfv (cgl.GLuint index, cgl.GLenum pname, cgl.GLfloat* params)\ncdef void   glGetVertexAttribiv (cgl.GLuint index, cgl.GLenum pname, cgl.GLint* params)\ncdef void   glGetVertexAttribPointerv (cgl.GLuint index, cgl.GLenum pname, cgl.GLvoid** pointer)\ncdef void   glHint (cgl.GLenum target, cgl.GLenum mode)\ncdef cgl.GLboolean  glIsBuffer (cgl.GLuint buffer)\ncdef cgl.GLboolean  glIsEnabled (cgl.GLenum cap)\ncdef cgl.GLboolean  glIsFramebuffer (cgl.GLuint framebuffer)\ncdef cgl.GLboolean  glIsProgram (cgl.GLuint program)\ncdef cgl.GLboolean  glIsRenderbuffer (cgl.GLuint renderbuffer)\ncdef cgl.GLboolean  glIsShader (cgl.GLuint shader)\ncdef cgl.GLboolean  glIsTexture (cgl.GLuint texture)\ncdef void  glLineWidth (cgl.GLfloat width)\ncdef void  glLinkProgram (cgl.GLuint program)\ncdef void  glPixelStorei (cgl.GLenum pname, cgl.GLint param)\ncdef void  glPolygonOffset (cgl.GLfloat factor, cgl.GLfloat units)\ncdef void  glReadPixels (cgl.GLint x, cgl.GLint y, cgl.GLsizei width, cgl.GLsizei height, cgl.GLenum format, cgl.GLenum type, cgl.GLvoid* pixels)\n#cdef void  glReleaseShaderCompiler ()\ncdef void  glRenderbufferStorage (cgl.GLenum target, cgl.GLenum internalformat, cgl.GLsizei width, cgl.GLsizei height)\ncdef void  glSampleCoverage (cgl.GLclampf value, cgl.GLboolean invert)\ncdef void  glScissor (cgl.GLint x, cgl.GLint y, cgl.GLsizei width, cgl.GLsizei height)\n#cdef void  glShaderBinary (cgl.GLsizei n,  cgl.GLuint* shaders, cgl.GLenum binaryformat,  cgl.GLvoid* binary, cgl.GLsizei length)\ncdef void  glShaderSource (cgl.GLuint shader, cgl.GLsizei count,  cgl.GLchar** string,  cgl.GLint* length)\ncdef void  glStencilFunc (cgl.GLenum func, cgl.GLint ref, cgl.GLuint mask)\ncdef void  glStencilFuncSeparate (cgl.GLenum face, cgl.GLenum func, cgl.GLint ref, cgl.GLuint mask)\ncdef void  glStencilMask (cgl.GLuint mask)\ncdef void  glStencilMaskSeparate (cgl.GLenum face, cgl.GLuint mask)\ncdef void  glStencilOp (cgl.GLenum fail, cgl.GLenum zfail, cgl.GLenum zpass)\ncdef void  glStencilOpSeparate (cgl.GLenum face, cgl.GLenum fail, cgl.GLenum zfail, cgl.GLenum zpass)\ncdef void  glTexImage2D (cgl.GLenum target, cgl.GLint level, cgl.GLint internalformat, cgl.GLsizei width, cgl.GLsizei height, cgl.GLint border, cgl.GLenum format, cgl.GLenum type,  cgl.GLvoid* pixels)\ncdef void  glTexParameterf (cgl.GLenum target, cgl.GLenum pname, cgl.GLfloat param)\ncdef void  glTexParameterfv (cgl.GLenum target, cgl.GLenum pname,  cgl.GLfloat* params)\ncdef void  glTexParameteri (cgl.GLenum target, cgl.GLenum pname, cgl.GLint param)\ncdef void  glTexParameteriv (cgl.GLenum target, cgl.GLenum pname,  cgl.GLint* params)\ncdef void  glTexSubImage2D (cgl.GLenum target, cgl.GLint level, cgl.GLint xoffset, cgl.GLint yoffset, cgl.GLsizei width, cgl.GLsizei height, cgl.GLenum format, cgl.GLenum type,  cgl.GLvoid* pixels)\ncdef void  glUniform1f (cgl.GLint location, cgl.GLfloat x)\ncdef void  glUniform1fv (cgl.GLint location, cgl.GLsizei count,  cgl.GLfloat* v)\ncdef void  glUniform1i (cgl.GLint location, cgl.GLint x)\ncdef void  glUniform1iv (cgl.GLint location, cgl.GLsizei count,  cgl.GLint* v)\ncdef void  glUniform2f (cgl.GLint location, cgl.GLfloat x, cgl.GLfloat y)\ncdef void  glUniform2fv (cgl.GLint location, cgl.GLsizei count,  cgl.GLfloat* v)\ncdef void  glUniform2i (cgl.GLint location, cgl.GLint x, cgl.GLint y)\ncdef void  glUniform2iv (cgl.GLint location, cgl.GLsizei count,  cgl.GLint* v)\ncdef void  glUniform3f (cgl.GLint location, cgl.GLfloat x, cgl.GLfloat y, cgl.GLfloat z)\ncdef void  glUniform3fv (cgl.GLint location, cgl.GLsizei count,  cgl.GLfloat* v)\ncdef void  glUniform3i (cgl.GLint location, cgl.GLint x, cgl.GLint y, cgl.GLint z)\ncdef void  glUniform3iv (cgl.GLint location, cgl.GLsizei count,  cgl.GLint* v)\ncdef void  glUniform4f (cgl.GLint location, cgl.GLfloat x, cgl.GLfloat y, cgl.GLfloat z, cgl.GLfloat w)\ncdef void  glUniform4fv (cgl.GLint location, cgl.GLsizei count,  cgl.GLfloat* v)\ncdef void  glUniform4i (cgl.GLint location, cgl.GLint x, cgl.GLint y, cgl.GLint z, cgl.GLint w)\ncdef void  glUniform4iv (cgl.GLint location, cgl.GLsizei count,  cgl.GLint* v)\ncdef void  glUniformMatrix2fv (cgl.GLint location, cgl.GLsizei count, cgl.GLboolean transpose,  cgl.GLfloat* value)\ncdef void  glUniformMatrix3fv (cgl.GLint location, cgl.GLsizei count, cgl.GLboolean transpose,  cgl.GLfloat* value)\ncdef void  glUniformMatrix4fv (cgl.GLint location, cgl.GLsizei count, cgl.GLboolean transpose,  cgl.GLfloat* value)\ncdef void  glUseProgram (cgl.GLuint program)\ncdef void  glValidateProgram (cgl.GLuint program)\ncdef void  glVertexAttrib1f (cgl.GLuint indx, cgl.GLfloat x)\ncdef void  glVertexAttrib1fv (cgl.GLuint indx,  cgl.GLfloat* values)\ncdef void  glVertexAttrib2f (cgl.GLuint indx, cgl.GLfloat x, cgl.GLfloat y)\ncdef void  glVertexAttrib2fv (cgl.GLuint indx,  cgl.GLfloat* values)\ncdef void  glVertexAttrib3f (cgl.GLuint indx, cgl.GLfloat x, cgl.GLfloat y, cgl.GLfloat z)\ncdef void  glVertexAttrib3fv (cgl.GLuint indx,  cgl.GLfloat* values)\ncdef void  glVertexAttrib4f (cgl.GLuint indx, cgl.GLfloat x, cgl.GLfloat y, cgl.GLfloat z, cgl.GLfloat w)\ncdef void  glVertexAttrib4fv (cgl.GLuint indx,  cgl.GLfloat* values)\ncdef void  glVertexAttribPointer (cgl.GLuint indx, cgl.GLint size, cgl.GLenum type, cgl.GLboolean normalized, cgl.GLsizei stride,  cgl.GLvoid* ptr)\ncdef void  glViewport (cgl.GLint x, cgl.GLint y, cgl.GLsizei width, cgl.GLsizei height)'''\n\ndef replace(s):\n    item = s.split(' ')\n    rettype = item[1]\n    item = item[2:]\n    for x in item:\n        x = x.strip()\n        if not x or x.startswith('GL'):\n            continue\n        if x.startswith('(GL'):\n            yield '('\n            continue\n        if x.startswith('gl'):\n            prefix = ''\n            if rettype != 'void':\n                prefix = 'return '\n            yield '%scgl.%s' % (prefix, x)\n            continue\n        yield x\n\nprint('''\n# This file was automatically generated with kivy/tools/stub-gl-debug.py\ncimport c_opengl as cgl\n\n''')\n\nlines = a.splitlines()\nfor x in lines:\n    if x.startswith('#'):\n        # There are some functions that either do not exist or break on OSX.\n        # Just skip those.\n        print('# Skipping generation of: \"%s\"' % x)\n        continue\n    x = x.replace('cgl.', '')\n    y = ' '.join(replace(x))\n\n    print('%s with gil:' % x)\n    s = x.split()\n    print('    print \"GL %s(' % s[2], end=' ')\n    pointer = 0\n    for arg in s[3:]:\n        arg = arg.strip()\n        arg = arg.replace(',', '').replace(')', '')\n        if 'GL' in arg or arg == '(':\n            pointer = arg.count('*')\n            continue\n        pointer = '*' * pointer\n        if pointer:\n            print('%s%s=\", repr(hex(<long> %s)), \",' % (arg, pointer, arg), end=' ')\n        else:\n            print('%s = \", %s, \",' % (arg, arg), end=' ')\n        pointer = 0\n    print(')\"')\n    print('    %s' % y)\n    print('    ret = glGetError()')\n    print('    if ret: print(\"ERR {} / {}\".format(ret, ret))')\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/tools/texturecompress.py",
    "content": "#:/usr/bin/env python2.7\n'''\nTexture compression tool\n========================\n\nThis tool is designed to compress images into:\n\n- PVRTC (PowerVR Texture Compression), mostly iOS devices\n- ETC1 (Ericson compression), working on all GLES2/Android devices\n\nUsage\n-----\n\nIn order to compress a texture::\n\n    texturecompress.py [--dir <directory>] <format> <image.png>\n\nThis will create a `image.tex` file with a json header that contains all the\nimage information and the compressed data.\n\nTODO\n----\n\nSupport more format, such as:\n\n- S3TC (already supported in Kivy)\n- DXT1 (already supported in Kivy)\n'''\n\nimport json\nfrom struct import pack\nfrom pprint import pprint\nfrom subprocess import Popen\nfrom PIL import Image\nfrom argparse import ArgumentParser\nfrom sys import exit\nfrom os.path import join, exists, dirname, basename\nfrom os import environ, unlink\n\n\nclass Tool(object):\n    def __init__(self, options):\n        super(Tool, self).__init__()\n        self.options = options\n        self.source_fn = options.image\n        self.dest_dir = options.dir or dirname(options.image)\n\n    @property\n    def tex_fn(self):\n        fn = basename(self.source_fn).rsplit('.', 1)[0] + '.tex'\n        return join(self.dest_dir, fn)\n\n    def compress(self):\n        pass\n\n    def nearest_pow2(self, v):\n        # Credits: Sean Anderson\n        v -= 1\n        v |= v >> 1\n        v |= v >> 2\n        v |= v >> 4\n        v |= v >> 8\n        v |= v >> 16\n        return v + 1\n\n    def runcmd(self, cmd):\n        print('Run: {}'.format(' '.join(cmd)))\n        Popen(cmd).communicate()\n\n    def write_tex(self, data, fmt, image_size, texture_size, mipmap=False,\n            formatinfo=None):\n        infos = {\n            'datalen': len(data),\n            'image_size': image_size,\n            'texture_size': texture_size,\n            'mipmap': mipmap,\n            'format': fmt}\n        if formatinfo:\n            infos['formatinfo'] = formatinfo\n        header = json.dumps(infos, indent=0, separators=(',', ':'))\n        header = header.replace('\\n', '')\n        with open(self.tex_fn, 'wb') as fd:\n            fd.write('KTEX')\n            fd.write(pack('I', len(header)))\n            fd.write(header)\n            fd.write(data)\n\n        print('Done! Compressed texture written at {}'.format(self.tex_fn))\n        pprint(infos)\n\n    @staticmethod\n    def run():\n        parser = ArgumentParser(\n                description='Convert images to compressed texture')\n        parser.add_argument('--mipmap', type=bool, default=False,\n                help='Auto generate mipmaps')\n        parser.add_argument('--dir', type=str, default=None,\n                help='Output directory to generate the compressed texture')\n        parser.add_argument('format', type=str, choices=['pvrtc', 'etc1'],\n                help='Format of the final texture')\n        parser.add_argument('image', type=str,\n                help='Image filename')\n        args = parser.parse_args()\n\n        if args.format == 'pvrtc':\n            PvrtcTool(args).compress()\n        elif args.format == 'etc1':\n            Etc1Tool(args).compress()\n        else:\n            print('Unknown compression format')\n            exit(1)\n\n\nclass Etc1Tool(Tool):\n    def __init__(self, options):\n        super(Etc1Tool, self).__init__(options)\n        self.etc1tool = None\n        self.locate_etc1tool()\n\n    def locate_etc1tool(self):\n        search_directories = [environ.get('ANDROIDSDK', '/')]\n        search_directories += environ.get('PATH', '').split(':')\n        for directory in search_directories:\n            fn = join(directory, 'etc1tool')\n            if not exists(fn):\n                fn = join(directory, 'tools', 'etc1tool')\n                if not exists(fn):\n                    continue\n            print('Found texturetool at {}'.format(directory))\n            self.etc1tool = fn\n            return\n\n        if self.etc1tool is None:\n            print('Error: Unable to locate \"etc1tool\".\\n'\n                  'Make sure that \"etc1tool\" is available in your PATH.\\n'\n                  'Or export the path of your Android SDK to ANDROIDSDK')\n            exit(1)\n\n    def compress(self):\n        # 1. open the source image, and get the dimensions\n        image = Image.open(self.source_fn)\n        w, h = image.size\n        print('Image size is {}x{}'.format(*image.size))\n\n        # 2. search the nearest 2^\n        w2 = self.nearest_pow2(w)\n        h2 = self.nearest_pow2(h)\n        print('Nearest power-of-2 size is {}x{}'.format(w2, h2))\n\n        # 3. invoke etc1tool\n        raw_tex_fn = self.tex_fn + '.raw'\n        cmd = [self.etc1tool, self.source_fn, '--encodeNoHeader', '-o',\n               raw_tex_fn]\n        try:\n            self.runcmd(cmd)\n            with open(raw_tex_fn, 'rb') as fd:\n                data = fd.read()\n        finally:\n            if exists(raw_tex_fn):\n                unlink(raw_tex_fn)\n\n        # 5. write texture info\n        self.write_tex(data, 'etc1_rgb8', (w, h), (w2, h2), self.options.mipmap)\n\n\nclass PvrtcTool(Tool):\n    def __init__(self, options):\n        super(PvrtcTool, self).__init__(options)\n        self.texturetool = None\n        self.locate_texturetool()\n\n    def locate_texturetool(self):\n        search_directories = [\n            ('/Applications/Xcode.app/Contents/Developer/Platforms/'\n             'iPhoneOS.platform/Developer/usr/bin/'),\n            '/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/']\n        search_directories += environ.get('PATH', '').split(':')\n\n        for directory in search_directories:\n            fn = join(directory, 'texturetool')\n            if not exists(fn):\n                continue\n            print('Found texturetool at {}'.format(directory))\n            self.texturetool = fn\n            return\n\n        print('Error: Unable to locate \"texturetool\".\\n'\n              'Please install the iPhone SDK, or the PowerVR SDK.\\n'\n              'Then make sure that \"texturetool\" is available in your PATH.')\n        exit(1)\n\n    def compress(self):\n        # 1. open the source image, and get the dimensions\n        image = Image.open(self.source_fn)\n        w, h = image.size\n        print('Image size is {}x{}'.format(*image.size))\n\n        # 2. search the nearest 2^\n        w2 = self.nearest_pow2(w)\n        h2 = self.nearest_pow2(h)\n        print('Nearest power-of-2 size is {}x{}'.format(w2, h2))\n\n        # 3. for PVR, the image MUST be a square. use the bigger size then\n        s2 = max(w2, h2)\n        print('PVR need a square image, the texture will be {0}x{0}'.format(s2))\n\n        ext = self.source_fn.rsplit('.', 1)[-1]\n        tmpfile = '/tmp/ktexturecompress.{}'.format(ext)\n        image = image.resize((s2, s2))\n        image.save(tmpfile)\n\n        # 4. invoke texture tool\n        raw_tex_fn = self.tex_fn + '.raw'\n        cmd = [self.texturetool]\n        if self.options.mipmap:\n            cmd += ['-m']\n        cmd += ['-e', 'PVRTC', '-o', raw_tex_fn, '-f', 'RAW', tmpfile]\n        try:\n            self.runcmd(cmd)\n            with open(raw_tex_fn, 'rb') as fd:\n                data = fd.read()\n        finally:\n            if exists(raw_tex_fn):\n                unlink(raw_tex_fn)\n\n        # 5. write texture info\n        self.write_tex(data, 'pvrtc_rgba4', (w, h), (s2, s2),\n                       self.options.mipmap)\n\n\nif __name__ == '__main__':\n    Tool.run()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/__init__.py",
    "content": "'''\nWidgets\n=======\n\nWidgets are elements of a graphical user interface that form part of the\n`User Experience <http://en.wikipedia.org/wiki/User_experience>`_.\nThe `kivy.uix` module contains classes for creating and managing Widgets.\nPlease refer to the :doc:`api-kivy.uix.widget` documentation for further\ninformation.\n\nKivy widgets can be categorized as follows:\n\n- **UX widgets**: Classical user interface widgets, ready to be assembled to\n  create more complex widgets.\n\n    :doc:`api-kivy.uix.label`, :doc:`api-kivy.uix.button`,\n    :doc:`api-kivy.uix.checkbox`,\n    :doc:`api-kivy.uix.image`, :doc:`api-kivy.uix.slider`,\n    :doc:`api-kivy.uix.progressbar`, :doc:`api-kivy.uix.textinput`,\n    :doc:`api-kivy.uix.togglebutton`, :doc:`api-kivy.uix.switch`,\n    :doc:`api-kivy.uix.video`\n\n- **Layouts**: A layout widget does no rendering but just acts as a trigger\n  that arranges its children in a specific way. Read more on\n  :doc:`Layouts here <api-kivy.uix.layout>`.\n\n    :doc:`api-kivy.uix.anchorlayout`, :doc:`api-kivy.uix.boxlayout`,\n    :doc:`api-kivy.uix.floatlayout`,\n    :doc:`api-kivy.uix.gridlayout`, :doc:`api-kivy.uix.pagelayout`,\n    :doc:`api-kivy.uix.relativelayout`, :doc:`api-kivy.uix.scatterlayout`,\n    :doc:`api-kivy.uix.stacklayout`\n\n- **Complex UX widgets**: Non-atomic widgets that are the result of\n  combining multiple classic widgets.\n  We call them complex because their assembly and usage are not as\n  generic as the classical widgets.\n\n    :doc:`api-kivy.uix.bubble`, :doc:`api-kivy.uix.dropdown`,\n    :doc:`api-kivy.uix.filechooser`, :doc:`api-kivy.uix.popup`,\n    :doc:`api-kivy.uix.spinner`,\n    :doc:`api-kivy.uix.listview`,\n    :doc:`api-kivy.uix.tabbedpanel`, :doc:`api-kivy.uix.videoplayer`,\n    :doc:`api-kivy.uix.vkeyboard`,\n\n- **Behaviors widgets**: Theses widgets do no rendering but act on the\n  graphics instructions or interaction (touch) behavior of their children.\n\n    :doc:`api-kivy.uix.scatter`, :doc:`api-kivy.uix.stencilview`\n\n- **Screen manager**: Manages screens and transitions when switching\n  from one to another.\n\n    :doc:`api-kivy.uix.screenmanager`\n\n----\n'''\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/abstractview.py",
    "content": "'''\nAbstract View\n=============\n\n.. versionadded:: 1.5\n\n.. warning::\n\n    This code is still experimental, and its API is subject to change in a\n    future version.\n\nThe :class:`~kivy.uix.abstractview.AbstractView` widget has an adapter property\nfor an adapter that mediates to data. The adapter manages an\nitem_view_instance dict property that holds views for each data item,\noperating as a cache.\n\n'''\n\n__all__ = ('AbstractView', )\n\nfrom kivy.uix.floatlayout import FloatLayout\nfrom kivy.properties import ObjectProperty\n\n\nclass AbstractView(FloatLayout):\n    '''\n    View using an :class:`~kivy.adapters.adapter.Adapter` as a data provider.\n    '''\n\n    adapter = ObjectProperty(None)\n    '''The adapter can be one of several kinds of\n    :class:`adapters <kivy.adapters.adapter.Adapter>`. The most\n    common example is the :class:`~kivy.adapters.listadapter.ListAdapter` used\n    for managing data items in a list.\n    '''\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/accordion.py",
    "content": "'''\nAccordion\n=========\n\n.. versionadded:: 1.0.8\n\n\n.. image:: images/accordion.jpg\n    :align: right\n\nThe Accordion widget is a form of menu where the options are stacked either\nvertically or horizontally and the item in focus (when touched) opens up to\ndisplay its content.\n\nThe :class:`Accordion` should contain one or many :class:`AccordionItem`\ninstances, each of which should contain one root content widget. You'll end up\nwith a Tree something like this:\n\n- Accordion\n\n  - AccordionItem\n\n    - YourContent\n\n  - AccordionItem\n\n    - BoxLayout\n\n      - Another user content 1\n\n      - Another user content 2\n\n  - AccordionItem\n\n    - Another user content\n\n\nThe current implementation divides the :class:`AccordionItem` into two parts:\n\n#. One container for the title bar\n#. One container for the content\n\nThe title bar is made from a Kv template. We'll see how to create a new\ntemplate to customize the design of the title bar.\n\n.. warning::\n\n    If you see message like::\n\n        [WARNING] [Accordion] not have enough space for displaying all children\n        [WARNING] [Accordion] need 440px, got 100px\n        [WARNING] [Accordion] layout aborted.\n\n    That means you have too many children and there is no more space to\n    display the content. This is \"normal\" and nothing will be done. Try to\n    increase the space for the accordion or reduce the number of children. You\n    can also reduce the :attr:`Accordion.min_space`.\n\nSimple example\n--------------\n\n.. include:: ../../examples/widgets/accordion_1.py\n    :literal:\n\nCustomize the accordion\n-----------------------\n\nYou can increase the default size of the title bar::\n\n    root = Accordion(min_space=60)\n\nOr change the orientation to vertical::\n\n    root = Accordion(orientation='vertical')\n\nThe AccordionItem is more configurable and you can set your own title\nbackground when the item is collapsed or opened::\n\n    item = AccordionItem(background_normal='image_when_collapsed.png',\n        background_selected='image_when_selected.png')\n\n'''\n\n__all__ = ('Accordion', 'AccordionItem', 'AccordionException')\n\nfrom kivy.animation import Animation\nfrom kivy.uix.floatlayout import FloatLayout\nfrom kivy.clock import Clock\nfrom kivy.lang import Builder\nfrom kivy.properties import (ObjectProperty, StringProperty,\n                             BooleanProperty, NumericProperty,\n                             ListProperty, OptionProperty, DictProperty)\nfrom kivy.uix.widget import Widget\nfrom kivy.logger import Logger\n\n\nclass AccordionException(Exception):\n    '''AccordionException class.\n    '''\n    pass\n\n\nclass AccordionItem(FloatLayout):\n    '''AccordionItem class that must be used in conjunction with the\n    :class:`Accordion` class. See the module documentation for more\n    information.\n    '''\n\n    title = StringProperty('')\n    '''Title string of the item. The title might be used in conjuction with the\n    `AccordionItemTitle` template. If you are using a custom template, you can\n    use that property as a text entry, or not. By default, it's used for the\n    title text. See title_template and the example below.\n\n    :attr:`title` is a :class:`~kivy.properties.StringProperty` and defaults\n    to ''.\n    '''\n\n    title_template = StringProperty('AccordionItemTitle')\n    '''Template to use for creating the title part of the accordion item. The\n    default template is a simple Label, not customizable (except the text) that\n    supports vertical and horizontal orientation and different backgrounds for\n    collapse and selected mode.\n\n    It's better to create and use your own template if the default template\n    does not suffice.\n\n    :attr:`title` is a :class:`~kivy.properties.StringProperty` and defaults to\n    'AccordionItemTitle'. The current default template lives in the\n    `kivy/data/style.kv` file.\n\n    Here is the code if you want to build your own template::\n\n        [AccordionItemTitle@Label]:\n            text: ctx.title\n            canvas.before:\n                Color:\n                    rgb: 1, 1, 1\n                BorderImage:\n                    source:\n                        ctx.item.background_normal \\\n                        if ctx.item.collapse \\\n                        else ctx.item.background_selected\n                    pos: self.pos\n                    size: self.size\n                PushMatrix\n                Translate:\n                    xy: self.center_x, self.center_y\n                Rotate:\n                    angle: 90 if ctx.item.orientation == 'horizontal' else 0\n                    axis: 0, 0, 1\n                Translate:\n                    xy: -self.center_x, -self.center_y\n            canvas.after:\n                PopMatrix\n\n\n    '''\n\n    title_args = DictProperty({})\n    '''Default arguments that will be passed to the\n    :meth:`kivy.lang.Builder.template` method.\n\n    :attr:`title_args` is a :class:`~kivy.properties.DictProperty` and defaults\n    to {}.\n    '''\n\n    collapse = BooleanProperty(True)\n    '''Boolean to indicate if the current item is collapsed or not.\n\n    :attr:`collapse` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n\n    collapse_alpha = NumericProperty(1.)\n    '''Value between 0 and 1 to indicate how much the item is collasped (1) or\n    whether it is selected (0). It's mostly used for animation.\n\n    :attr:`collapse_alpha` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 1.\n    '''\n\n    accordion = ObjectProperty(None)\n    '''Instance of the :class:`Accordion` that the item belongs to.\n\n    :attr:`accordion` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    background_normal = StringProperty(\n        'atlas://data/images/defaulttheme/button')\n    '''Background image of the accordion item used for the default graphical\n    representation when the item is collapsed.\n\n    :attr:`background_normal` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/button'.\n    '''\n\n    background_disabled_normal = StringProperty(\n        'atlas://data/images/defaulttheme/button_disabled')\n    '''Background image of the accordion item used for the default graphical\n    representation when the item is collapsed and disabled.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`background__disabled_normal` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/button_disabled'.\n    '''\n\n    background_selected = StringProperty(\n        'atlas://data/images/defaulttheme/button_pressed')\n    '''Background image of the accordion item used for the default graphical\n    representation when the item is selected (not collapsed).\n\n    :attr:`background_normal` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/button_pressed'.\n    '''\n\n    background_disabled_selected = StringProperty(\n        'atlas://data/images/defaulttheme/button_disabled_pressed')\n    '''Background image of the accordion item used for the default graphical\n    representation when the item is selected (not collapsed) and disabled.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`background_disabled_selected` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/button_disabled_pressed'.\n    '''\n\n    orientation = OptionProperty('vertical', options=(\n        'horizontal', 'vertical'))\n    '''Link to the :attr:`Accordion.orientation` property.\n    '''\n\n    min_space = NumericProperty('44dp')\n    '''Link to the :attr:`Accordion.min_space` property.\n    '''\n\n    content_size = ListProperty([100, 100])\n    '''(internal) Set by the :class:`Accordion` to the size allocated for the\n    content.\n    '''\n\n    container = ObjectProperty(None)\n    '''(internal) Property that will be set to the container of children inside\n    the AccordionItem representation.\n    '''\n\n    container_title = ObjectProperty(None)\n    '''(internal) Property that will be set to the container of title inside\n    the AccordionItem representation.\n    '''\n\n    def __init__(self, **kwargs):\n        self._trigger_title = Clock.create_trigger(self._update_title, -1)\n        self._anim_collapse = None\n        super(AccordionItem, self).__init__(**kwargs)\n        self.bind(title=self._trigger_title,\n                  title_template=self._trigger_title,\n                  title_args=self._trigger_title)\n        self._trigger_title()\n\n    def add_widget(self, widget):\n        if self.container is None:\n            return super(AccordionItem, self).add_widget(widget)\n        return self.container.add_widget(widget)\n\n    def remove_widget(self, widget):\n        if self.container:\n            self.container.remove_widget(widget)\n        super(AccordionItem, self).remove_widget(widget)\n\n    def on_collapse(self, instance, value):\n        accordion = self.accordion\n        if accordion is None:\n            return\n        if not value:\n            self.accordion.select(self)\n        collapse_alpha = float(value)\n        if self._anim_collapse:\n            self._anim_collapse.stop()\n            self._anim_collapse = None\n        if self.collapse_alpha != collapse_alpha:\n            self._anim_collapse = Animation(\n                collapse_alpha=collapse_alpha,\n                t=accordion.anim_func,\n                d=accordion.anim_duration).start(self)\n\n    def on_collapse_alpha(self, instance, value):\n        self.accordion._trigger_layout()\n\n    def on_touch_down(self, touch):\n        if not self.collide_point(*touch.pos):\n            return\n        if self.disabled:\n            return True\n        if self.collapse:\n            self.collapse = False\n            return True\n        else:\n            return super(AccordionItem, self).on_touch_down(touch)\n\n    def _update_title(self, dt):\n        if not self.container_title:\n            self._trigger_title()\n            return\n        c = self.container_title\n        c.clear_widgets()\n        instance = Builder.template(self.title_template,\n                                    title=self.title,\n                                    item=self,\n                                    **self.title_args)\n        c.add_widget(instance)\n\n\nclass Accordion(Widget):\n    '''Accordion class. See module documentation for more information.\n    '''\n\n    orientation = OptionProperty('horizontal', options=(\n        'horizontal', 'vertical'))\n    '''Orientation of the layout.\n\n    :attr:`orientation` is an :class:`~kivy.properties.OptionProperty`\n    and defaults to 'horizontal'. Can take a value of 'vertical' or\n    'horizontal'.\n\n    '''\n\n    anim_duration = NumericProperty(.25)\n    '''Duration of the animation in seconds when a new accordion item is\n    selected.\n\n    :attr:`anim_duration` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to .25 (250ms).\n    '''\n\n    anim_func = ObjectProperty('out_expo')\n    '''Easing function to use for the animation. Check\n    :class:`kivy.animation.AnimationTransition` for more information about\n    available animation functions.\n\n    :attr:`anim_func` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to 'out_expo'. You can set a string or a function to use as an\n    easing function.\n    '''\n\n    min_space = NumericProperty('44dp')\n    '''Minimum space to use for the title of each item. This value is\n    automatically set for each child every time the layout event occurs.\n\n    :attr:`min_space` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 44 (px).\n    '''\n\n    def __init__(self, **kwargs):\n        super(Accordion, self).__init__(**kwargs)\n        self._trigger_layout = Clock.create_trigger(self._do_layout, -1)\n        self.bind(\n            orientation=self._trigger_layout,\n            children=self._trigger_layout,\n            size=self._trigger_layout,\n            pos=self._trigger_layout,\n            min_space=self._trigger_layout)\n\n    def add_widget(self, widget, *largs):\n        if not isinstance(widget, AccordionItem):\n            raise AccordionException('Accordion accept only AccordionItem')\n\n        widget.accordion = self\n        ret = super(Accordion, self).add_widget(widget, *largs)\n        return ret\n\n    def select(self, instance):\n        if instance not in self.children:\n            raise AccordionException(\n                'Accordion: instance not found in children')\n        for widget in self.children:\n            widget.collapse = widget is not instance\n        self._trigger_layout()\n\n    def _do_layout(self, dt):\n        children = self.children\n        if children:\n            all_collapsed = all(x.collapse for x in children)\n        else:\n            all_collapsed = False\n\n        if all_collapsed:\n            children[0].collapse = False\n\n        orientation = self.orientation\n        min_space = self.min_space\n        min_space_total = len(children) * self.min_space\n        w, h = self.size\n        x, y = self.pos\n        if orientation == 'horizontal':\n            display_space = self.width - min_space_total\n        else:\n            display_space = self.height - min_space_total\n\n        if display_space <= 0:\n            Logger.warning('Accordion: not enough space '\n                           'for displaying all children')\n            Logger.warning('Accordion: need %dpx, got %dpx' % (\n                min_space_total, min_space_total + display_space))\n            Logger.warning('Accordion: layout aborted.')\n            return\n\n        if orientation == 'horizontal':\n            children = reversed(children)\n\n        for child in children:\n            child_space = min_space\n            child_space += display_space * (1 - child.collapse_alpha)\n            child._min_space = min_space\n            child.x = x\n            child.y = y\n            child.orientation = self.orientation\n            if orientation == 'horizontal':\n                child.content_size = display_space, h\n                child.width = child_space\n                child.height = h\n                x += child_space\n            else:\n                child.content_size = w, display_space\n                child.width = w\n                child.height = child_space\n                y += child_space\n\nif __name__ == '__main__':\n    from kivy.base import runTouchApp\n    from kivy.uix.button import Button\n    from kivy.uix.boxlayout import BoxLayout\n    from kivy.uix.label import Label\n\n    acc = Accordion()\n    for x in range(10):\n        item = AccordionItem(title='Title %d' % x)\n        if x == 0:\n            item.add_widget(Button(text='Content %d' % x))\n        elif x == 1:\n            l = BoxLayout(orientation='vertical')\n            l.add_widget(Button(text=str(x), size_hint_y=None, height=35))\n            l.add_widget(Label(text='Content %d' % x))\n            item.add_widget(l)\n        else:\n            item.add_widget(Label(text='This is a big content\\n' * 20))\n        acc.add_widget(item)\n\n    def toggle_layout(*l):\n        o = acc.orientation\n        acc.orientation = 'vertical' if o == 'horizontal' else 'horizontal'\n    btn = Button(text='Toggle layout')\n    btn.bind(on_release=toggle_layout)\n\n    def select_2nd_item(*l):\n        acc.select(acc.children[-2])\n    btn2 = Button(text='Select 2nd item')\n    btn2.bind(on_release=select_2nd_item)\n\n    from kivy.uix.slider import Slider\n    slider = Slider()\n\n    def update_min_space(instance, value):\n        acc.min_space = value\n\n    slider.bind(value=update_min_space)\n\n    root = BoxLayout(spacing=20, padding=20)\n    controls = BoxLayout(orientation='vertical', size_hint_x=.3)\n    controls.add_widget(btn)\n    controls.add_widget(btn2)\n    controls.add_widget(slider)\n    root.add_widget(controls)\n    root.add_widget(acc)\n    runTouchApp(root)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/actionbar.py",
    "content": "'''\nAction Bar\n==========\n\n.. versionadded:: 1.8.0\n\n.. image:: images/actionbar.png\n    :align: right\n\nThe ActionBar widget is like Android's ActionBar, where items are stacked\nhorizontally.\n\nThe :class:`ActionBar` will contain one :class:`ActionView` and many\n:class:`ContextualActionView`\\s.\nAn :class:`ActionView` will contain an :class:`ActionPrevious` having title,\napp_icon and previous_icon properties. An :class:`ActionView` will contain\nsubclasses of :class:`ActionItem`\\s. Some predefined ones inlcude an\n:class:`ActionButton`, an :class:`ActionToggleButton`, an :class:`ActionCheck`,\nan :class:`ActionSeparator` and an :class:`ActionGroup`.\n\nAn :class:`ActionGroup` is used to display :class:`ActionItem`\\s in a group.\nAn :class:`ActionView` will always display an :class:`ActionGroup` after other\n:class:`ActionItem`\\s.\nAn :class:`ActionView` will contain an :class:`ActionOverflow`.\nA :class:`ContextualActionView` is a subclass of an :class:`ActionView`.\n'''\n\n__all__ = ('ActionBarException', 'ActionItem', 'ActionButton',\n           'ActionToggleButton', 'ActionCheck', 'ActionSeparator',\n           'ActionDropDown', 'ActionGroup', 'ActionOverflow',\n           'ActionView', 'ContextualActionView', 'ActionPrevious',\n           'ActionBar')\n\nfrom kivy.uix.boxlayout import BoxLayout\nfrom kivy.uix.dropdown import DropDown\nfrom kivy.uix.widget import Widget\nfrom kivy.uix.button import Button\nfrom kivy.uix.togglebutton import ToggleButton\nfrom kivy.uix.checkbox import CheckBox\nfrom kivy.uix.spinner import Spinner\nfrom kivy.config import Config\nfrom kivy.properties import ObjectProperty, NumericProperty, \\\n    BooleanProperty, StringProperty, ListProperty, OptionProperty\nfrom kivy.metrics import sp\nfrom kivy.lang import Builder\nfrom functools import partial\n\n\nwindow_icon = ''\nif Config:\n    window_icon = Config.get('kivy', 'window_icon')\n\n\nclass ActionBarException(Exception):\n    '''ActionBarException class\n    '''\n    pass\n\n\nclass ActionItem(object):\n    '''ActionItem class, an abstract class for all ActionBar widgets. To create\n       a custom widget for an ActionBar, inherit from this\n       class. See module documentation for more information.\n    '''\n\n    minimum_width = NumericProperty('90sp')\n    '''Minimum Width required by an ActionItem.\n\n       :attr:`minimum_width` is a :class:`~kivy.properties.NumericProperty` and\n       defaults to '90sp'.\n    '''\n\n    important = BooleanProperty(False)\n    '''Determines if an ActionItem is important or not.\n\n       :attr:`important` is a :class:`~kivy.properties.BooleanProperty` and\n       defaults to False.\n    '''\n\n    inside_group = BooleanProperty(False)\n    '''(internal) Determines if an ActionItem is displayed inside an\n       ActionGroup or not.\n\n       :attr:`inside_group` is a :class:`~kivy.properties.BooleanProperty` and\n       defaults to False.\n    '''\n\n    background_normal = StringProperty(\n        'atlas://data/images/defaulttheme/action_item')\n    '''Background image of the ActionItem used for the default graphical\n       representation when the ActionItem is not pressed.\n\n       :attr:`background_normal` is a :class:`~kivy.properties.StringProperty`\n       and defaults to 'atlas://data/images/defaulttheme/action_item'.\n    '''\n\n    background_down = StringProperty(\n        'atlas://data/images/defaulttheme/action_item_down')\n    '''Background image of the ActionItem used for default graphical\n       representation when an ActionItem is pressed.\n\n       :attr:`background_down` is a :class:`~kivy.properties.StringProperty`\n       and defaults to 'atlas://data/images/defaulttheme/action_item_down'.\n    '''\n\n    mipmap = BooleanProperty(True)\n    '''Defines whether the image/icon dispayed on top of the button uses a\n    mipmap or not.\n\n    :attr:`mipmap` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to `True`.\n    '''\n\n\nclass ActionButton(Button, ActionItem):\n    '''ActionButton class, see module documentation for more information.\n\n    The text color, width and size_hint_x are set manually via the Kv language\n    file. It covers a lot of cases: with/without an icon, with/without a group\n    and takes care of the padding between elements.\n\n    You don't have much control over these properties, so if you want to\n    customize it's appearance, we suggest you create you own button\n    representation. You can do this by creating a class that subclasses an\n    existing widget and an :class:`ActionItem`::\n\n        class MyOwnActionButton(Button, ActionItem):\n            pass\n\n    You can then create your own style using the Kv language.\n    '''\n\n    icon = StringProperty(None, allownone=True)\n    '''Source image to use when the Button is part of the ActionBar. If the\n    Button is in a group, the text will be preferred.\n    '''\n\n\nclass ActionPrevious(ActionButton):\n    '''ActionPrevious class, see module documentation for more information.\n    '''\n\n    with_previous = BooleanProperty(True)\n    '''Specifies whether clicking on ActionPrevious will load the previous\n       screen or not. If True, the previous_icon will be shown otherwise it\n       will not.\n\n       :attr:`with_previous` is a :class:`~kivy.properties.BooleanProperty` and\n       defaults to True.\n    '''\n\n    app_icon = StringProperty(window_icon)\n    '''Application icon for the ActionView.\n\n       :attr:`app_icon` is a :class:`~kivy.properties.StringProperty`\n       and defaults to the window icon if set, otherwise\n       'data/logo/kivy-icon-32.png'.\n    '''\n\n    app_icon_width = NumericProperty(0)\n    '''Width of app_icon image.\n    '''\n\n    app_icon_height = NumericProperty(0)\n    '''Height of app_icon image.\n    '''\n\n    previous_image = StringProperty(\n        'atlas://data/images/defaulttheme/previous_normal')\n    '''Image for the 'previous' ActionButtons default graphical representation.\n\n       :attr:`previous_image` is a :class:`~kivy.properties.StringProperty` and\n       defaults to 'atlas://data/images/defaulttheme/previous_normal'.\n    '''\n\n    previous_image_width = NumericProperty(0)\n    '''Width of previous_image image.\n    '''\n\n    previous_image_height = NumericProperty(0)\n    '''Height of previous_image image.\n    '''\n\n    title = StringProperty('')\n    '''Title for ActionView.\n\n       :attr:`title` is a :class:`~kivy.properties.StringProperty` and\n       defaults to ''.\n    '''\n\n    def __init__(self, **kwargs):\n        super(ActionPrevious, self).__init__(**kwargs)\n        if not self.app_icon:\n            self.app_icon = 'data/logo/kivy-icon-32.png'\n\n\nclass ActionToggleButton(ActionItem, ToggleButton):\n    '''ActionToggleButton class, see module documentation for more information.\n    '''\n\n    icon = StringProperty(None, allownone=True)\n    '''Source image to use when the Button is part of the ActionBar. If the\n    Button is in a group, the text will be preferred.\n    '''\n\n\nclass ActionCheck(ActionItem, CheckBox):\n    '''ActionCheck class, see module documentation for more information.\n    '''\n    pass\n\n\nclass ActionSeparator(ActionItem, Widget):\n    '''ActionSeparator class, see module documentation for more information.\n    '''\n\n    background_image = StringProperty(\n        'atlas://data/images/defaulttheme/separator')\n    '''Background image for the separators default graphical representation.\n\n       :attr:`background_image` is a :class:`~kivy.properties.StringProperty`\n       and defaults to 'atlas://data/images/defaulttheme/separator'.\n    '''\n\n\nclass ActionDropDown(DropDown):\n    '''ActionDropDown class, see module documentation for more information.\n    '''\n    pass\n\n\nclass ActionGroup(ActionItem, Spinner):\n    '''ActionGroup class, see module documentation for more information.\n    '''\n\n    use_separator = BooleanProperty(False)\n    '''Specifies whether to use a separator after/before this group or not.\n\n       :attr:`use_separator` is a :class:`~kivy.properties.BooleanProperty` and\n       defaults to False.\n    '''\n\n    separator_image = StringProperty(\n        'atlas://data/images/defaulttheme/separator')\n    '''Background Image for an ActionSeparator in an ActionView.\n\n       :attr:`separator_image` is a :class:`~kivy.properties.StringProperty`\n       and defaults to 'atlas://data/images/defaulttheme/separator'.\n    '''\n\n    separator_width = NumericProperty(0)\n    '''Width of the ActionSeparator in an ActionView.\n\n       :attr:`separator_width` is a :class:`~kivy.properties.NumericProperty`\n       and defaults to 0.\n    '''\n\n    mode = OptionProperty('normal', options=('normal', 'spinner'))\n    '''Sets the current mode of an ActionGroup. If mode is 'normal', the\n       ActionGroups children will be displayed normally if there is enough\n       space, otherwise they will be displayed in a spinner. If mode is\n       'spinner', then the children will always be displayed in a spinner.\n\n       :attr:`mode` is a :class:`~kivy.properties.OptionProperty` and\n       defaults to 'normal'.\n    '''\n\n    def __init__(self, **kwargs):\n        self.list_action_item = []\n        self._list_overflow_items = []\n        super(ActionGroup, self).__init__(**kwargs)\n        self.dropdown_cls = ActionDropDown\n\n    def add_widget(self, item):\n        if isinstance(item, ActionSeparator):\n            super(ActionGroup, self).add_widget(item)\n            return\n\n        if not isinstance(item, ActionItem):\n            raise ActionBarException('ActionGroup only accepts ActionItem')\n\n        self.list_action_item.append(item)\n\n    def show_group(self):\n        self.clear_widgets()\n        for item in self._list_overflow_items + self.list_action_item:\n            item.inside_group = True\n            self._dropdown.add_widget(item)\n\n    def _build_dropdown(self, *largs):\n        if self._dropdown:\n            self._dropdown.unbind(on_dismiss=self._toggle_dropdown)\n            self._dropdown.dismiss()\n            self._dropdown = None\n        self._dropdown = self.dropdown_cls()\n        self._dropdown.bind(on_dismiss=self._toggle_dropdown)\n\n    def _update_dropdown(self, *largs):\n        pass\n\n    def _toggle_dropdown(self, *largs):\n        self.is_open = not self.is_open\n        ddn = self._dropdown\n        ddn.size_hint_x = None\n        if not ddn.container:\n            return\n        children = ddn.container.children\n\n        if children:\n            ddn.width = max([self.width, children[0].minimum_width])\n        else:\n            ddn.width = self.width\n\n        for item in children:\n            item.size_hint_y = None\n            item.height = max([self.height, sp(48)])\n\n    def clear_widgets(self):\n        self._dropdown.clear_widgets()\n\n\nclass ActionOverflow(ActionGroup):\n    '''ActionOverflow class, see module documentation for more information.\n    '''\n\n    overflow_image = StringProperty(\n        'atlas://data/images/defaulttheme/overflow')\n    '''Image to be used as an Overflow Image.\n\n      :attr:`overflow_image` is an :class:`~kivy.properties.ObjectProperty` and\n       defaults to 'atlas://data/images/defaulttheme/overflow'.\n    '''\n\n    def add_widget(self, action_item, index=0):\n        if action_item is None:\n            return\n\n        if isinstance(action_item, ActionSeparator):\n            return\n\n        if not isinstance(action_item, ActionItem):\n            raise ActionBarException('ActionView only accepts ActionItem'\n                                     ' (got {!r}'.format(action_item))\n\n        else:\n            if index == 0:\n                index = len(self._list_overflow_items)\n            self._list_overflow_items.insert(index, action_item)\n\n    def show_default_items(self, parent):\n        # display overflow and it's items if widget's directly added to it\n        if self._list_overflow_items == []:\n            return\n        self.show_group()\n        super(ActionView, parent).add_widget(self)\n\n\nclass ActionView(BoxLayout):\n    '''ActionView class, see module documentation for more information.\n    '''\n\n    action_previous = ObjectProperty(None)\n    '''Previous button for an ActionView.\n\n       :attr:`action_previous` is an :class:`~kivy.properties.ObjectProperty`\n        and defaults to None.\n    '''\n\n    background_color = ListProperty([1, 1, 1, 1])\n    '''Background color in the format (r, g, b, a).\n\n       :attr:`background_color` is a :class:`~kivy.properties.ListProperty` and\n        defaults to [1, 1, 1, 1].\n    '''\n\n    background_image = StringProperty(\n        'atlas://data/images/defaulttheme/action_view')\n    '''Background image of an ActionViews default graphical representation.\n\n      :attr:`background_image` is an :class:`~kivy.properties.StringProperty`\n      and defaults to 'atlas://data/images/defaulttheme/action_view'.\n    '''\n\n    use_separator = BooleanProperty(False)\n    '''Specify whether to use a separator before every ActionGroup or not.\n\n       :attr:`use_separator` is a :class:`~kivy.properties.BooleanProperty` and\n       defaults to False.\n    '''\n\n    overflow_group = ObjectProperty(None)\n    '''Widget to be used for the overflow.\n\n       :attr:`overflow_group` is an :class:`~kivy.properties.ObjectProperty`\n       and defaults to an instance of :class:`ActionOverflow`.\n    '''\n\n    def __init__(self, **kwargs):\n        self._list_action_items = []\n        self._list_action_group = []\n        super(ActionView, self).__init__(**kwargs)\n        self._state = ''\n        if not self.overflow_group:\n            self.overflow_group = ActionOverflow(\n                use_separator=self.use_separator)\n\n    def on_action_previous(self, instance, value):\n        self._list_action_items.insert(0, value)\n\n    def add_widget(self, action_item, index=0):\n        if action_item is None:\n            return\n\n        if not isinstance(action_item, ActionItem):\n            raise ActionBarException('ActionView only accepts ActionItem'\n                                     ' (got {!r}'.format(action_item))\n\n        elif isinstance(action_item, ActionOverflow):\n            self.overflow_group = action_item\n            action_item.use_separator = self.use_separator\n\n        elif isinstance(action_item, ActionGroup):\n            self._list_action_group.append(action_item)\n            action_item.use_separator = self.use_separator\n\n        elif isinstance(action_item, ActionPrevious):\n            self.action_previous = action_item\n\n        else:\n            super(ActionView, self).add_widget(action_item, index)\n            if index == 0:\n                index = len(self._list_action_items)\n            self._list_action_items.insert(index, action_item)\n\n    def on_use_separator(self, instance, value):\n        for group in self._list_action_group:\n            group.use_separator = value\n        self.overflow_group.use_separator = value\n\n    def _clear_all(self):\n        self.clear_widgets()\n        for group in self._list_action_group:\n            group.clear_widgets()\n\n        self.overflow_group.clear_widgets()\n        self.overflow_group.list_action_item = []\n\n    def _layout_all(self):\n        # all the items can fit to the view, so expand everything\n        super_add = super(ActionView, self).add_widget\n        self._state = 'all'\n        self._clear_all()\n        super_add(self.action_previous)\n        if len(self._list_action_items) > 1:\n            for child in self._list_action_items[1:]:\n                child.inside_group = False\n                super_add(child)\n\n        for group in self._list_action_group:\n            if group.mode == 'spinner':\n                super_add(group)\n                group.show_group()\n            else:\n                if group.list_action_item != []:\n                    super_add(ActionSeparator())\n                for child in group.list_action_item:\n                    child.inside_group = False\n                    super_add(child)\n\n        self.overflow_group.show_default_items(self)\n\n    def _layout_group(self):\n        # layout all the items in order to pack them per group\n        super_add = super(ActionView, self).add_widget\n        self._state = 'group'\n        self._clear_all()\n        super_add(self.action_previous)\n        if len(self._list_action_items) > 1:\n            for child in self._list_action_items[1:]:\n                super_add(child)\n                child.inside_group = False\n\n        for group in self._list_action_group:\n            super_add(group)\n            group.show_group()\n\n        self.overflow_group.show_default_items(self)\n\n    def _layout_random(self):\n        # layout the items in order to pack all of them grouped, and display\n        # only the action items having 'important'\n        super_add = super(ActionView, self).add_widget\n        self._state = 'random'\n        self._clear_all()\n        hidden_items = []\n        hidden_groups = []\n        total_width = 0\n        super_add(self.action_previous)\n\n        width = (self.width - self.overflow_group.minimum_width -\n                 self.action_previous.minimum_width)\n\n        if len(self._list_action_items):\n            for child in self._list_action_items[1:]:\n                if child.important:\n                    if child.minimum_width + total_width < width:\n                        super_add(child)\n                        child.inside_group = False\n                        total_width += child.minimum_width\n                    else:\n                        hidden_items.append(child)\n                else:\n                    hidden_items.append(child)\n\n        # if space is left then display ActionItem inside their\n        # ActionGroup\n        if total_width < self.width:\n            for group in self._list_action_group:\n                if group.minimum_width + total_width +\\\n                   group.separator_width < width:\n                    super_add(group)\n                    group.show_group()\n                    total_width += (group.minimum_width +\n                                    group.separator_width)\n\n                else:\n                    hidden_groups.append(group)\n\n        group_index = len(self.children) - 1\n        # if space is left then display other ActionItems\n        if total_width < self.width:\n            for child in hidden_items[:]:\n                if child.minimum_width + total_width < width:\n                    super_add(child, group_index)\n                    total_width += child.minimum_width\n                    child.inside_group = False\n                    hidden_items.remove(child)\n\n        # for all the remaining ActionItems and ActionItems with in\n        # ActionGroups, Display them inside overflow_group\n        extend_hidden = hidden_items.extend\n        for group in hidden_groups:\n            extend_hidden(group.list_action_item)\n\n        overflow_group = self.overflow_group\n\n        if hidden_items != []:\n            over_add = super(overflow_group.__class__,\n                             overflow_group).add_widget\n            for child in hidden_items:\n                over_add(child)\n\n            overflow_group.show_group()\n            super_add(overflow_group)\n\n    def on_width(self, width, *args):\n        # determine the layout to use\n\n        # can we display all of them?\n        total_width = 0\n        for child in self._list_action_items:\n            total_width += child.minimum_width\n        for group in self._list_action_group:\n            for child in group.list_action_item:\n                total_width += child.minimum_width\n        if total_width <= self.width:\n            if self._state != 'all':\n                self._layout_all()\n            return\n\n        # can we display them per group?\n        total_width = 0\n        for child in self._list_action_items:\n            total_width += child.minimum_width\n        for group in self._list_action_group:\n            total_width += group.minimum_width\n        if total_width < self.width:\n            # ok, we can display all the items grouped\n            if self._state != 'group':\n                self._layout_group()\n            return\n\n        # none of the solutions worked, display them in pack mode\n        self._layout_random()\n\n\nclass ContextualActionView(ActionView):\n    '''ContextualActionView class, see the module documentation\n       for more information.\n    '''\n    pass\n\n\nclass ActionBar(BoxLayout):\n    '''ActionBar, see the module documentation for more information.\n\n    :Events:\n        `on_previous`\n            Fired when action_previous of action_view is pressed.\n    '''\n\n    action_view = ObjectProperty(None)\n    '''action_view of ActionBar.\n\n       :attr:`action_view` is an :class:`~kivy.properties.ObjectProperty` and\n       defaults to an instance of ActionView.\n    '''\n\n    background_color = ListProperty([1, 1, 1, 1])\n    '''Background color, in the format (r, g, b, a).\n\n       :attr:`background_color` is a :class:`~kivy.properties.ListProperty` and\n        defaults to [1, 1, 1, 1].\n    '''\n\n    background_image = StringProperty(\n        'atlas://data/images/defaulttheme/action_bar')\n\n    '''Background image of the ActionBars default graphical representation.\n\n      :attr:`background_image` is an :class:`~kivy.properties.StringProperty`\n      and defaults to 'atlas://data/images/defaulttheme/action_bar'.\n    '''\n\n    border = ListProperty([2, 2, 2, 2])\n    ''':attr:`border` to be applied to the :attr:`background_image`.\n    '''\n\n    __events__ = ('on_previous',)\n\n    def __init__(self, **kwargs):\n        super(ActionBar, self).__init__(**kwargs)\n        self._stack_cont_action_view = []\n        self._emit_previous = partial(self.dispatch, 'on_previous')\n\n    def add_widget(self, view):\n        if isinstance(view, ContextualActionView):\n            self._stack_cont_action_view.append(view)\n            if view.action_previous is not None:\n                view.action_previous.unbind(on_release=self._emit_previous)\n                view.action_previous.bind(on_release=self._emit_previous)\n            self.clear_widgets()\n            super(ActionBar, self).add_widget(view)\n\n        elif isinstance(view, ActionView):\n            self.action_view = view\n            super(ActionBar, self).add_widget(view)\n\n        else:\n            raise ActionBarException(\n                'ActionBar can only add ContextualActionView or ActionView')\n\n    def on_previous(self, *args):\n        self._pop_contextual_action_view()\n\n    def _pop_contextual_action_view(self):\n        '''Remove the current ContextualActionView and display either the\n           previous one or the ActionView.\n        '''\n        self._stack_cont_action_view.pop()\n        self.clear_widgets()\n        if self._stack_cont_action_view == []:\n            super(ActionBar, self).add_widget(self.action_view)\n        else:\n            super(ActionBar, self).add_widget(self._stack_cont_action_view[-1])\n\n\nif __name__ == \"__main__\":\n    from kivy.base import runTouchApp\n    from kivy.uix.floatlayout import FloatLayout\n    from kivy.factory import Factory\n\n    # XXX clean the first registration done from '__main__' here.\n    # otherwise kivy.uix.actionbar.ActionPrevious != __main__.ActionPrevious\n    Factory.unregister('ActionPrevious')\n\n    Builder.load_string('''\n<MainWindow>:\n    ActionBar:\n        pos_hint: {'top':1}\n        ActionView:\n            use_separator: True\n            ActionPrevious:\n                title: 'Action Bar'\n                with_previous: False\n            ActionOverflow:\n            ActionButton:\n                text: 'Btn0'\n                icon: 'atlas://data/images/defaulttheme/audio-volume-high'\n            ActionButton:\n                text: 'Btn1'\n            ActionButton:\n                text: 'Btn2'\n            ActionGroup:\n                text: 'Group 2'\n                ActionButton:\n                    text: 'Btn3'\n                ActionButton:\n                    text: 'Btn4'\n            ActionGroup:\n                text: 'Group1'\n                ActionButton:\n                    text: 'Btn5'\n                ActionButton:\n                    text: 'Btn6'\n                ActionButton:\n                    text: 'Btn7'\n''')\n\n    class MainWindow(FloatLayout):\n        pass\n\n    float_layout = MainWindow()\n    runTouchApp(float_layout)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/anchorlayout.py",
    "content": "'''\nAnchor Layout\n=============\n\n.. only:: html\n\n    .. image:: images/anchorlayout.gif\n        :align: right\n\n.. only:: latex\n\n    .. image:: images/anchorlayout.png\n        :align: right\n\nThe :class:`AnchorLayout` aligns its children to a border (top, bottom,\nleft, right) or center.\n\n\nTo draw a button in the lower-right corner::\n\n    layout = AnchorLayout(\n        anchor_x='right', anchor_y='bottom')\n    btn = Button(text='Hello World')\n    layout.add_widget(btn)\n\n'''\n\n__all__ = ('AnchorLayout', )\n\nfrom kivy.uix.layout import Layout\nfrom kivy.properties import OptionProperty, VariableListProperty\n\n\nclass AnchorLayout(Layout):\n    '''Anchor layout class. See the module documentation for more information.\n    '''\n\n    padding = VariableListProperty([0, 0, 0, 0])\n    '''Padding between the widget box and its children, in pixels:\n    [padding_left, padding_top, padding_right, padding_bottom].\n\n    padding also accepts a two argument form [padding_horizontal,\n    padding_vertical] and a one argument form [padding].\n\n    :attr:`padding` is a :class:`~kivy.properties.VariableListProperty` and\n    defaults to [0, 0, 0, 0].\n    '''\n\n    anchor_x = OptionProperty('center', options=(\n        'left', 'center', 'right'))\n    '''Horizontal anchor.\n\n    :attr:`anchor_x` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to 'center'. It accepts values of 'left', 'center' or\n    'right'.\n    '''\n\n    anchor_y = OptionProperty('center', options=(\n        'top', 'center', 'bottom'))\n    '''Vertical anchor.\n\n    :attr:`anchor_y` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to 'center'. It accepts values of 'top', 'center' or\n    'bottom'.\n    '''\n\n    def __init__(self, **kwargs):\n        super(AnchorLayout, self).__init__(**kwargs)\n        self.bind(\n            children=self._trigger_layout,\n            parent=self._trigger_layout,\n            padding=self._trigger_layout,\n            anchor_x=self._trigger_layout,\n            anchor_y=self._trigger_layout,\n            size=self._trigger_layout,\n            pos=self._trigger_layout)\n\n    def do_layout(self, *largs):\n        _x, _y = self.pos\n        width = self.width\n        height = self.height\n        anchor_x = self.anchor_x\n        anchor_y = self.anchor_y\n        padding = self.padding\n\n        for c in self.children:\n            x, y = _x, _y\n            w, h = c.size\n            if c.size_hint[0] is not None:\n                w = c.size_hint[0] * width - (padding[0] + padding[2])\n            if c.size_hint[1] is not None:\n                h = c.size_hint[1] * height - (padding[1] + padding[3])\n\n            if anchor_x == 'left':\n                x = x + padding[0]\n            if anchor_x == 'right':\n                x = x + width - (w + padding[2])\n            if self.anchor_x == 'center':\n                x = x + (width / 2) - (w / 2)\n            if anchor_y == 'bottom':\n                y = y + padding[1]\n            if anchor_y == 'top':\n                y = y + height - (h + padding[3])\n            if anchor_y == 'center':\n                y = y + (height / 2) - (h / 2)\n\n            c.x = x\n            c.y = y\n            c.width = w\n            c.height = h\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/behaviors.py",
    "content": "'''\nBehaviors\n=========\n\n.. versionadded:: 1.8.0\n\nThis module implements behaviors that can be mixed with existing base widgets.\nFor example, if you want to add a \"button\" capability to an `Image`, you could\ndo::\n\n\n    class IconButton(ButtonBehavior, Image):\n        pass\n\n.. note::\n\n    The behavior class must always be _before_ the widget class. If you don't\n    specify the inheritance in this order, the behavior will not work because\n    the behavior methods are overwritten by the class method listed first.\n\n    Similarly, if you combine a behavior class with a class which\n    requires the use of the methods also defined by the behavior class, the\n    resulting class may not function properly. E.g. combining a ButtonBehavior\n    with a Slider, both of which require the on_touch_up methods, the resulting\n    class will not work.\n\n'''\n\n__all__ = ('ButtonBehavior', 'ToggleButtonBehavior', 'DragBehavior',\n           'FocusBehavior', 'CompoundSelectionBehavior')\n\nfrom kivy.clock import Clock\nfrom kivy.properties import OptionProperty, ObjectProperty, NumericProperty,\\\n    ReferenceListProperty, BooleanProperty, ListProperty, AliasProperty\nfrom kivy.config import Config\nfrom kivy.metrics import sp\nfrom kivy.base import EventLoop\nfrom kivy.logger import Logger\nfrom functools import partial\nfrom weakref import ref\nfrom time import time\nimport string\n\n# When we are generating documentation, Config doesn't exist\n_scroll_timeout = _scroll_distance = 0\n_is_desktop = False\n_keyboard_mode = 'system'\nif Config:\n    _scroll_timeout = Config.getint('widgets', 'scroll_timeout')\n    _scroll_distance = Config.getint('widgets', 'scroll_distance')\n    _is_desktop = Config.getboolean('kivy', 'desktop')\n    _keyboard_mode = Config.get('kivy', 'keyboard_mode')\n\n\nclass ButtonBehavior(object):\n    '''Button behavior.\n\n    :Events:\n        `on_press`\n            Fired when the button is pressed.\n        `on_release`\n            Fired when the button is released (i.e. the touch/click that\n            pressed the button goes away).\n    '''\n\n    state = OptionProperty('normal', options=('normal', 'down'))\n    '''State of the button, must be one of 'normal' or 'down'.\n    The state is 'down' only when the button is currently touched/clicked,\n    otherwise 'normal'.\n\n    :attr:`state` is an :class:`~kivy.properties.OptionProperty`.\n    '''\n\n    last_touch = ObjectProperty(None)\n    '''Contains the last relevant touch received by the Button. This can\n    be used in `on_press` or `on_release` in order to know which touch\n    dispatched the event.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`last_touch` is a :class:`~kivy.properties.ObjectProperty`,\n    defaults to None.\n    '''\n\n    MIN_STATE_TIME = 0.035\n    '''The minimum period of time which the widget must remain in the\n    `'down'` state.\n\n    :attr:`MIN_STATE_TIME` is a float.\n    '''\n\n    always_release = BooleanProperty(True)\n    '''This determines if the widget fires a `on_release` event if\n    the touch_up is outside the widget.\n\n    ..versionadded:: 1.9.0\n\n    :attr:`always_release` is a :class:`~kivy.properties.BooleanProperty`,\n    defaults to `True`.\n    '''\n\n    def __init__(self, **kwargs):\n        self.register_event_type('on_press')\n        self.register_event_type('on_release')\n        super(ButtonBehavior, self).__init__(**kwargs)\n        self.__state_event = None\n        self.__touch_time = None\n        self.bind(state=self.cancel_event)\n\n    def _do_press(self):\n        self.state = 'down'\n\n    def _do_release(self, *args):\n        self.state = 'normal'\n\n    def cancel_event(self, *args):\n        if self.__state_event:\n            self.__state_event.cancel()\n            self.__state_event = None\n\n    def on_touch_down(self, touch):\n        if super(ButtonBehavior, self).on_touch_down(touch):\n            return True\n        if touch.is_mouse_scrolling:\n            return False\n        if not self.collide_point(touch.x, touch.y):\n            return False\n        if self in touch.ud:\n            return False\n        touch.grab(self)\n        touch.ud[self] = True\n        self.last_touch = touch\n        self.__touch_time = time()\n        self._do_press()\n        self.dispatch('on_press')\n        return True\n\n    def on_touch_move(self, touch):\n        if touch.grab_current is self:\n            return True\n        if super(ButtonBehavior, self).on_touch_move(touch):\n            return True\n        return self in touch.ud\n\n    def on_touch_up(self, touch):\n        if touch.grab_current is not self:\n            return super(ButtonBehavior, self).on_touch_up(touch)\n        assert(self in touch.ud)\n        touch.ungrab(self)\n        self.last_touch = touch\n\n        if (not self.always_release\n                and not self.collide_point(*touch.pos)):\n            self.state = 'normal'\n            return\n\n        touchtime = time() - self.__touch_time\n        if touchtime < self.MIN_STATE_TIME:\n            self.__state_event = Clock.schedule_once(\n                self._do_release, self.MIN_STATE_TIME - touchtime)\n        else:\n            self._do_release()\n        self.dispatch('on_release')\n        return True\n\n    def on_press(self):\n        pass\n\n    def on_release(self):\n        pass\n\n    def trigger_action(self, duration=0.1):\n        '''Trigger whatever action(s) have been bound to the button by calling\n        both the on_press and on_release callbacks.\n\n        This simulates a quick button press without using any touch events.\n\n        Duration is the length of the press in seconds. Pass 0 if you want\n        the action to happen instantly.\n\n        .. versionadded:: 1.8.0\n        '''\n        self._do_press()\n        self.dispatch('on_press')\n\n        def trigger_release(dt):\n            self._do_release()\n            self.dispatch('on_release')\n        if not duration:\n            trigger_release(0)\n        else:\n            Clock.schedule_once(trigger_release, duration)\n\n\nclass ToggleButtonBehavior(ButtonBehavior):\n    '''ToggleButton behavior, see ToggleButton module documentation for more\n    information.\n\n    .. versionadded:: 1.8.0\n    '''\n\n    __groups = {}\n\n    group = ObjectProperty(None, allownone=True)\n    '''Group of the button. If None, no group will be used (button is\n    independent). If specified, :attr:`group` must be a hashable object, like\n    a string. Only one button in a group can be in 'down' state.\n\n    :attr:`group` is a :class:`~kivy.properties.ObjectProperty`\n    '''\n\n    allow_no_selection = BooleanProperty(True)\n    '''This specifies whether the checkbox in group allows everything to\n    be deselected.\n\n    ..versionadded::1.9.0\n\n    :attr:`allow_no_selection` is a :class:`BooleanProperty` defaults to\n    `True`\n    '''\n\n    def __init__(self, **kwargs):\n        self._previous_group = None\n        super(ToggleButtonBehavior, self).__init__(**kwargs)\n\n    def on_group(self, *largs):\n        groups = ToggleButtonBehavior.__groups\n        if self._previous_group:\n            group = groups[self._previous_group]\n            for item in group[:]:\n                if item() is self:\n                    group.remove(item)\n                    break\n        group = self._previous_group = self.group\n        if group not in groups:\n            groups[group] = []\n        r = ref(self, ToggleButtonBehavior._clear_groups)\n        groups[group].append(r)\n\n    def _release_group(self, current):\n        if self.group is None:\n            return\n        group = self.__groups[self.group]\n        for item in group[:]:\n            widget = item()\n            if widget is None:\n                group.remove(item)\n            if widget is current:\n                continue\n            widget.state = 'normal'\n\n    def _do_press(self):\n        if (not self.allow_no_selection and\n            self.group and self.state == 'down'):\n            return\n        self._release_group(self)\n        self.state = 'normal' if self.state == 'down' else 'down'\n\n    def _do_release(self, *args):\n        pass\n\n    @staticmethod\n    def _clear_groups(wk):\n        # auto flush the element when the weak reference have been deleted\n        groups = ToggleButtonBehavior.__groups\n        for group in list(groups.values()):\n            if wk in group:\n                group.remove(wk)\n                break\n\n    @staticmethod\n    def get_widgets(groupname):\n        '''Return the widgets contained in a specific group. If the group\n        doesn't exist, an empty list will be returned.\n\n        .. important::\n\n            Always release the result of this method! In doubt, do::\n\n                l = ToggleButtonBehavior.get_widgets('mygroup')\n                # do your job\n                del l\n\n        .. warning::\n\n            It's possible that some widgets that you have previously\n            deleted are still in the list. Garbage collector might need\n            more elements before flushing it. The return of this method\n            is informative, you've been warned!\n        '''\n        groups = ToggleButtonBehavior.__groups\n        if groupname not in groups:\n            return []\n        return [x() for x in groups[groupname] if x()][:]\n\n\nclass DragBehavior(object):\n    '''Drag behavior. When combined with a widget, dragging in the rectangle\n    defined by :attr:`drag_rectangle` will drag the widget.\n\n    For example, to make a popup which is draggable by its title do::\n\n        from kivy.uix.behaviors import DragBehavior\n        from kivy.uix.popup import Popup\n\n        class DragPopup(DragBehavior, Popup):\n            pass\n\n    And in .kv do::\n        <DragPopup>:\n            drag_rectangle: self.x, self.y+self._container.height, self.width,\\\n            self.height - self._container.height\n            drag_timeout: 10000000\n            drag_distance: 0\n\n    .. versionadded:: 1.8.0\n    '''\n\n    drag_distance = NumericProperty(_scroll_distance)\n    '''Distance to move before dragging the :class:`DragBehavior`, in pixels.\n    As soon as the distance has been traveled, the :class:`DragBehavior` will\n    start to drag, and no touch event will go to children.\n    It is advisable that you base this value on the dpi of your target device's\n    screen.\n\n    :attr:`drag_distance` is a :class:`~kivy.properties.NumericProperty`,\n    defaults to 20 (pixels), according to the default value of scroll_distance\n    in user configuration.\n    '''\n\n    drag_timeout = NumericProperty(_scroll_timeout)\n    '''Timeout allowed to trigger the :attr:`drag_distance`, in milliseconds.\n    If the user has not moved :attr:`drag_distance` within the timeout,\n    dragging will be disabled, and the touch event will go to the children.\n\n    :attr:`drag_timeout` is a :class:`~kivy.properties.NumericProperty`,\n    defaults to 55 (milliseconds), according to the default value of\n    scroll_timeout in user configuration.\n    '''\n\n    drag_rect_x = NumericProperty(0)\n    '''X position of the axis aligned bounding rectangle where dragging\n    is allowed. In window coordinates.\n\n    :attr:`drag_rect_x` is a :class:`~kivy.properties.NumericProperty`,\n    defaults to 0.\n    '''\n\n    drag_rect_y = NumericProperty(0)\n    '''Y position of the axis aligned bounding rectangle where dragging\n    is allowed. In window coordinates.\n\n    :attr:`drag_rect_Y` is a :class:`~kivy.properties.NumericProperty`,\n    defaults to 0.\n    '''\n\n    drag_rect_width = NumericProperty(100)\n    '''Width of the axis aligned bounding rectangle where dragging is allowed.\n\n    :attr:`drag_rect_width` is a :class:`~kivy.properties.NumericProperty`,\n    defaults to 100.\n    '''\n\n    drag_rect_height = NumericProperty(100)\n    '''Height of the axis aligned bounding rectangle where dragging is allowed.\n\n    :attr:`drag_rect_height` is a :class:`~kivy.properties.NumericProperty`,\n    defaults to 100.\n    '''\n\n    drag_rectangle = ReferenceListProperty(drag_rect_x, drag_rect_y,\n                                           drag_rect_width, drag_rect_height)\n    '''Position and size of the axis aligned bounding rectangle where dragging\n    is allowed.\n\n    :attr:`drag_rectangle` is a :class:`~kivy.properties.ReferenceListProperty`\n    of (:attr:`drag_rect_x`, :attr:`drag_rect_y`, :attr:`drag_rect_width`,\n    :attr:`drag_rect_height`) properties.\n    '''\n\n    def __init__(self, **kwargs):\n        self._drag_touch = None\n        super(DragBehavior, self).__init__(**kwargs)\n\n    def _get_uid(self, prefix='sv'):\n        return '{0}.{1}'.format(prefix, self.uid)\n\n    def on_touch_down(self, touch):\n        xx, yy, w, h = self.drag_rectangle\n        x, y = touch.pos\n        if not self.collide_point(x, y):\n            touch.ud[self._get_uid('svavoid')] = True\n            return super(DragBehavior, self).on_touch_down(touch)\n        if self._drag_touch or ('button' in touch.profile and\n                                touch.button.startswith('scroll')) or\\\n                not ((xx < x <= xx + w) and (yy < y <= yy + h)):\n            return super(DragBehavior, self).on_touch_down(touch)\n\n        # no mouse scrolling, so the user is going to drag with this touch.\n        self._drag_touch = touch\n        uid = self._get_uid()\n        touch.grab(self)\n        touch.ud[uid] = {\n            'mode': 'unknown',\n            'dx': 0,\n            'dy': 0}\n        Clock.schedule_once(self._change_touch_mode,\n                            self.drag_timeout / 1000.)\n        return True\n\n    def on_touch_move(self, touch):\n        if self._get_uid('svavoid') in touch.ud or\\\n                self._drag_touch is not touch:\n            return super(DragBehavior, self).on_touch_move(touch) or\\\n                self._get_uid() in touch.ud\n        if touch.grab_current is not self:\n            return True\n\n        uid = self._get_uid()\n        ud = touch.ud[uid]\n        mode = ud['mode']\n        if mode == 'unknown':\n            ud['dx'] += abs(touch.dx)\n            ud['dy'] += abs(touch.dy)\n            if ud['dx'] > sp(self.drag_distance):\n                mode = 'drag'\n            if ud['dy'] > sp(self.drag_distance):\n                mode = 'drag'\n            ud['mode'] = mode\n        if mode == 'drag':\n            self.x += touch.dx\n            self.y += touch.dy\n        return True\n\n    def on_touch_up(self, touch):\n        if self._get_uid('svavoid') in touch.ud:\n            return super(DragBehavior, self).on_touch_up(touch)\n\n        if self._drag_touch and self in [x() for x in touch.grab_list]:\n            touch.ungrab(self)\n            self._drag_touch = None\n            ud = touch.ud[self._get_uid()]\n            if ud['mode'] == 'unknown':\n                super(DragBehavior, self).on_touch_down(touch)\n                Clock.schedule_once(partial(self._do_touch_up, touch), .1)\n        else:\n            if self._drag_touch is not touch:\n                super(DragBehavior, self).on_touch_up(touch)\n        return self._get_uid() in touch.ud\n\n    def _do_touch_up(self, touch, *largs):\n        super(DragBehavior, self).on_touch_up(touch)\n        # don't forget about grab event!\n        for x in touch.grab_list[:]:\n            touch.grab_list.remove(x)\n            x = x()\n            if not x:\n                continue\n            touch.grab_current = x\n            super(DragBehavior, self).on_touch_up(touch)\n        touch.grab_current = None\n\n    def _change_touch_mode(self, *largs):\n        if not self._drag_touch:\n            return\n        uid = self._get_uid()\n        touch = self._drag_touch\n        ud = touch.ud[uid]\n        if ud['mode'] != 'unknown':\n            return\n        touch.ungrab(self)\n        self._drag_touch = None\n        super(DragBehavior, self).on_touch_down(touch)\n        return\n\n\nclass FocusBehavior(object):\n    '''Implements keyboard focus behavior. When combined with other\n    FocusBehavior widgets it allows one to cycle focus among them by pressing\n    tab. In addition, upon gaining focus the instance will automatically\n    receive keyboard input.\n\n    Focus, very different then selection, is intimately tied with the keyboard;\n    each keyboard can focus on zero or one widgets, and each widget can only\n    have the focus of one keyboard. However, multiple keyboards can focus\n    simultaneously on different widgets. When escape is hit, the widget having\n    the focus of that keyboard will de-focus.\n\n    In essence, focus is implemented as a doubly linked list, where each\n    node holds a (weak) reference to the instance before it and after it,\n    as visualized when cycling through the nodes using tab (forward) or\n    shift+tab (backward). If previous or next widget is not specified,\n    :attr:`focus_next` and :attr:`focus_previous` defaults to `None`,\n    which means that the children list and parents are walked to find\n    the next focusable widget, unless :attr:`focus_next` or\n    :attr:`focus_previous` is set to the `StopIteration` class, in which case\n    focus stops there.\n\n    For example, to cycle focus between :class:`~kivy.uix.button.Button`\n    elements of a :class:`~kivy.uix.gridlayout.GridLayout`::\n\n        class FocusButton(FocusBehavior, Button):\n            pass\n\n        grid = GridLayout(cols=4)\n        for i in range(40):\n            grid.add_widget(FocusButton(text=str(i)))\n        # clicking on a widget will activate focus, and tab can now be used\n        # to cycle through\n\n\n    .. versionadded:: 1.9.0\n\n    .. warning::\n\n        This code is still experimental, and its API is subject to change in a\n        future version.\n    '''\n\n    _requested_keyboard = False\n    _keyboard = ObjectProperty(None, allownone=True)\n    _keyboards = {}\n\n    ignored_touch = []\n    '''A list of touches that should not be used to defocus. After on_touch_up,\n    every touch that is not in :attr:`ignored_touch` will defocus all the\n    focused widgets, if, the config keyboard mode is not multi. Touches on\n    focusable widgets that were used to focus are automatically added here.\n\n    Example usage::\n\n        class Unfocusable(Widget):\n\n            def on_touch_down(self, touch):\n                if self.collide_point(*touch.pos):\n                    FocusBehavior.ignored_touch.append(touch)\n\n    Notice that you need to access this as class, not instance variable.\n    '''\n\n    def _set_keyboard(self, value):\n        focus = self.focus\n        keyboard = self._keyboard\n        keyboards = FocusBehavior._keyboards\n        if keyboard:\n            self.focus = False    # this'll unbind\n            if self._keyboard:  # remove assigned keyboard from dict\n                del keyboards[keyboard]\n        if value and not value in keyboards:\n            keyboards[value] = None\n        self._keyboard = value\n        self.focus = focus\n\n    def _get_keyboard(self):\n        return self._keyboard\n    keyboard = AliasProperty(_get_keyboard, _set_keyboard,\n                             bind=('_keyboard', ))\n    '''The keyboard to bind, or bound to the widget when focused.\n\n    When None, a keyboard is requested and released whenever the widget comes\n    into and out of focus. If not None, it must be a keyboard, which gets\n    bound and unbound from the widget whenever it's in or out of focus. It is\n    useful only when more than one keyboard is available, so it is recommended\n    to be set to None when only one keyboard is available\n\n    If more than one keyboard is available, whenever an instance get focused\n    a new keyboard will be requested if None. Unless, the other instances lose\n    focus (e.g. if tab was used), a new keyboard will appear. When this is\n    undesired, the keyboard property can be used. For example, if there are\n    two users with two keyboards, then each keyboard can be assigned to\n    different groups of instances of FocusBehavior, ensuring that within\n    each group, only one FocusBehavior will have focus, and will receive input\n    from the correct keyboard. see `keyboard_mode` in :mod:`~kivy.config` for\n    information on the keyboard modes.\n\n    :attr:`keyboard` is a :class:`~kivy.properties.AliasProperty`, defaults to\n    None.\n\n    .. note::\n\n        When Config's `keyboard_mode` is multi, each new touch is considered\n        a touch by a different user and will focus (if clicked on a\n        focusable) with a new keyboard. Already focused elements will not lose\n        their focus (even if clicked on a unfocusable).\n\n    .. note:\n\n        If the keyboard property is set, that keyboard will be used when the\n        instance gets focused. If widgets with different keyboards are linked\n        through :attr:`focus_next` and :attr:`focus_previous`, then as they are\n        tabbed through, different keyboards will become active. Therefore,\n        typically it's undesirable to link instances which are assigned\n        different keyboards.\n\n    .. note:\n\n        When an instance has focus, setting keyboard to None will remove the\n        current keyboard, but will then try to get a keyboard back. It is\n        better to set :attr:`focus` to False.\n\n    .. warning:\n\n        When assigning a keyboard, the keyboard must not be released while\n        it is still assigned to an instance. Similarly, the keyboard created\n        by the instance on focus and assigned to :attr:`keyboard` if None,\n        will be released by the instance when the instance loses focus.\n        Therefore, it is not safe to assign this keyboard to another instance's\n        :attr:`keyboard`.\n    '''\n\n    is_focusable = BooleanProperty(_is_desktop)\n    '''Whether the instance can become focused. If focused, it'll lose focus\n    when set to False.\n\n    :attr:`is_focusable` is a :class:`~kivy.properties.BooleanProperty`,\n    defaults to True on a desktop (i.e. desktop is True in\n    :mod:`~kivy.config`), False otherwise.\n    '''\n\n    focus = BooleanProperty(False)\n    '''Whether the instance currently has focus.\n\n    Setting it to True, will bind to and/or request the keyboard, and input\n    will be forwarded to the instance. Setting it to False, will unbind\n    and/or release the keyboard. For a given keyboard, only one widget can\n    have its focus, so focusing one will automatically unfocus the other\n    instance holding its focus.\n\n    :attr:`focus` is a :class:`~kivy.properties.BooleanProperty`, defaults to\n    False.\n    '''\n\n    focused = focus\n    '''An alias of :attr:`focus`.\n\n    :attr:`focused` is a :class:`~kivy.properties.BooleanProperty`, defaults to\n    False.\n\n    .. warning::\n        :attr:`focused` is an alias of :attr:`focus` and will be removed in\n        2.0.0.\n    '''\n\n    def _set_on_focus_next(self, instance, value):\n        ''' If changing code, ensure following code is not infinite loop:\n        widget.focus_next = widget\n        widget.focus_previous = widget\n        widget.focus_previous = widget2\n        '''\n        next = self._old_focus_next\n        if next is value:   # prevent infinite loop\n            return\n\n        if isinstance(next, FocusBehavior):\n            next.focus_previous = None\n        self._old_focus_next = value\n        if value is None or value is StopIteration:\n            return\n        if not isinstance(value, FocusBehavior):\n            raise ValueError('focus_next accepts only objects based'\n                             ' on FocusBehavior, or the StopIteration class.')\n        value.focus_previous = self\n\n    focus_next = ObjectProperty(None, allownone=True)\n    '''The :class:`FocusBehavior` instance to acquire focus when\n    tab is pressed when this instance has focus, if not `None` or\n    `'StopIteration'`.\n\n    When tab is pressed, focus cycles through all the :class:`FocusBehavior`\n    widgets that are linked through :attr:`focus_next` and are focusable. If\n    :attr:`focus_next` is `None`, it instead walks the children lists to find\n    the next focusable widget. Finally, if :attr:`focus_next` is\n    the `StopIteration` class, focus won't move forward, but end here.\n\n    .. note:\n\n        Setting :attr:`focus_next` automatically sets :attr:`focus_previous`\n        of the other instance to point to this instance, if not None or\n        `StopIteration`. Similarly, if it wasn't None or `StopIteration`, it\n        also sets the :attr:`focus_previous` property of the instance\n        previously in :attr:`focus_next` to `None`. Therefore, it is only\n        required to set one side of the :attr:`focus_previous`,\n        :attr:`focus_next`, links since the other side will be set\n        automatically.\n\n    :attr:`focus_next` is a :class:`~kivy.properties.ObjectProperty`, defaults\n    to `None`.\n    '''\n\n    def _set_on_focus_previous(self, instance, value):\n        prev = self._old_focus_previous\n        if prev is value:\n            return\n\n        if isinstance(prev, FocusBehavior):\n            prev.focus_next = None\n        self._old_focus_previous = value\n        if value is None or value is StopIteration:\n            return\n        if not isinstance(value, FocusBehavior):\n            raise ValueError('focus_previous accepts only objects based'\n                             ' on FocusBehavior, or the StopIteration class.')\n        value.focus_next = self\n\n    focus_previous = ObjectProperty(None, allownone=True)\n    '''The :class:`FocusBehavior` instance to acquire focus when\n    shift+tab is pressed on this instance, if not None or `StopIteration`.\n\n    When shift+tab is pressed, focus cycles through all the\n    :class:`FocusBehavior` widgets that are linked through\n    :attr:`focus_previous` and are focusable. If :attr:`focus_previous` is\n    `None', it instead walks the children tree to find the\n    previous focusable widget. Finally, if :attr:`focus_previous` is the\n    `StopIteration` class, focus won't move backward, but end here.\n\n    .. note:\n\n        Setting :attr:`focus_previous` automatically sets :attr:`focus_next`\n        of the other instance to point to this instance, if not None or\n        `StopIteration`. Similarly, if it wasn't None or `StopIteration`, it\n        also sets the :attr:`focus_next` property of the instance previously in\n        :attr:`focus_previous` to `None`. Therefore, it is only required\n        to set one side of the :attr:`focus_previous`, :attr:`focus_next`,\n        links since the other side will be set automatically.\n\n    :attr:`focus_previous` is a :class:`~kivy.properties.ObjectProperty`,\n    defaults to  `None`.\n    '''\n\n    keyboard_mode = OptionProperty('auto', options=('auto', 'managed'))\n    '''How the keyboard visibility should be managed (auto will have standard\n    behaviour to show/hide on focus, managed requires setting keyboard_visible\n    manually, or calling the helper functions ``show_keyboard()``\n    and ``hide_keyboard()``.\n\n    :attr:`keyboard_mode` is an :class:`~kivy.properties.OptionsProperty` and\n    defaults to 'auto'. Can be one of 'auto' or 'managed'.\n    '''\n\n    input_type = OptionProperty('text', options=('text', 'number', 'url',\n                                                 'mail', 'datetime', 'tel',\n                                                 'address'))\n    '''The kind of input keyboard to request.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`input_type` is an :class:`~kivy.properties.OptionsProperty` and\n    defaults to 'text'. Can be one of 'text', 'number', 'url', 'mail',\n    'datetime', 'tel', 'address'.\n    '''\n\n    unfocus_on_touch = BooleanProperty(_keyboard_mode not in\n                                       ('multi', 'systemandmulti'))\n    '''Whether a instance should lose focus when clicked outside the instance.\n\n    When a user clicks on a widget that is focus aware and shares the same\n    keyboard as the this widget (which in the case of only one keyboard, are\n    all focus aware widgets), then as the other widgets gains focus, this\n    widget loses focus. In addition to that, if this property is `True`,\n    clicking on any widget other than this widget, will remove focus form this\n    widget.\n\n    :attr:`unfocus_on_touch` is a :class:`~kivy.properties.BooleanProperty`,\n    defaults to `False` if the `keyboard_mode` in :attr:`~kivy.config.Config`\n    is `'multi'` or `'systemandmulti'`, otherwise it defaults to `True`.\n    '''\n\n    def __init__(self, **kwargs):\n        self._old_focus_next = None\n        self._old_focus_previous = None\n        super(FocusBehavior, self).__init__(**kwargs)\n\n        self._keyboard_mode = _keyboard_mode\n        self.bind(focus=self._on_focus, disabled=self._on_focusable,\n                  is_focusable=self._on_focusable,\n                  focus_next=self._set_on_focus_next,\n                  focus_previous=self._set_on_focus_previous)\n\n    def _on_focusable(self, instance, value):\n        if self.disabled or not self.is_focusable:\n            self.focus = False\n\n    def _on_focus(self, instance, value, *largs):\n        if self.keyboard_mode == 'auto':\n            if value:\n                self._bind_keyboard()\n            else:\n                self._unbind_keyboard()\n\n    def _ensure_keyboard(self):\n        if self._keyboard is None:\n            self._requested_keyboard = True\n            keyboard = self._keyboard =\\\n                EventLoop.window.request_keyboard(\n                    self._keyboard_released, self, input_type=self.input_type)\n            keyboards = FocusBehavior._keyboards\n            if keyboard not in keyboards:\n                keyboards[keyboard] = None\n\n    def _bind_keyboard(self):\n        self._ensure_keyboard()\n        keyboard = self._keyboard\n\n        if not keyboard or self.disabled or not self.is_focusable:\n            self.focus = False\n            return\n        keyboards = FocusBehavior._keyboards\n        old_focus = keyboards[keyboard]  # keyboard should be in dict\n        if old_focus:\n            old_focus.focus = False\n            # keyboard shouldn't have been released here, see keyboard warning\n        keyboards[keyboard] = self\n        keyboard.bind(on_key_down=self.keyboard_on_key_down,\n                      on_key_up=self.keyboard_on_key_up,\n                      on_textinput=self.keyboard_on_textinput)\n\n    def _unbind_keyboard(self):\n        keyboard = self._keyboard\n        if keyboard:\n            keyboard.unbind(on_key_down=self.keyboard_on_key_down,\n                            on_key_up=self.keyboard_on_key_up,\n                            on_textinput=self.keyboard_on_textinput)\n            if self._requested_keyboard:\n                keyboard.release()\n                self._keyboard = None\n                self._requested_keyboard = False\n                del FocusBehavior._keyboards[keyboard]\n            else:\n                FocusBehavior._keyboards[keyboard] = None\n\n    def keyboard_on_textinput(self, window, text):\n        pass\n\n    def _keyboard_released(self):\n        self.focus = False\n\n    def on_touch_down(self, touch):\n        if not self.collide_point(*touch.pos):\n            return\n        if (not self.disabled and self.is_focusable and\n            ('button' not in touch.profile or\n             not touch.button.startswith('scroll'))):\n            self.focus = True\n            FocusBehavior.ignored_touch.append(touch)\n        return super(FocusBehavior, self).on_touch_down(touch)\n\n    @staticmethod\n    def _handle_post_on_touch_up(touch):\n        ''' Called by window after each touch has finished.\n        '''\n        touches = FocusBehavior.ignored_touch\n        if touch in touches:\n            touches.remove(touch)\n            return\n        for focusable in list(FocusBehavior._keyboards.values()):\n            if focusable is None or not focusable.unfocus_on_touch:\n                continue\n            focusable.focus = False\n\n    def _get_focus_next(self, focus_dir):\n        current = self\n        walk_tree = 'walk' if focus_dir is 'focus_next' else 'walk_reverse'\n\n        while 1:\n            # if we hit a focusable, walk through focus_xxx\n            while getattr(current, focus_dir) is not None:\n                current = getattr(current, focus_dir)\n                if current is self or current is StopIteration:\n                    return None  # make sure we don't loop forever\n                if current.is_focusable and not current.disabled:\n                    return current\n\n            # hit unfocusable, walk widget tree\n            itr = getattr(current, walk_tree)(loopback=True)\n            if focus_dir is 'focus_next':\n                next(itr)  # current is returned first  when walking forward\n            for current in itr:\n                if isinstance(current, FocusBehavior):\n                    break\n            # why did we stop\n            if isinstance(current, FocusBehavior):\n                if current is self:\n                    return None\n                if current.is_focusable and not current.disabled:\n                    return current\n            else:\n                return None\n\n    def keyboard_on_key_down(self, window, keycode, text, modifiers):\n        '''The method bound to the keyboard when the instance has focus.\n\n        When the instance becomes focused, this method is bound to the\n        keyboard and will be called for every input press. The parameters are\n        the same as :meth:`kivy.core.window.WindowBase.on_key_down`.\n\n        When overwriting the method in the derived widget, super should be\n        called to enable tab cycling. If the derived widget wishes to use tab\n        for its own purposes, it can call super at the end after it is done if\n        it didn't consume tab.\n\n        Similar to other keyboard functions, it should return True if the\n        key was consumed.\n        '''\n        if keycode[1] == 'tab':  # deal with cycle\n            if ['shift'] == modifiers:\n                next = self._get_focus_next('focus_previous')\n            else:\n                next = self._get_focus_next('focus_next')\n            if next:\n                self.focus = False\n\n                next.focus = True\n\n            return True\n        return False\n\n    def keyboard_on_key_up(self, window, keycode):\n        '''The method bound to the keyboard when the instance has focus.\n\n        When the instance becomes focused, this method is bound to the\n        keyboard and will be called for every input release. The parameters are\n        the same as :meth:`kivy.core.window.WindowBase.on_key_up`.\n\n        When overwriting the method in the derived widget, super should be\n        called to enable de-focusing on escape. If the derived widget wishes\n        to use escape for its own purposes, it can call super at the end after\n        it is done if it didn't consume escape.\n\n        See :meth:`on_key_down`\n        '''\n        if keycode[1] == 'escape':\n            self.focus = False\n            return True\n        return False\n\n    def show_keyboard(self):\n        '''\n        Convenience function to show the keyboard in managed mode.\n        '''\n        if self.keyboard_mode == 'managed':\n            self._bind_keyboard()\n\n    def hide_keyboard(self):\n        '''\n        Convenience function to hide the keyboard in managed mode.\n        '''\n        if self.keyboard_mode == 'managed':\n            self._unbind_keyboard()\n\n\nclass CompoundSelectionBehavior(object):\n    '''Selection behavior implements the logic behind keyboard and touch\n    selection of selectable widgets managed by the derived widget.\n    For example, it could be combined with a\n    :class:`~kivy.uix.gridlayout.GridLayout` to add selection to the layout.\n\n    At its core, it keeps a dynamic list of widgets that can be selected.\n    Then, as the touches and keyboard input are passed in, it selects one or\n    more of the widgets based on these inputs. For example, it uses the mouse\n    scroll and keyboard up/down buttons to scroll through the list of widgets.\n    Multiselection can also be achieved using the keyboard shift and ctrl keys.\n    Finally, in addition to the up/down type keyboard inputs, it can also\n    accepts letters from the kayboard to be used to select nodes with\n    associated strings that start with those letters, similar to how files\n    are selected by a file browser.\n\n    When the controller needs to select a node it calls :meth:`select_node` and\n    :meth:`deselect_node`. Therefore, they must be overwritten in order affect\n    the selected nodes. By default, the class doesn't listen to keyboard and\n    touch events, therefore, the derived widget must call\n    :meth:`select_with_touch`, :meth:`select_with_key_down`, and\n    :meth:`select_with_key_up` on events that it wants to pass on for selection\n    purposes.\n\n    For example, to add selection to a grid layout which will contain\n    :class:`~kivy.uix.Button` widgets::\n\n        class SelectableGrid(CompoundSelectionBehavior, GridLayout):\n\n            def __init__(self, **kwargs):\n                super(CompoundSelectionBehavior, self).__init__(**kwargs)\n                keyboard = Window.request_keyboard(None, self)\n                keyboard.bind(on_key_down=self.select_with_key_down,\n                on_key_up=self.select_with_key_up)\n\n            def select_node(self, node):\n                node.background_color = (1, 0, 0, 1)\n                return super(CompoundSelectionBehavior, self).select_node(node)\n\n            def deselect_node(self, node):\n                node.background_color = (1, 1, 1, 1)\n                super(CompoundSelectionBehavior, self).deselect_node(node)\n\n    Then, for each button added to the layout, bind on_touch_down of the button\n    to :meth:`select_with_touch` to pass on the touch events.\n\n    .. versionadded:: 1.9.0\n\n    .. warning::\n\n        This code is still experimental, and its API is subject to change in a\n        future version.\n    '''\n\n    selected_nodes = ListProperty([])\n    '''The list of selected nodes.\n\n    .. note:\n\n        Multiple nodes can be selected right after another using e.g. the\n        keyboard, so when listening to :attr:`selected_nodes` one should be\n        aware of this.\n\n    :attr:`selected_nodes` is a :class:`~kivy.properties.ListProperty` and\n    defaults to the empty list, []. It is read-only and should not be modified.\n    '''\n\n    touch_multiselect = BooleanProperty(False)\n    '''A special touch mode which determines whether touch events, as\n    processed with :meth:`select_with_touch`, will add to the selection the\n    currently touched node, or if it will clear the selection before adding the\n    node. This allows the selection of multiple nodes by simply touching them.\n    This is different than :attr:`multiselect`, because when this is True\n    simply touching an unselected node will select it, even if e.g. ctrl is not\n    pressed. If this is False, however, ctrl is required to be held in order to\n    add to selection when :attr:`multiselect` is True.\n\n    .. note::\n\n        :attr:`multiselect`, when False, will disable\n        :attr:`touch_multiselect`.\n\n    :attr:`touch_multiselect` is a :class:`~kivy.properties.BooleanProperty`,\n    defaults to False.\n    '''\n\n    multiselect = BooleanProperty(False)\n    '''Determines whether multiple nodes can be selected. If enabled, keyboard\n    shift and ctrl selection, optionally combined with touch, for example, will\n    be able to select multiple widgets in the normally expected manner.\n    This dominates :attr:`touch_multiselect` when False.\n\n    :attr:`multiselect` is a :class:`~kivy.properties.BooleanProperty`\n    , defaults to False.\n    '''\n\n    keyboard_select = BooleanProperty(True)\n    ''' Whether the keybaord can be used for selection. If False, keyboard\n    inputs will be ignored.\n\n    :attr:`keyboard_select` is a :class:`~kivy.properties.BooleanProperty`\n    , defaults to True.\n    '''\n\n    page_count = NumericProperty(10)\n    '''Determines by how much the selected node is moved up or down, relative\n    to position of the last selected node, when pageup (or pagedown) is\n    pressed.\n\n    :attr:`page_count` is a :class:`~kivy.properties.NumericProperty`,\n    defaults to 10.\n    '''\n\n    up_count = NumericProperty(1)\n    '''Determines by how much the selected node is moved up or down, relative\n    to position of the last selected node, when the up (or down) arrow on the\n    keyboard is pressed.\n\n    :attr:`up_count` is a :class:`~kivy.properties.NumericProperty`,\n    defaults to 1.\n    '''\n\n    right_count = NumericProperty(1)\n    '''Determines by how much the selected node is moved up or down, relative\n    to position of the last selected node, when the right (or left) arrow on\n    the keyboard is pressed.\n\n    :attr:`right_count` is a :class:`~kivy.properties.NumericProperty`,\n    defaults to 1.\n    '''\n\n    scroll_count = NumericProperty(0)\n    '''Determines by how much the selected node is moved up or down, relative\n    to position of the last selected node, when the mouse scroll wheel is\n    scrolled.\n\n    :attr:`right_count` is a :class:`~kivy.properties.NumericProperty`,\n    defaults to 0.\n    '''\n\n    _anchor = None  # the last anchor node selected (e.g. shift relative node)\n    # the idx may be out of sync\n    _anchor_idx = 0  # cache indexs in case list hasn't changed\n    _last_selected_node = None  # the absolute last node selected\n    _last_node_idx = 0\n    _ctrl_down = False  # if it's pressed - for e.g. shift selection\n    _shift_down = False\n    # holds str used to find node, e.g. if word is typed. passed to goto_node\n    _word_filter = ''\n    _last_key_time = 0  # time since last press, for finding whole strs in node\n    _printable = set(string.printable)\n    _key_list = []  # keys that are already pressed, to not press continuously\n    _offset_counts = {}  # cache of counts for faster access\n\n    def __init__(self, **kwargs):\n        super(CompoundSelectionBehavior, self).__init__(**kwargs)\n\n        def ensure_single_select(*l):\n            if (not self.multiselect) and len(self.selected_nodes) > 1:\n                self.clear_selection()\n        self._update_counts()\n        self.bind(multiselect=ensure_single_select,\n        page_count=self._update_counts, up_count=self._update_counts,\n        right_count=self._update_counts, scroll_count=self._update_counts)\n\n    def select_with_touch(self, node, touch=None):\n        '''(internal) Processes a touch on the node. This should be called by\n        the derived widget when a node is touched and is to be used for\n        selection. Depending on the keyboard keys pressed and the\n        configuration, it could select or deslect this and other nodes in the\n        selectable nodes list, :meth:`get_selectable_nodes`.\n\n        :Parameters:\n            `node`\n                The node that recieved the touch. Can be None for a scroll\n                type touch.\n            `touch`\n                Optionally, the touch. Defaults to None.\n\n        :Returns:\n            bool, True if the touch was used, False otherwise.\n        '''\n        multi = self.multiselect\n        multiselect = multi and (self._ctrl_down or self.touch_multiselect)\n        range_select = multi and self._shift_down\n\n        if touch and 'button' in touch.profile and touch.button in\\\n            ('scrollup', 'scrolldown', 'scrollleft', 'scrollright'):\n            node_src, idx_src = self._reslove_last_node()\n            node, idx = self.goto_node(touch.button, node_src, idx_src)\n            if node == node_src:\n                return False\n            if range_select:\n                self._select_range(multiselect, True, node, idx)\n            else:\n                if not multiselect:\n                    self.clear_selection()\n                self.select_node(node)\n            return True\n        if node is None:\n            return False\n\n        if (node in self.selected_nodes and (not range_select)):  # selected\n            if multiselect:\n                self.deselect_node(node)\n            else:\n                self.clear_selection()\n                self.select_node(node)\n        elif range_select:\n            # keep anchor only if not multislect (ctrl-type selection)\n            self._select_range(multiselect, not multiselect, node, 0)\n        else:   # it's not selected at this point\n            if not multiselect:\n                self.clear_selection()\n            self.select_node(node)\n        return True\n\n    def select_with_key_down(self, keyboard, scancode, codepoint, modifiers,\n                             **kwargs):\n        '''Processes a key press. This is called when a key press is to be used\n        for selection. Depending on the keyboard keys pressed and the\n        configuration, it could select or deslect nodes or node ranges\n        from the selectable nodes list, :meth:`get_selectable_nodes`.\n\n        The parameters are such that it could be bound directly to the\n        on_key_down event of a keyboard. Therefore, it is safe to be called\n        repeatedly when the key is held down as is done by the keyboard.\n\n        :Returns:\n            bool, True if the keypress was used, False otherwise.\n        '''\n        if not self.keyboard_select:\n            return False\n        keys = self._key_list\n        multi = self.multiselect\n        node_src, idx_src = self._reslove_last_node()\n\n        if scancode[1] == 'shift':\n            self._shift_down = True\n        elif scancode[1] == 'ctrl':\n            self._ctrl_down = True\n        elif (multi and 'ctrl' in modifiers and scancode[1] in ('a', 'A')\n              and scancode[1] not in keys):\n            sister_nodes = self.get_selectable_nodes()\n            select = self.select_node\n            for node in sister_nodes:\n                select(node)\n            keys.append(scancode[1])\n        else:\n            if scancode[1] in self._printable:\n                if time() - self._last_key_time <= 1.:\n                    self._word_filter += scancode[1]\n                else:\n                    self._word_filter = scancode[1]\n                self._last_key_time = time()\n                node, idx = self.goto_node(self._word_filter, node_src,\n                                           idx_src)\n            else:\n                node, idx = self.goto_node(scancode[1], node_src, idx_src)\n            if node == node_src:\n                return False\n\n            multiselect = multi and 'ctrl' in modifiers\n            if multi and 'shift' in modifiers:\n                self._select_range(multiselect, True, node, idx)\n            else:\n                if not multiselect:\n                    self.clear_selection()\n                self.select_node(node)\n            return True\n        return False\n\n    def select_with_key_up(self, keyboard, scancode, **kwargs):\n        '''(internal) Processes a key release. This must be called by the\n        derived widget when a key that :meth:`select_with_key_down` returned\n        True is released.\n\n        The parameters are such that it could be bound directly to the\n        on_key_up event of a keyboard.\n\n        :Returns:\n            bool, True if the key release was used, False otherwise.\n        '''\n        if scancode[1] == 'shift':\n            self._shift_down = False\n        elif scancode[1] == 'ctrl':\n            self._ctrl_down = False\n        else:\n            try:\n                self._key_list.remove(scancode[1])\n                return True\n            except ValueError:\n                return False\n        return True\n\n    def _update_counts(self, *largs):\n        # doesn't invert indices here\n        pc = self.page_count\n        uc = self.up_count\n        rc = self.right_count\n        sc = self.scroll_count\n        self._offset_counts = {'pageup': -pc, 'pagedown': pc, 'up': -uc,\n        'down': uc, 'right': rc, 'left': -rc, 'scrollup': sc,\n        'scrolldown': -sc, 'scrollright': -sc, 'scrollleft': sc}\n\n    def _reslove_last_node(self):\n        # for offset selection, we have a anchor, and we select everything\n        # between anchor and added offset relative to last node\n        sister_nodes = self.get_selectable_nodes()\n        if not len(sister_nodes):\n            return None, 0\n        last_node = self._last_selected_node\n        last_idx = self._last_node_idx\n        end = len(sister_nodes) - 1\n\n        if last_node is None:\n            last_node = self._anchor\n            last_idx = self._anchor_idx\n        if last_node is None:\n            return sister_nodes[end], end\n        if last_idx > end or sister_nodes[last_idx] != last_node:\n            try:\n                return last_node, sister_nodes.index(last_node)\n            except ValueError:\n                return sister_nodes[end], end\n        return last_node, last_idx\n\n    def _select_range(self, multiselect, keep_anchor, node, idx):\n        '''Selects a range between self._anchor and node or idx.\n        If multiselect, it'll add to selection, otherwise it will unselect\n        everything before selecting the range. This is only called if\n        self.multiselect is True.\n        If keep anchor is False, the anchor is moved to node. This should\n        always be True of keyboard selection.\n        '''\n        select = self.select_node\n        sister_nodes = self.get_selectable_nodes()\n        end = len(sister_nodes) - 1\n        last_node = self._anchor\n        last_idx = self._anchor_idx\n\n        if last_node is None:\n            last_idx = end\n            last_node = sister_nodes[end]\n        else:\n            if last_idx > end or sister_nodes[last_idx] != last_node:\n                try:\n                    last_idx = sister_nodes.index(last_node)\n                except ValueError:\n                    # list changed - cannot do select across them\n                    return\n        if idx > end or sister_nodes[idx] != node:\n            try:    # just in case\n                idx = sister_nodes.index(node)\n            except ValueError:\n                return\n\n        if last_idx > idx:\n            last_idx, idx = idx, last_idx\n        if not multiselect:\n            self.clear_selection()\n        for item in sister_nodes[last_idx:idx + 1]:\n            select(item)\n\n        if keep_anchor:\n            self._anchor = last_node\n            self._anchor_idx = last_idx\n        else:\n            self._anchor = node  # in case idx was reversed, reset\n            self._anchor_idx = idx\n        self._last_selected_node = node\n        self._last_node_idx = idx\n\n    def clear_selection(self):\n        ''' Deselects all the currently selected nodes.\n        '''\n        # keep the anchor and last selected node\n        deselect = self.deselect_node\n        nodes = self.selected_nodes\n        # empty beforehand so lookup in deselect will be fast\n        self.selected_nodes = []\n        for node in nodes:\n            deselect(node)\n\n    def get_selectable_nodes(self):\n        '''(internal) Returns a list of the nodes that can be selected. It can\n        be overwritten by the derived widget to return the correct list.\n\n        This list is used to determine which nodes to select with group\n        selection. E.g. the last element in the list will be selected when\n        home is pressed, pagedown will move (or add to, if shift is held) the\n        selection from the current position by negative :attr:`page_count`\n        nodes starting from the position of the currently selected node in\n        this list and so on. Still, nodes can be selected even if they are not\n        in this list.\n\n        .. note::\n\n            It is safe to dynamically change this list including removing,\n            adding, or re-arranging its elements. Nodes can be selected even\n            if they are not on this list. And selected nodes removed from the\n            list will remain selected until :meth:`deselect_node` is called.\n\n        .. warning::\n\n            Layouts display their children in the reverse order. That is, the\n            contents of :attr:`~kivy.uix.widget.Widget.children` is displayed\n            form right to left, bottom to top. Therefore, internally, the\n            indices of the elements returned by this function is reversed to\n            make it work by default for most layouts so that the final result\n            is that e.g. home, although it will select the last element on this\n            list, visually it'll select the first element when counting from\n            top to bottom and left to right. If this behavior is not desired,\n            a reversed list should be returned instead.\n\n        Defaults to returning :attr:`~kivy.uix.widget.Widget.children`.\n        '''\n        return self.children\n\n    def goto_node(self, key, last_node, last_node_idx):\n        '''(internal) Used by the controller to get the node at the position\n        indicated by key. The key can be keyboard inputs, e.g. pageup,\n        or scroll inputs from the mouse scroll wheel, e.g. scrollup.\n        Last node is the last node selected and is used to find the resulting\n        node. For example, if the key is up, the returned node is one node\n        up from the last node.\n\n        It can be overwritten by the derived widget.\n\n        :Parameters:\n            `key`\n                str, the string used to find the desired node. It can be any\n                of the keyboard keys, as well as the mouse scrollup,\n                scrolldown, scrollright, and scrollleft strings. If letters\n                are typed in quick succession, the letters will be combined\n                before it's passed in as key and can be used to find nodes that\n                have an associated string that starts with those letters.\n            `last_node`\n                The last node that was selected.\n            `last_node_idx`\n                The cached index of the last node selected in the\n                :meth:`get_selectable_nodes` list. If the list hasn't changed\n                it saves having to look up the index of `last_node` in that\n                list.\n\n        :Returns:\n            tuple, the node targeted by key and its index in the\n            :meth:`get_selectable_nodes` list. Returning\n            `(last_node, last_node_idx)` indicates a node wasn't found.\n        '''\n        sister_nodes = self.get_selectable_nodes()\n        end = len(sister_nodes) - 1\n        counts = self._offset_counts\n        if end == -1:\n            return last_node, last_node_idx\n        if last_node_idx > end or sister_nodes[last_node_idx] != last_node:\n            try:    # just in case\n                last_node_idx = sister_nodes.index(last_node)\n            except ValueError:\n                return last_node, last_node_idx\n\n        try:\n            idx = max(min(-counts[key] + last_node_idx, end), 0)\n            return sister_nodes[idx], idx\n        except KeyError:\n            pass\n        if key == 'home':\n            return sister_nodes[end], end\n        elif key == 'end':\n            return sister_nodes[0], 0\n        else:\n            return last_node, last_node_idx\n\n    def select_node(self, node):\n        ''' Selects a node.\n\n        It is called by the controller when it selects a node and can be\n        called from the outside to select a node directly. The derived widget\n        should overwrite this method and change the node to its selected state\n        when this is called\n\n        :Parameters:\n            `node`\n                The node to be selected.\n\n        :Returns:\n            bool, True if the node was selected, False otherwise.\n\n        .. warning::\n\n            This method must be called by the derived widget using super if it\n            is overwritten.\n        '''\n        nodes = self.selected_nodes\n        if (not self.multiselect) and len(nodes):\n            self.clear_selection()\n        if node not in nodes:\n            nodes.append(node)\n        self._anchor = node\n        self._last_selected_node = node\n        return True\n\n    def deselect_node(self, node):\n        ''' Deselects a possibly selected node.\n\n        It is called by the controller when it deselects a node and can also\n        be called from the outside to deselect a node directly. The derived\n        widget should overwrite this method and change the node to its\n        unselected state when this is called\n\n        :Parameters:\n            `node`\n                The node to be deselected.\n\n        .. warning::\n\n            This method must be called by the derived widget using super if it\n            is overwritten.\n        '''\n        try:\n            self.selected_nodes.remove(node)\n        except ValueError:\n            pass\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/boxlayout.py",
    "content": "'''\nBox Layout\n==========\n\n.. only:: html\n\n    .. image:: images/boxlayout.gif\n        :align: right\n\n.. only:: latex\n\n    .. image:: images/boxlayout.png\n        :align: right\n\n:class:`BoxLayout` arranges children in a vertical or horizontal box.\n\nTo position widgets above/below each other, use a vertical BoxLayout::\n\n    layout = BoxLayout(orientation='vertical')\n    btn1 = Button(text='Hello')\n    btn2 = Button(text='World')\n    layout.add_widget(btn1)\n    layout.add_widget(btn2)\n\nTo position widgets next to each other, use a horizontal BoxLayout. In this\nexample, we use 10 pixel spacing between children; the first button covers\n70% of the horizontal space, the second covers 30%::\n\n    layout = BoxLayout(spacing=10)\n    btn1 = Button(text='Hello', size_hint=(.7, 1))\n    btn2 = Button(text='World', size_hint=(.3, 1))\n    layout.add_widget(btn1)\n    layout.add_widget(btn2)\n\nPosition hints are partially working, depending on the orientation:\n\n* If the orientation is `vertical`: `x`, `right` and `center_x` will be used.\n* If the orientation is `horizontal`: `y`, `top` and `center_y` will be used.\n\nYou can check the `examples/widgets/boxlayout_poshint.py` for a live example.\n\n.. note::\n\n    The `size_hint` uses the available space after subtracting all the\n    fixed-size widgets. For example, if you have a layout that is 800px\n    wide, and add three buttons like this:\n\n    btn1 = Button(text='Hello', size=(200, 100), size_hint=(None, None))\n    btn2 = Button(text='Kivy', size_hint=(.5, 1))\n    btn3 = Button(text='World', size_hint=(.5, 1))\n\n    The first button will be 200px wide as specified, the second and third\n    will be 300px each, e.g. (800-200) * 0.5\n\n\n.. versionchanged:: 1.4.1\n    Added support for `pos_hint`.\n\n'''\n\n__all__ = ('BoxLayout', )\n\nfrom kivy.uix.layout import Layout\nfrom kivy.properties import (NumericProperty, OptionProperty,\n                             VariableListProperty)\n\n\nclass BoxLayout(Layout):\n    '''Box layout class. See module documentation for more information.\n    '''\n\n    spacing = NumericProperty(0)\n    '''Spacing between children, in pixels.\n\n    :attr:`spacing` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 0.\n    '''\n\n    padding = VariableListProperty([0, 0, 0, 0])\n    '''Padding between layout box and children: [padding_left, padding_top,\n    padding_right, padding_bottom].\n\n    padding also accepts a two argument form [padding_horizontal,\n    padding_vertical] and a one argument form [padding].\n\n    .. versionchanged:: 1.7.0\n        Replaced NumericProperty with VariableListProperty.\n\n    :attr:`padding` is a :class:`~kivy.properties.VariableListProperty` and\n    defaults to [0, 0, 0, 0].\n    '''\n\n    orientation = OptionProperty('horizontal', options=(\n        'horizontal', 'vertical'))\n    '''Orientation of the layout.\n\n    :attr:`orientation` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to 'horizontal'. Can be 'vertical' or 'horizontal'.\n    '''\n\n    def __init__(self, **kwargs):\n        super(BoxLayout, self).__init__(**kwargs)\n        self.bind(\n            spacing=self._trigger_layout,\n            padding=self._trigger_layout,\n            children=self._trigger_layout,\n            orientation=self._trigger_layout,\n            parent=self._trigger_layout,\n            size=self._trigger_layout,\n            pos=self._trigger_layout)\n\n    def do_layout(self, *largs):\n        # optimize layout by preventing looking at the same attribute in a loop\n        len_children = len(self.children)\n        if len_children == 0:\n            return\n        selfx = self.x\n        selfy = self.y\n        selfw = self.width\n        selfh = self.height\n        padding_left = self.padding[0]\n        padding_top = self.padding[1]\n        padding_right = self.padding[2]\n        padding_bottom = self.padding[3]\n        spacing = self.spacing\n        orientation = self.orientation\n        padding_x = padding_left + padding_right\n        padding_y = padding_top + padding_bottom\n\n        # calculate maximum space used by size_hint\n        stretch_weight_x = 0.\n        stretch_weight_y = 0.\n        minimum_size_x = padding_x + spacing * (len_children - 1)\n        minimum_size_y = padding_y + spacing * (len_children - 1)\n        for w in self.children:\n            shw = w.size_hint_x\n            shh = w.size_hint_y\n            if shw is None:\n                minimum_size_x += w.width\n            else:\n                stretch_weight_x += shw\n            if shh is None:\n                minimum_size_y += w.height\n            else:\n                stretch_weight_y += shh\n\n        if orientation == 'horizontal':\n            x = padding_left\n            stretch_space = max(0.0, selfw - minimum_size_x)\n            for c in reversed(self.children):\n                shw = c.size_hint_x\n                shh = c.size_hint_y\n                w = c.width\n                h = c.height\n                cx = selfx + x\n                cy = selfy + padding_bottom\n\n                if shw:\n                    w = stretch_space * shw / stretch_weight_x\n                if shh:\n                    h = max(0, shh * (selfh - padding_y))\n\n                for key, value in c.pos_hint.items():\n                    posy = value * (selfh - padding_y)\n                    if key == 'y':\n                        cy += posy\n                    elif key == 'top':\n                        cy += posy - h\n                    elif key == 'center_y':\n                        cy += posy - (h / 2.)\n\n                c.x = cx\n                c.y = cy\n                c.width = w\n                c.height = h\n                x += w + spacing\n\n        if orientation == 'vertical':\n            y = padding_bottom\n            stretch_space = max(0.0, selfh - minimum_size_y)\n            for c in self.children:\n                shw = c.size_hint_x\n                shh = c.size_hint_y\n                w = c.width\n                h = c.height\n                cx = selfx + padding_left\n                cy = selfy + y\n\n                if shh:\n                    h = stretch_space * shh / stretch_weight_y\n                if shw:\n                    w = max(0, shw * (selfw - padding_x))\n\n                for key, value in c.pos_hint.items():\n                    posx = value * (selfw - padding_x)\n                    if key == 'x':\n                        cx += posx\n                    elif key == 'right':\n                        cx += posx - w\n                    elif key == 'center_x':\n                        cx += posx - (w / 2.)\n\n                c.x = cx\n                c.y = cy\n                c.width = w\n                c.height = h\n                y += h + spacing\n\n    def add_widget(self, widget, index=0):\n        widget.bind(\n            pos_hint=self._trigger_layout)\n        return super(BoxLayout, self).add_widget(widget, index)\n\n    def remove_widget(self, widget):\n        widget.unbind(\n            pos_hint=self._trigger_layout)\n        return super(BoxLayout, self).remove_widget(widget)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/bubble.py",
    "content": "'''\nBubble\n======\n\n.. versionadded:: 1.1.0\n\n.. image:: images/bubble.jpg\n    :align: right\n\nThe Bubble widget is a form of menu or a small popup where the menu options\nare stacked either vertically or horizontally.\n\nThe :class:`Bubble` contains an arrow pointing in the direction you\nchoose.\n\nSimple example\n--------------\n\n.. include:: ../../examples/widgets/bubble_test.py\n    :literal:\n\nCustomize the Bubble\n--------------------\n\nYou can choose the direction in which the arrow points::\n\n    Bubble(arrow_pos='top_mid')\n\nThe widgets added to the Bubble are ordered horizontally by default, like a\nBoxlayout. You can change that by::\n\n    orientation = 'vertical'\n\nTo add items to the bubble::\n\n    bubble = Bubble(orientation = 'vertical')\n    bubble.add_widget(your_widget_instance)\n\nTo remove items::\n\n    bubble.remove_widget(widget)\n    or\n    bubble.clear_widgets()\n\nTo access the list of children, use content.children::\n\n    bubble.content.children\n\n.. warning::\n  This is important! Do not use bubble.children\n\nTo change the appearance of the bubble::\n\n    bubble.background_color = (1, 0, 0, .5) #50% translucent red\n    bubble.border = [0, 0, 0, 0]\n    background_image = 'path/to/background/image'\n    arrow_image = 'path/to/arrow/image'\n'''\n\n__all__ = ('Bubble', 'BubbleButton', 'BubbleContent')\n\nfrom kivy.uix.image import Image\nfrom kivy.uix.widget import Widget\nfrom kivy.uix.scatter import Scatter\nfrom kivy.uix.gridlayout import GridLayout\nfrom kivy.uix.boxlayout import BoxLayout\nfrom kivy.uix.button import Button\nfrom kivy.properties import ObjectProperty, StringProperty, OptionProperty, \\\n    ListProperty, BooleanProperty\nfrom kivy.clock import Clock\nfrom kivy.base import EventLoop\nfrom kivy.metrics import dp\n\n\nclass BubbleButton(Button):\n    '''A button intended for use in a Bubble widget.\n    You can use a \"normal\" button class, but it will not look good unless\n    the background is changed.\n\n    Rather use this BubbleButton widget that is already defined and provides a\n    suitable background for you.\n    '''\n    pass\n\n\nclass BubbleContent(GridLayout):\n    pass\n\n\nclass Bubble(GridLayout):\n    '''Bubble class. See module documentation for more information.\n    '''\n\n    background_color = ListProperty([1, 1, 1, 1])\n    '''Background color, in the format (r, g, b, a).\n\n    :attr:`background_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [1, 1, 1, 1].\n    '''\n\n    border = ListProperty([16, 16, 16, 16])\n    '''Border used for :class:`~kivy.graphics.vertex_instructions.BorderImage`\n    graphics instruction. Used with the :attr:`background_image`.\n    It should be used when using custom backgrounds.\n\n    It must be a list of 4 values: (top, right, bottom, left). Read the\n    BorderImage instructions for more information about how to use it.\n\n    :attr:`border` is a :class:`~kivy.properties.ListProperty` and defaults to\n    (16, 16, 16, 16)\n    '''\n\n    background_image = StringProperty(\n        'atlas://data/images/defaulttheme/bubble')\n    '''Background image of the bubble.\n\n    :attr:`background_image` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/bubble'.\n    '''\n\n    arrow_image = StringProperty(\n        'atlas://data/images/defaulttheme/bubble_arrow')\n    ''' Image of the arrow pointing to the bubble.\n\n    :attr:`arrow_image` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/bubble_arrow'.\n    '''\n\n    show_arrow = BooleanProperty(True)\n    ''' Indicates whether to show arrow.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`show_arrow` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to `True`.\n    '''\n\n    arrow_pos = OptionProperty('bottom_mid', options=(\n        'left_top', 'left_mid', 'left_bottom', 'top_left', 'top_mid',\n        'top_right', 'right_top', 'right_mid', 'right_bottom',\n        'bottom_left', 'bottom_mid', 'bottom_right'))\n    '''Specifies the position of the arrow relative to the bubble.\n    Can be one of: left_top, left_mid, left_bottom top_left, top_mid, top_right\n    right_top, right_mid, right_bottom bottom_left, bottom_mid, bottom_right.\n\n    :attr:`arrow_pos` is a :class:`~kivy.properties.OptionProperty` and\n    defaults to 'bottom_mid'.\n    '''\n\n    content = ObjectProperty(None)\n    '''This is the object where the main content of the bubble is held.\n\n    :attr:`content` is a :class:`~kivy.properties.ObjectProperty` and\n    defaults to 'None'.\n    '''\n\n    orientation = OptionProperty('horizontal',\n                                 options=('horizontal', 'vertical'))\n    '''This specifies the manner in which the children inside bubble\n    are arranged. Can be one of 'vertical' or 'horizontal'.\n\n    :attr:`orientation` is a :class:`~kivy.properties.OptionProperty` and\n    defaults to 'horizontal'.\n    '''\n\n    limit_to = ObjectProperty(None, allownone=True)\n    '''Specifies the widget to which the bubbles position is restricted.\n\n    .. versionadded:: 1.6.0\n\n    :attr:`limit_to` is a :class:`~kivy.properties.ObjectProperty` and\n    defaults to 'None'.\n    '''\n\n    def __init__(self, **kwargs):\n        self._prev_arrow_pos = None\n        self._arrow_layout = BoxLayout()\n        self._bk_img = Image(\n            source=self.background_image, allow_stretch=True,\n            keep_ratio=False, color=self.background_color)\n        self.background_texture = self._bk_img.texture\n        self._arrow_img = Image(source=self.arrow_image,\n                                allow_stretch=True,\n                                color=self.background_color)\n        self.content = content = BubbleContent(parent=self)\n        super(Bubble, self).__init__(**kwargs)\n        content.parent = None\n        self.add_widget(content)\n        self.on_arrow_pos()\n\n    def add_widget(self, *l):\n        content = self.content\n        if content is None:\n            return\n        if l[0] == content or l[0] == self._arrow_img\\\n                or l[0] == self._arrow_layout:\n            super(Bubble, self).add_widget(*l)\n        else:\n            content.add_widget(*l)\n\n    def remove_widget(self, *l):\n        content = self.content\n        if not content:\n            return\n        if l[0] == content or l[0] == self._arrow_img\\\n                or l[0] == self._arrow_layout:\n            super(Bubble, self).remove_widget(*l)\n        else:\n            content.remove_widget(l[0])\n\n    def clear_widgets(self, **kwargs):\n        content = self.content\n        if not content:\n            return\n        if kwargs.get('do_super', False):\n            super(Bubble, self).clear_widgets()\n        else:\n            content.clear_widgets()\n\n    def on_show_arrow(self, instance, value):\n        self._arrow_img.opacity = int(value)\n\n    def on_parent(self, instance, value):\n        Clock.schedule_once(self._update_arrow)\n\n    def on_pos(self, instance, pos):\n        lt = self.limit_to\n\n        if lt:\n            self.limit_to = None\n            if lt is EventLoop.window:\n                x = y = 0\n                top = lt.height\n                right = lt.width\n            else:\n                x, y = lt.x, lt.y\n                top, right = lt.top, lt.right\n\n            self.x = max(self.x, x)\n            self.right = min(self.right, right)\n            self.top = min(self.top, top)\n            self.y = max(self.y, y)\n            self.limit_to = lt\n\n    def on_background_image(self, *l):\n        self._bk_img.source = self.background_image\n\n    def on_background_color(self, *l):\n        if self.content is None:\n            return\n        self._arrow_img.color = self._bk_img.color = self.background_color\n\n    def on_orientation(self, *l):\n        content = self.content\n        if not content:\n            return\n        if self.orientation[0] == 'v':\n            content.cols = 1\n            content.rows = 99\n        else:\n            content.cols = 99\n            content.rows = 1\n\n    def on_arrow_image(self, *l):\n        self._arrow_img.source = self.arrow_image\n\n    def on_arrow_pos(self, *l):\n        self_content = self.content\n        if not self_content:\n            Clock.schedule_once(self.on_arrow_pos)\n            return\n        if self_content not in self.children:\n            Clock.schedule_once(self.on_arrow_pos)\n            return\n        self_arrow_pos = self.arrow_pos\n        if self._prev_arrow_pos == self_arrow_pos:\n            return\n        self._prev_arrow_pos = self_arrow_pos\n\n        self_arrow_layout = self._arrow_layout\n        self_arrow_layout.clear_widgets()\n        self_arrow_img = self._arrow_img\n        self._sctr = self._arrow_img\n        self.clear_widgets(do_super=True)\n        self_content.parent = None\n\n        self_arrow_img.size_hint = (1, None)\n        self_arrow_img.height = dp(self_arrow_img.texture_size[1])\n        self_arrow_img.pos = 0, 0\n        widget_list = []\n        arrow_list = []\n        parent = self_arrow_img.parent\n        if parent:\n            parent.remove_widget(self_arrow_img)\n\n        if self_arrow_pos[0] == 'b' or self_arrow_pos[0] == 't':\n            self.cols = 1\n            self.rows = 3\n            self_arrow_layout.orientation = 'horizontal'\n            self_arrow_img.width = self.width / 3\n            self_arrow_layout.size_hint = (1, None)\n            self_arrow_layout.height = self_arrow_img.height\n            if self_arrow_pos[0] == 'b':\n                if self_arrow_pos == 'bottom_mid':\n                    widget_list = (self_content, self_arrow_img)\n                else:\n                    if self_arrow_pos == 'bottom_left':\n                        arrow_list = (self_arrow_img, Widget(), Widget())\n                    elif self_arrow_pos == 'bottom_right':\n                        #add two dummy widgets\n                        arrow_list = (Widget(), Widget(), self_arrow_img)\n                    widget_list = (self_content, self_arrow_layout)\n            else:\n                sctr = Scatter(do_translation=False,\n                               rotation=180,\n                               do_rotation=False,\n                               do_scale=False,\n                               size_hint=(None, None),\n                               size=self_arrow_img.size)\n                sctr.add_widget(self_arrow_img)\n                if self_arrow_pos == 'top_mid':\n                    #add two dummy widgets\n                    arrow_list = (Widget(), sctr, Widget())\n                elif self_arrow_pos == 'top_left':\n                    arrow_list = (sctr, Widget(), Widget())\n                elif self_arrow_pos == 'top_right':\n                    arrow_list = (Widget(), Widget(), sctr)\n                widget_list = (self_arrow_layout, self_content)\n        elif self_arrow_pos[0] == 'l' or self_arrow_pos[0] == 'r':\n            self.cols = 3\n            self.rows = 1\n            self_arrow_img.width = self.height / 3\n            self_arrow_layout.orientation = 'vertical'\n            self_arrow_layout.cols = 1\n            self_arrow_layout.size_hint = (None, 1)\n            self_arrow_layout.width = self_arrow_img.height\n\n            rotation = -90 if self_arrow_pos[0] == 'l' else 90\n            self._sctr = sctr = Scatter(do_translation=False,\n                                        rotation=rotation,\n                                        do_rotation=False,\n                                        do_scale=False,\n                                        size_hint=(None, None),\n                                        size=(self_arrow_img.size))\n            sctr.add_widget(self_arrow_img)\n\n            if self_arrow_pos[-4:] == '_top':\n                arrow_list = (Widget(size_hint=(1, .07)),\n                              sctr, Widget(size_hint=(1, .3)))\n            elif self_arrow_pos[-4:] == '_mid':\n                arrow_list = (Widget(), sctr, Widget())\n                Clock.schedule_once(self._update_arrow)\n            elif self_arrow_pos[-7:] == '_bottom':\n                arrow_list = (Widget(), Widget(), sctr)\n\n            if self_arrow_pos[0] == 'l':\n                widget_list = (self_arrow_layout, self_content)\n            else:\n                widget_list = (self_content, self_arrow_layout)\n\n        # add widgets to arrow_layout\n        add = self_arrow_layout.add_widget\n        for widg in arrow_list:\n            add(widg)\n\n        # add widgets to self\n        add = self.add_widget\n        for widg in widget_list:\n            add(widg)\n\n    def _update_arrow(self, *dt):\n        if self.arrow_pos in ('left_mid', 'right_mid'):\n            self._sctr.center_y = self._arrow_layout.center_y\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/button.py",
    "content": "'''\nButton\n======\n\n.. image:: images/button.jpg\n    :align: right\n\nThe :class:`Button` is a :class:`~kivy.uix.label.Label` with associated actions\nthat are triggered when the button is pressed (or released after a\nclick/touch). To configure the button, the same properties are used\nas for the Label class::\n\n    button = Button(text='Hello world', font_size=14)\n\nTo attach a callback when the button is pressed (clicked/touched), use\n:class:`~kivy.uix.widget.Widget.bind`::\n\n    def callback(instance):\n        print('The button <%s> is being pressed' % instance.text)\n\n    btn1 = Button(text='Hello world 1')\n    btn1.bind(on_press=callback)\n    btn2 = Button(text='Hello world 2')\n    btn2.bind(on_press=callback)\n\nIf you want to be notified every time the button state changes, you can bind\nto the :attr:`Button.state` property::\n\n    def callback(instance, value):\n        print('My button <%s> state is <%s>' % (instance, value))\n    btn1 = Button(text='Hello world 1')\n    btn1.bind(state=callback)\n\n'''\n\n__all__ = ('Button', )\n\nfrom kivy.uix.label import Label\nfrom kivy.properties import StringProperty, ListProperty\nfrom kivy.uix.behaviors import ButtonBehavior\n\n\nclass Button(ButtonBehavior, Label):\n    '''Button class, see module documentation for more information.\n\n    .. versionchanged:: 1.8.0\n        The behavior / logic of the button has been moved to\n        :class:`~kivy.uix.behaviors.ButtonBehaviors`.\n\n    '''\n\n    background_color = ListProperty([1, 1, 1, 1])\n    '''Background color, in the format (r, g, b, a).\n\n    This acts as a *multiplier* to the texture colour. The default\n    texture is grey, so just setting the background color will give\n    a darker result. To set a plain color, set the\n    :attr:`background_normal` to ``''``.\n\n    .. versionadded:: 1.0.8\n\n    The :attr:`background_color` is a\n    :class:`~kivy.properties.ListProperty` and defaults to [1, 1, 1, 1].\n    '''\n\n    background_normal = StringProperty(\n        'atlas://data/images/defaulttheme/button')\n    '''Background image of the button used for the default graphical\n    representation when the button is not pressed.\n\n    .. versionadded:: 1.0.4\n\n    :attr:`background_normal` is a :class:`~kivy.properties.StringProperty`\n    and defaults to 'atlas://data/images/defaulttheme/button'.\n    '''\n\n    background_down = StringProperty(\n        'atlas://data/images/defaulttheme/button_pressed')\n    '''Background image of the button used for the default graphical\n    representation when the button is pressed.\n\n    .. versionadded:: 1.0.4\n\n    :attr:`background_down` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/button_pressed'.\n    '''\n\n    background_disabled_normal = StringProperty(\n        'atlas://data/images/defaulttheme/button_disabled')\n    '''Background image of the button used for the default graphical\n    representation when the button is disabled and not pressed.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`background_disabled_normal` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/button_disabled'.\n    '''\n\n    background_disabled_down = StringProperty(\n        'atlas://data/images/defaulttheme/button_disabled_pressed')\n    '''Background image of the button used for the default graphical\n    representation when the button is disabled and pressed.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`background_disabled_down` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/button_disabled_pressed'.\n    '''\n\n    border = ListProperty([16, 16, 16, 16])\n    '''Border used for :class:`~kivy.graphics.vertex_instructions.BorderImage`\n    graphics instruction. Used with :attr:`background_normal` and\n    :attr:`background_down`. Can be used for custom backgrounds.\n\n    It must be a list of four values: (top, right, bottom, left). Read the\n    BorderImage instruction for more information about how to use it.\n\n    :attr:`border` is a :class:`~kivy.properties.ListProperty` and defaults to\n    (16, 16, 16, 16)\n    '''\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/camera.py",
    "content": "'''\nCamera\n======\n\nThe :class:`Camera` widget is used to capture and display video from a camera.\nOnce the widget is created, the texture inside the widget will be automatically\nupdated. Our :class:`~kivy.core.camera.CameraBase` implementation is used under\nthe hood::\n\n    cam = Camera()\n\nBy default, the first camera found on your system is used. To use a different\ncamera, set the index property::\n\n    cam = Camera(index=1)\n\nYou can also select the camera resolution::\n\n    cam = Camera(resolution=(320, 240))\n\n.. warning::\n\n    The camera texture is not updated as soon as you have created the object.\n    The camera initialization is asynchronous, so there may be a delay before\n    the requested texture is created.\n'''\n\n__all__ = ('Camera', )\n\nfrom kivy.uix.image import Image\nfrom kivy.core.camera import Camera as CoreCamera\nfrom kivy.properties import NumericProperty, ListProperty, \\\n    BooleanProperty\n\n\nclass Camera(Image):\n    '''Camera class. See module documentation for more information.\n    '''\n\n    play = BooleanProperty(True)\n    '''Boolean indicating whether the camera is playing or not.\n    You can start/stop the camera by setting this property::\n\n        # start the camera playing at creation (default)\n        cam = Camera(play=True)\n\n        # create the camera, and start later\n        cam = Camera(play=False)\n        # and later\n        cam.play = True\n\n    :attr:`play` is a :class:`~kivy.properties.BooleanProperty` and defaults to\n    True.\n    '''\n\n    index = NumericProperty(-1)\n    '''Index of the used camera, starting from 0.\n\n    :attr:`index` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to -1 to allow auto selection.\n    '''\n\n    resolution = ListProperty([-1, -1])\n    '''Preferred resolution to use when invoking the camera. If you are using\n    [-1, -1], the resolution will be the default one::\n\n        # create a camera object with the best image available\n        cam = Camera()\n\n        # create a camera object with an image of 320x240 if possible\n        cam = Camera(resolution=(320, 240))\n\n    .. warning::\n\n        Depending on the implementation, the camera may not respect this\n        property.\n\n    :attr:`resolution` is a :class:`~kivy.properties.ListProperty` and defaults\n    to [-1, -1].\n    '''\n\n    def __init__(self, **kwargs):\n        self._camera = None\n        super(Camera, self).__init__(**kwargs)\n        if self.index == -1:\n            self.index = 0\n        self.bind(index=self._on_index,\n                  resolution=self._on_index)\n        self._on_index()\n\n    def on_tex(self, *l):\n        self.canvas.ask_update()\n\n    def _on_index(self, *largs):\n        self._camera = None\n        if self.index < 0:\n            return\n        if self.resolution[0] < 0 or self.resolution[1] < 0:\n            return\n        self._camera = CoreCamera(index=self.index,\n                                  resolution=self.resolution, stopped=True)\n        self._camera.bind(on_load=self._camera_loaded)\n        if self.play:\n            self._camera.start()\n            self._camera.bind(on_texture=self.on_tex)\n\n    def _camera_loaded(self, *largs):\n        self.texture = self._camera.texture\n        self.texture_size = list(self.texture.size)\n\n    def on_play(self, instance, value):\n        if not self._camera:\n            return\n        if value:\n            self._camera.start()\n        else:\n            self._camera.stop()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/carousel.py",
    "content": "'''\nCarousel\n========\n\n.. versionadded:: 1.4.0\n\nThe :class:`Carousel` widget provides the classic mobile-friendly carousel view\nwhere you can swipe between slides.\nYou can add any content to the carousel and use it horizontally or verticaly.\nThe carousel can display pages in loop or not.\n\nExample::\n\n    class Example1(App):\n\n        def build(self):\n            carousel = Carousel(direction='right')\n            for i in range(10):\n                src = \"http://placehold.it/480x270.png&text=slide-%d&.png\" % i\n                image = Factory.AsyncImage(source=src, allow_stretch=True)\n                carousel.add_widget(image)\n            return carousel\n\n    Example1().run()\n\n.. versionchanged:: 1.5.0\n    The carousel now supports active children, like the\n    :class:`~kivy.uix.scrollview.ScrollView`. It will detect a swipe gesture\n    according to :attr:`Carousel.scroll_timeout` and\n    :attr:`Carousel.scroll_distance`.\n\n    In addition, the container used for adding a slide is now hidden in\n    the API. We made a mistake by exposing it to the user. The impacted\n    properties are:\n    :attr:`Carousel.slides`, :attr:`Carousel.current_slide`,\n    :attr:`Carousel.previous_slide` and :attr:`Carousel.next_slide`.\n\n'''\n\n__all__ = ('Carousel', )\n\nfrom functools import partial\nfrom kivy.clock import Clock\nfrom kivy.factory import Factory\nfrom kivy.animation import Animation\nfrom kivy.uix.stencilview import StencilView\nfrom kivy.uix.relativelayout import RelativeLayout\nfrom kivy.properties import BooleanProperty, OptionProperty, AliasProperty, \\\n    NumericProperty, ListProperty, ObjectProperty, StringProperty\n\n\nclass Carousel(StencilView):\n    '''Carousel class. See module documentation for more information.\n    '''\n\n    slides = ListProperty([])\n    '''List of slides inside the Carousel. The slides are added when a\n    widget is added to Carousel using add_widget().\n\n    :attr:`slides` is a :class:`~kivy.properties.ListProperty` and is\n    read-only.\n    '''\n\n    def _get_slides_container(self):\n        return [x.parent for x in self.slides]\n\n    slides_container = AliasProperty(_get_slides_container, None,\n                                     bind=('slides', ))\n\n    direction = OptionProperty('right',\n                               options=('right', 'left', 'top', 'bottom'))\n    '''Specifies the direction in which the slides are ordered i.e. the\n    direction from which the user swipes to go from one slide to the next.\n    Can be `right`, `left`, 'top', or `bottom`. For example, with\n    the default value of `right`, the second slide is to the right\n    of the first and the user would swipe from the right towards the\n    left to get to the second slide.\n\n    :attr:`direction` is a :class:`~kivy.properties.OptionProperty` and\n    defaults to 'right'.\n    '''\n\n    min_move = NumericProperty(0.2)\n    '''Defines the minimal distance from the edge where the movement is\n    considered a swipe gesture and the Carousel will change its content.\n    This is a percentage of the Carousel width.\n    If the movement doesn't reach this minimal value, then the movement is\n    cancelled and the content is restored to its original position.\n\n    :attr:`min_move` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.2.\n    '''\n\n    anim_move_duration = NumericProperty(0.5)\n    '''Defines the duration of the Carousel animation between pages.\n\n    :attr:`anim_move_duration` is a :class:`~kivy.properties.NumericProperty`\n    and defaults to 0.5.\n    '''\n\n    anim_cancel_duration = NumericProperty(0.3)\n    '''Defines the duration of the animation when a swipe movement is not\n    accepted. This is generally when the user doesnt swipe enough.\n    See :attr:`min_move`.\n\n    :attr:`anim_cancel_duration` is a :class:`~kivy.properties.NumericProperty`\n    and defaults to 0.3.\n    '''\n\n    loop = BooleanProperty(False)\n    '''Allow the Carousel to swipe infinitely. When the user reaches the last\n    page, they will return to first page when trying to swipe to the next.\n\n    :attr:`loop` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    def _get_index(self):\n        if self.slides:\n            return self._index % len(self.slides)\n        return None\n\n    def _set_index(self, value):\n        if self.slides:\n            self._index = value % len(self.slides)\n        else:\n            self._index = None\n    index = AliasProperty(_get_index, _set_index, bind=('_index', 'slides'))\n    '''Get/Set the current visible slide based on the index.\n\n    :attr:`index` is a :class:`~kivy.properties.AliasProperty` and defaults\n    to 0 (the first item).\n    '''\n\n    def _prev_slide(self):\n        slides = self.slides\n        len_slides = len(slides)\n        index = self.index\n        if len_slides < 2:  # None, or 1 slide\n            return None\n        if len_slides == 2:\n            if index == 0:\n                return None\n            if index == 1:\n                return slides[0]\n        if self.loop and index == 0:\n            return slides[-1]\n        if index > 0:\n            return slides[index - 1]\n\n    previous_slide = AliasProperty(_prev_slide, None, bind=('slides', 'index'))\n    '''The previous slide in the Carousel. It is None if the current slide is\n    the first slide in the Carousel. If :attr:`orientation` is 'horizontal',\n    the previous slide is to the left. If :attr:`orientation` is 'vertical',\n    the previous slide towards the bottom.\n\n    :attr:`previous_slide` is a :class:`~kivy.properties.AliasProperty`.\n\n    .. versionchanged:: 1.5.0\n        This property doesn't expose the container used for storing the slide.\n        It returns the widget you have added.\n    '''\n\n    def _curr_slide(self):\n        if len(self.slides):\n            return self.slides[self.index]\n    current_slide = AliasProperty(_curr_slide, None, bind=('slides', 'index'))\n    '''The currently shown slide.\n\n    :attr:`current_slide` is an :class:`~kivy.properties.AliasProperty`.\n\n    .. versionchanged:: 1.5.0\n        The property doesn't expose the container used for storing the slide.\n        It returns widget you have added.\n    '''\n\n    def _next_slide(self):\n        if len(self.slides) < 2:  # None, or 1 slide\n            return None\n        if len(self.slides) == 2:\n            if self.index == 0:\n                return self.slides[1]\n            if self.index == 1:\n                return None\n        if self.loop and self.index == len(self.slides) - 1:\n            return self.slides[0]\n        if self.index < len(self.slides) - 1:\n            return self.slides[self.index + 1]\n    next_slide = AliasProperty(_next_slide, None, bind=('slides', 'index'))\n    '''The next slide in the Carousel. It is None if the current slide is\n    the last slide in the Carousel. If :attr:`orientation` is 'horizontal',\n    the next slide is to the right. If :attr:`orientation` is 'vertical',\n    the next slide is towards the bottom.\n\n    :attr:`next_slide` is a :class:`~kivy.properties.AliasProperty`.\n\n    .. versionchanged:: 1.5.0\n        The property doesn't expose the container used for storing the slide.\n        It returns the widget you have added.\n    '''\n\n    scroll_timeout = NumericProperty(200)\n    '''Timeout allowed to trigger the :attr:`scroll_distance`, in milliseconds.\n    If the user has not moved :attr:`scroll_distance` within the timeout,\n    the scrolling will be disabled and the touch event will go to the children.\n\n    :attr:`scroll_timeout` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 200 (milliseconds)\n\n    .. versionadded:: 1.5.0\n    '''\n\n    scroll_distance = NumericProperty('20dp')\n    '''Distance to move before scrolling the :class:`Carousel` in pixels. As\n    soon as the distance has been traveled, the :class:`Carousel` will start\n    to scroll, and no touch event will go to children.\n    It is advisable that you base this value on the dpi of your target device's\n    screen.\n\n    :attr:`scroll_distance` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 20dp.\n\n    .. versionadded:: 1.5.0\n    '''\n\n    anim_type = StringProperty('out_quad')\n    '''Type of animation to use while animating in the next/previous slide.\n\n    .. versionadded:: 1.8.0\n    '''\n\n    #### private properties, for internal use only ###\n    _index = NumericProperty(0, allownone=True)\n    _prev = ObjectProperty(None, allownone=True)\n    _current = ObjectProperty(None, allownone=True)\n    _next = ObjectProperty(None, allownone=True)\n    _offset = NumericProperty(0)\n    _touch = ObjectProperty(None, allownone=True)\n\n    def __init__(self, **kwargs):\n        self._trigger_position_visible_slides = Clock.create_trigger(\n            self._position_visible_slides, -1)\n        super(Carousel, self).__init__(**kwargs)\n        self._skip_slide = None\n\n    def load_slide(self, slide):\n        '''Animate to the slide that is passed as the argument.\n\n        .. versionchanged:: 1.8.0\n        '''\n        slides = self.slides\n        start, stop = slides.index(self.current_slide), slides.index(slide)\n        if start == stop:\n            return\n\n        self._skip_slide = stop\n        if stop > start:\n            self._insert_visible_slides(_next_slide=slide)\n            self.load_next()\n        else:\n            self._insert_visible_slides(_prev_slide=slide)\n            self.load_previous()\n\n    def load_previous(self):\n        '''Animate to the previous slide.\n\n        .. versionadded:: 1.7.0\n        '''\n        self.load_next(mode='prev')\n\n    def load_next(self, mode='next'):\n        '''Animate to next slide.\n\n        .. versionadded:: 1.7.0\n        '''\n        if not self.index is None:\n            w, h = self.size\n            _direction = {\n                'top': -h / 2,\n                'bottom': h / 2,\n                'left': w / 2,\n                'right': -w / 2}\n            _offset = _direction[self.direction]\n            if mode == 'prev':\n                _offset = -_offset\n\n            self._start_animation(min_move=0, offset=_offset)\n\n    def get_slide_container(self, slide):\n        return slide.parent\n\n    def _insert_visible_slides(self, _next_slide=None, _prev_slide=None):\n        get_slide_container = self.get_slide_container\n\n        previous_slide = _prev_slide if _prev_slide else self.previous_slide\n        if previous_slide:\n            self._prev = get_slide_container(previous_slide)\n        else:\n            self._prev = None\n\n        current_slide = self.current_slide\n        if current_slide:\n            self._current = get_slide_container(current_slide)\n        else:\n            self._current = None\n\n        next_slide = _next_slide if _next_slide else self.next_slide\n        if next_slide:\n            self._next = get_slide_container(next_slide)\n        else:\n            self._next = None\n\n        super_remove = super(Carousel, self).remove_widget\n        for container in self.slides_container:\n            super_remove(container)\n\n        if self._prev:\n            super(Carousel, self).add_widget(self._prev)\n        if self._next:\n            super(Carousel, self).add_widget(self._next)\n        if self._current:\n            super(Carousel, self).add_widget(self._current)\n\n    def _position_visible_slides(self, *args):\n        slides, index = self.slides, self.index\n        no_of_slides = len(slides) - 1\n        if not slides:\n            return\n        x, y, width, height = self.x, self.y, self.width, self.height\n        _offset, direction = self._offset, self.direction\n        _prev, _next, _current = self._prev, self._next, self._current\n        get_slide_container = self.get_slide_container\n        last_slide = get_slide_container(slides[-1])\n        first_slide = get_slide_container(slides[0])\n        skip_next = False\n        _loop = self.loop\n\n        if direction[0] in ['r', 'l']:\n            xoff = x + _offset\n            x_prev = {'l': xoff + width, 'r': xoff - width}\n            x_next = {'l': xoff - width, 'r': xoff + width}\n            if _prev:\n                _prev.pos = (x_prev[direction[0]], y)\n            elif _loop and _next and index == 0:\n                # if first slide is moving to right with direction set to right\n                # or toward left with direction set to left\n                if ((_offset > 0 and direction[0] == 'r') or\n                        (_offset < 0 and direction[0] == 'l')):\n                    # put last_slide before first slide\n                    last_slide.pos = (x_prev[direction[0]], y)\n                    skip_next = True\n            if _current:\n                _current.pos = (xoff, y)\n            if skip_next:\n                return\n            if _next:\n                _next.pos = (x_next[direction[0]], y)\n            elif _loop and _prev and index == no_of_slides:\n                if ((_offset < 0 and direction[0] == 'r') or\n                        (_offset > 0 and direction[0] == 'l')):\n                    first_slide.pos = (x_next[direction[0]], y)\n        if direction[0] in ['t', 'b']:\n            yoff = y + _offset\n            y_prev = {'t': yoff - height, 'b': yoff + height}\n            y_next = {'t': yoff + height, 'b': yoff - height}\n            if _prev:\n                _prev.pos = (x, y_prev[direction[0]])\n            elif _loop and _next and index == 0:\n                if ((_offset > 0 and direction[0] == 't') or\n                        (_offset < 0 and direction[0] == 'b')):\n                    last_slide.pos = (x, y_prev[direction[0]])\n                    skip_next = True\n            if _current:\n                _current.pos = (x, yoff)\n            if skip_next:\n                return\n            if _next:\n                _next.pos = (x, y_next[direction[0]])\n            elif _loop and _prev and index == no_of_slides:\n                if ((_offset < 0 and direction[0] == 't') or\n                        (_offset > 0 and direction[0] == 'b')):\n                    first_slide.pos = (x, y_next[direction[0]])\n\n    def on_size(self, *args):\n        size = self.size\n        for slide in self.slides_container:\n            slide.size = size\n        self._trigger_position_visible_slides()\n\n    def on_pos(self, *args):\n        self._trigger_position_visible_slides()\n\n    def on_index(self, *args):\n        self._insert_visible_slides()\n        self._trigger_position_visible_slides()\n        self._offset = 0\n\n    def on_slides(self, *args):\n        if self.slides:\n            self.index = self.index % len(self.slides)\n        self._insert_visible_slides()\n        self._trigger_position_visible_slides()\n\n    def on__offset(self, *args):\n        self._trigger_position_visible_slides()\n        # if reached full offset, switch index to next or prev\n        direction = self.direction\n        _offset = self._offset\n        width = self.width\n        height = self.height\n        index = self.index\n        if self._skip_slide is not None or index is None:\n            return\n\n        if direction[0] == 'r':\n            if _offset <= -width:\n                index += 1\n            if _offset >= width:\n                index -= 1\n        if direction[0] == 'l':\n            if _offset <= -width:\n                index -= 1\n            if _offset >= width:\n                index += 1\n        if direction[0] == 't':\n            if _offset <= - height:\n                index += 1\n            if _offset >= height:\n                index -= 1\n        if direction[0] == 'b':\n            if _offset <= -height:\n                index -= 1\n            if _offset >= height:\n                index += 1\n        self.index = index\n\n    def _start_animation(self, *args, **kwargs):\n        # compute target offset for ease back, next or prev\n        new_offset = 0\n        direction = kwargs.get('direction', self.direction)\n        is_horizontal = direction[0] in ['r', 'l']\n        extent = self.width if is_horizontal else self.height\n        min_move = kwargs.get('min_move', self.min_move)\n        _offset = kwargs.get('offset', self._offset)\n\n        if _offset < min_move * -extent:\n            new_offset = -extent\n        elif _offset > min_move * extent:\n            new_offset = extent\n\n        # if new_offset is 0, it wasnt enough to go next/prev\n        dur = self.anim_move_duration\n        if new_offset == 0:\n            dur = self.anim_cancel_duration\n\n        # detect edge cases if not looping\n        len_slides = len(self.slides)\n        index = self.index\n        if not self.loop or len_slides == 1:\n            is_first = (index == 0)\n            is_last = (index == len_slides - 1)\n            if direction[0] in ['r', 't']:\n                towards_prev = (new_offset > 0)\n                towards_next = (new_offset < 0)\n            else:\n                towards_prev = (new_offset < 0)\n                towards_next = (new_offset > 0)\n            if (is_first and towards_prev) or (is_last and towards_next):\n                new_offset = 0\n\n        anim = Animation(_offset=new_offset, d=dur, t=self.anim_type)\n        anim.cancel_all(self)\n\n        def _cmp(*l):\n            if self._skip_slide is not None:\n                self.index = self._skip_slide\n                self._skip_slide = None\n\n        anim.bind(on_complete=_cmp)\n        anim.start(self)\n\n    def _get_uid(self, prefix='sv'):\n        return '{0}.{1}'.format(prefix, self.uid)\n\n    def on_touch_down(self, touch):\n        if not self.collide_point(*touch.pos):\n            touch.ud[self._get_uid('cavoid')] = True\n            return\n        if self.disabled:\n            return True\n        if self._touch:\n            return super(Carousel, self).on_touch_down(touch)\n        Animation.cancel_all(self)\n        self._touch = touch\n        uid = self._get_uid()\n        touch.grab(self)\n        touch.ud[uid] = {\n            'mode': 'unknown',\n            'time': touch.time_start}\n        Clock.schedule_once(self._change_touch_mode,\n                            self.scroll_timeout / 1000.)\n        return True\n\n    def on_touch_move(self, touch):\n        if self._get_uid('cavoid') in touch.ud:\n            return\n        if self._touch is not touch:\n            super(Carousel, self).on_touch_move(touch)\n            return self._get_uid() in touch.ud\n        if touch.grab_current is not self:\n            return True\n        ud = touch.ud[self._get_uid()]\n        direction = self.direction\n        if ud['mode'] == 'unknown':\n            if direction[0] in ('r', 'l'):\n                distance = abs(touch.ox - touch.x)\n            else:\n                distance = abs(touch.oy - touch.y)\n            if distance > self.scroll_distance:\n                Clock.unschedule(self._change_touch_mode)\n                ud['mode'] = 'scroll'\n        else:\n            if direction[0] in ('r', 'l'):\n                self._offset += touch.dx\n            if direction[0] in ('t', 'b'):\n                self._offset += touch.dy\n        return True\n\n    def on_touch_up(self, touch):\n        if self._get_uid('cavoid') in touch.ud:\n            return\n        if self in [x() for x in touch.grab_list]:\n            touch.ungrab(self)\n            self._touch = None\n            ud = touch.ud[self._get_uid()]\n            if ud['mode'] == 'unknown':\n                Clock.unschedule(self._change_touch_mode)\n                super(Carousel, self).on_touch_down(touch)\n                Clock.schedule_once(partial(self._do_touch_up, touch), .1)\n            else:\n                self._start_animation()\n\n        else:\n            if self._touch is not touch and self.uid not in touch.ud:\n                super(Carousel, self).on_touch_up(touch)\n        return self._get_uid() in touch.ud\n\n    def _do_touch_up(self, touch, *largs):\n        super(Carousel, self).on_touch_up(touch)\n        # don't forget about grab event!\n        for x in touch.grab_list[:]:\n            touch.grab_list.remove(x)\n            x = x()\n            if not x:\n                continue\n            touch.grab_current = x\n            super(Carousel, self).on_touch_up(touch)\n        touch.grab_current = None\n\n    def _change_touch_mode(self, *largs):\n        if not self._touch:\n            return\n        self._start_animation()\n        uid = self._get_uid()\n        touch = self._touch\n        ud = touch.ud[uid]\n        if ud['mode'] == 'unknown':\n            touch.ungrab(self)\n            self._touch = None\n            super(Carousel, self).on_touch_down(touch)\n            return\n\n    def add_widget(self, widget, index=0):\n        slide = RelativeLayout(size=self.size, x=self.x - self.width, y=self.y)\n        slide.add_widget(widget)\n        super(Carousel, self).add_widget(slide, index)\n        if index != 0:\n            self.slides.insert(index, widget)\n        else:\n            self.slides.append(widget)\n\n    def remove_widget(self, widget, *args, **kwargs):\n        # XXX be careful, the widget.parent refer to the RelativeLayout\n        # added in add_widget(). But it will break if RelativeLayout\n        # implementation change.\n        # if we passed the real widget\n        if widget in self.slides:\n            slide = widget.parent\n            self.slides.remove(widget)\n            return slide.remove_widget(widget, *args, **kwargs)\n        return super(Carousel, self).remove_widget(widget, *args, **kwargs)\n\n    def clear_widgets(self):\n        for slide in self.slides[:]:\n            self.remove_widget(slide)\n        super(Carousel, self).clear_widgets()\n\n\nif __name__ == '__main__':\n    from kivy.app import App\n\n    class Example1(App):\n\n        def build(self):\n            carousel = Carousel(direction='left',\n                                loop=True)\n            for i in range(4):\n                src = \"http://placehold.it/480x270.png&text=slide-%d&.png\" % i\n                image = Factory.AsyncImage(source=src, allow_stretch=True)\n                carousel.add_widget(image)\n            return carousel\n\n    Example1().run()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/checkbox.py",
    "content": "'''\nCheckBox\n========\n\n.. versionadded:: 1.4.0\n\n.. image:: images/checkbox.png\n    :align: right\n\n:class:`CheckBox` is a specific two-state button that can be either checked or\nunchecked. If the CheckBox is in a Group, it becomes a Radio button.\nAs with the :class:`~kivy.uix.togglebutton.ToggleButton`, only one Radio button\nat a time can be selected when the :attr:`CheckBox.group` is set.\n\nAn example usage::\n\n    from kivy.uix.checkbox import CheckBox\n\n    # ...\n\n    def on_checkbox_active(checkbox, value):\n        if value:\n            print('The checkbox', checkbox, 'is active')\n        else:\n            print('The checkbox', checkbox, 'is inactive')\n\n    checkbox = CheckBox()\n    checkbox.bind(active=on_checkbox_active)\n'''\n\n__all__ = ('CheckBox', )\n\nfrom kivy.uix.widget import Widget\nfrom kivy.properties import BooleanProperty, StringProperty\nfrom kivy.uix.behaviors import ToggleButtonBehavior\n\n\nclass CheckBox(ToggleButtonBehavior, Widget):\n    '''CheckBox class, see module documentation for more information.\n    '''\n\n    active = BooleanProperty(False)\n    '''Indicates if the switch is active or inactive.\n\n    :attr:`active` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    background_checkbox_normal = StringProperty(\n        'atlas://data/images/defaulttheme/checkbox_off')\n    '''Background image of the checkbox used for the default graphical\n    representation when the checkbox is not active.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`background_checkbox_normal` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/checkbox_off'.\n    '''\n\n    background_checkbox_down = StringProperty(\n        'atlas://data/images/defaulttheme/checkbox_on')\n    '''Background image of the checkbox used for the default graphical\n    representation when the checkbox is active.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`background_checkbox_down` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/checkbox_on'.\n    '''\n\n    background_checkbox_disabled_normal = StringProperty(\n        'atlas://data/images/defaulttheme/checkbox_disabled_off')\n    '''Background image of the checkbox used for the default graphical\n    representation when the checkbox is disabled and not active.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`background_checkbox_disabled_normal` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/checkbox_disabled_off'.\n    '''\n\n    background_checkbox_disabled_down = StringProperty(\n        'atlas://data/images/defaulttheme/checkbox_disabled_on')\n    '''Background image of the checkbox used for the default graphical\n    representation when the checkbox is disabled and active.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`background_checkbox_disabled_down` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/checkbox_disabled_on'.\n    '''\n\n    background_radio_normal = StringProperty(\n        'atlas://data/images/defaulttheme/checkbox_radio_off')\n    '''Background image of the radio button used for the default graphical\n    representation when the radio button is not active.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`background_radio_normal` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/checkbox_radio_off'.\n    '''\n\n    background_radio_down = StringProperty(\n        'atlas://data/images/defaulttheme/checkbox_radio_on')\n    '''Background image of the radio button used for the default graphical\n    representation when the radio button is active.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`background_radio_down` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/checkbox_radio_on'.\n    '''\n\n    background_radio_disabled_normal = StringProperty(\n        'atlas://data/images/defaulttheme/checkbox_radio_disabled_off')\n    '''Background image of the radio button used for the default graphical\n    representation when the radio button is disabled and not active.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`background_radio_disabled_normal` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/checkbox_radio_disabled_off'.\n    '''\n\n    background_radio_disabled_down = StringProperty(\n        'atlas://data/images/defaulttheme/checkbox_radio_disabled_on')\n    '''Background image of the radio button used for the default graphical\n    representation when the radio button is disabled and active.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`background_radio_disabled_down` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/checkbox_radio_disabled_on'.\n    '''\n\n    def on_state(self, instance, value):\n        if value == 'down':\n            self.active = True\n        else:\n            self.active = False\n\n    def _toggle_active(self):\n        self._do_press()\n\n    def on_active(self, instance, value):\n        self.state = 'down' if value else 'normal'\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/codeinput.py",
    "content": "'''\nCode Input\n==========\n\n.. versionadded:: 1.5.0\n\n.. image:: images/codeinput.jpg\n\n\nThe :class:`CodeInput` provides a box of editable highlighted text like the one\nshown in the image.\n\nIt supports all the features provided by the :class:`~kivy.uix.textinput` as\nwell as code highlighting for `languages supported by pygments\n<http://pygments.org/docs/lexers/>`_ along with `KivyLexer` for\n:mod:`kivy.lang` highlighting.\n\nUsage example\n-------------\n\nTo create a CodeInput with highlighting for `KV language`::\n\n    from kivy.uix.codeinput import CodeInput\n    from kivy.extras.highlight import KivyLexer\n    codeinput = CodeInput(lexer=KivyLexer())\n\nTo create a CodeInput with highlighting for `Cython`::\n\n    from kivy.uix.codeinput import CodeInput\n    from pygments.lexers import CythonLexer\n    codeinput = CodeInput(lexer=CythonLexer())\n\n'''\n\n__all__ = ('CodeInput', )\n\nfrom pygments import highlight\nfrom pygments import lexers\nfrom pygments import styles\nfrom pygments.formatters import BBCodeFormatter\n\nfrom kivy.uix.textinput import TextInput\nfrom kivy.core.text.markup import MarkupLabel as Label\nfrom kivy.cache import Cache\nfrom kivy.properties import ObjectProperty, OptionProperty\nfrom kivy.utils import get_hex_from_color\n\nCache_get = Cache.get\nCache_append = Cache.append\n\n# TODO: color chooser for keywords/strings/...\n\n\nclass CodeInput(TextInput):\n    '''CodeInput class, used for displaying highlighted code.\n    '''\n\n    lexer = ObjectProperty(None)\n    '''This holds the selected Lexer used by pygments to highlight the code.\n\n\n    :attr:`lexer` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to `PythonLexer`.\n    '''\n\n    style_name = OptionProperty(\n        'default', options=list(styles.get_all_styles())\n    )\n    '''Name of the pygments style to use for formatting.\n\n    :attr:`style_name` is an :class:`~kivy.properties.OptionProperty`\n    and defaults to ``'default'``.\n\n    '''\n\n    style = ObjectProperty(None)\n    '''The pygments style object to use for formatting.\n\n    When ``style_name`` is set, this will be changed to the\n    corresponding style object.\n\n    :attr:`style` is a :class:`~kivy.properties.ObjectProperty` and\n    defaults to ``None``\n\n    '''\n\n    def __init__(self, **kwargs):\n        stylename = kwargs.get('style_name', 'default')\n        style = kwargs['style'] if 'style' in kwargs \\\n            else styles.get_style_by_name(stylename)\n        self.formatter = BBCodeFormatter(style=style)\n        self.lexer = lexers.PythonLexer()\n        self.text_color = '#000000'\n        self._label_cached = Label()\n        self.use_text_color = True\n\n        super(CodeInput, self).__init__(**kwargs)\n\n        self._line_options = kw = self._get_line_options()\n        self._label_cached = Label(**kw)\n        # use text_color as foreground color\n        text_color = kwargs.get('foreground_color')\n        if text_color:\n            self.text_color = get_hex_from_color(text_color)\n        # set foreground to white to allow text colors to show\n        # use text_color as the default color in bbcodes\n        self.use_text_color = False\n        self.foreground_color = [1, 1, 1, .999]\n        if not kwargs.get('background_color'):\n            self.background_color = [.9, .92, .92, 1]\n\n    def on_style_name(self, *args):\n        self.style = styles.get_style_by_name(self.style_name)\n\n    def on_style(self, *args):\n        self.formatter = BBCodeFormatter(style=self.style)\n        self._trigger_update_graphics()\n\n    def _create_line_label(self, text, hint=False):\n        # Create a label from a text, using line options\n        ntext = text.replace(u'\\n', u'').replace(u'\\t', u' ' * self.tab_width)\n        if self.password and not hint:  # Don't replace hint_text with *\n            ntext = u'*' * len(ntext)\n        ntext = self._get_bbcode(ntext)\n        kw = self._get_line_options()\n        cid = u'{}\\0{}\\0{}'.format(ntext, self.password, kw)\n        texture = Cache_get('textinput.label', cid)\n\n        if texture is None:\n            # FIXME right now, we can't render very long line...\n            # if we move on \"VBO\" version as fallback, we won't need to\n            # do this.\n            # try to find the maximum text we can handle\n            label = Label(text=ntext, **kw)\n            if text.find(u'\\n') > 0:\n                label.text = u''\n            else:\n                label.text = ntext\n            label.refresh()\n\n            # ok, we found it.\n            texture = label.texture\n            Cache_append('textinput.label', cid, texture)\n            label.text = ''\n        return texture\n\n    def _get_line_options(self):\n        kw = super(CodeInput, self)._get_line_options()\n        kw['markup'] = True\n        kw['valign'] = 'top'\n        kw['codeinput'] = repr(self.lexer)\n        return kw\n\n    def _get_text_width(self, text, tab_width, _label_cached):\n        # Return the width of a text, according to the current line options.\n        cid = u'{}\\0{}\\0{}'.format(text, self.password,\n                                   self._get_line_options())\n        width = Cache_get('textinput.width', cid)\n        if width is not None:\n            return width\n        lbl = self._create_line_label(text)\n        width = lbl.width\n        Cache_append('textinput.width', cid, width)\n        return width\n\n    def _get_bbcode(self, ntext):\n        # get bbcoded text for python\n        try:\n            ntext[0]\n            # replace brackets with special chars that aren't highlighted\n            # by pygment. can't use &bl; ... cause & is highlighted\n            ntext = ntext.replace(u'[', u'\\x01;').replace(u']', u'\\x02;')\n            ntext = highlight(ntext, self.lexer, self.formatter)\n            ntext = ntext.replace(u'\\x01;', u'&bl;').replace(u'\\x02;', u'&br;')\n            # replace special chars with &bl; and &br;\n            ntext = ''.join((u'[color=', str(self.text_color), u']',\n                             ntext, u'[/color]'))\n            ntext = ntext.replace(u'\\n', u'')\n            return ntext\n        except IndexError:\n            return ''\n\n    # overriden to prevent cursor position off screen\n    def _cursor_offset(self):\n        '''Get the cursor x offset on the current line\n        '''\n        offset = 0\n        try:\n            if self.cursor_col:\n                offset = self._get_text_width(\n                    self._lines[self.cursor_row][:self.cursor_col])\n                return offset\n        except:\n            pass\n        finally:\n            return offset\n\n    def on_lexer(self, instance, value):\n        self._trigger_refresh_text()\n\n    def on_foreground_color(self, instance, text_color):\n        if not self.use_text_color:\n            self.use_text_color = True\n            return\n        self.text_color = get_hex_from_color(text_color)\n        self.use_text_color = False\n        self.foreground_color = (1, 1, 1, .999)\n        self._trigger_refresh_text()\n\n\nif __name__ == '__main__':\n    from kivy.extras.highlight import KivyLexer\n    from kivy.app import App\n\n    class CodeInputTest(App):\n        def build(self):\n            return CodeInput(lexer=KivyLexer(),\n                             font_name='data/fonts/DroidSansMono.ttf',\n                             font_size=12,\n                             text='''\n#:kivy 1.0\n\n<YourWidget>:\n    canvas:\n        Color:\n            rgb: .5, .5, .5\n        Rectangle:\n            pos: self.pos\n            size: self.size''')\n\n    CodeInputTest().run()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/colorpicker.py",
    "content": "'''\nColor Picker\n============\n\n.. versionadded:: 1.7.0\n\n.. warning::\n\n    This widget is experimental. Its use and API can change at any time until\n    this warning is removed.\n\n\nThe ColorPicker widget allows a user to select a color from a chromatic\nwheel where pinch and zoom can be used to change the wheel's saturation.\nSliders and TextInputs are also provided for entering the RGBA/HSV/HEX values\ndirectly.\n\nUsage::\n\n    clr_picker = ColorPicker()\n    parent.add_widget(clr_picker)\n\n    # To monitor changes, we can bind to color property changes\n    def on_color(instance, value):\n        print \"RGBA = \", str(value)  #  or instance.color\n        print \"HSV = \", str(instance.hsv)\n        print \"HEX = \", str(instance.hex_color)\n\n    clr_picker.bind(color=on_color)\n\n'''\n\n__all__ = ('ColorPicker', 'ColorWheel')\n\nfrom kivy.uix.relativelayout import RelativeLayout\nfrom kivy.uix.widget import Widget\nfrom kivy.properties import (NumericProperty, BoundedNumericProperty,\n                             ListProperty, ObjectProperty,\n                             ReferenceListProperty, StringProperty,\n                             AliasProperty)\nfrom kivy.clock import Clock\nfrom kivy.graphics import Mesh, InstructionGroup, Color\nfrom kivy.utils import get_color_from_hex, get_hex_from_color\nfrom kivy.logger import Logger\nfrom math import cos, sin, pi, sqrt, atan\nfrom colorsys import rgb_to_hsv, hsv_to_rgb\n\n\ndef distance(pt1, pt2):\n    return sqrt((pt1[0] - pt2[0]) ** 2. + (pt1[1] - pt2[1]) ** 2.)\n\n\ndef polar_to_rect(origin, r, theta):\n    return origin[0] + r * cos(theta), origin[1] + r * sin(theta)\n\n\ndef rect_to_polar(origin, x, y):\n    if x == origin[0]:\n        if y == origin[1]:\n            return (0, 0)\n        elif y > origin[1]:\n            return (y - origin[1], pi / 2.)\n        else:\n            return (origin[1] - y, 3 * pi / 2.)\n    t = atan(float((y - origin[1])) / (x - origin[0]))\n    if x - origin[0] < 0:\n        t += pi\n\n    if t < 0:\n        t += 2 * pi\n\n    return (distance((x, y), origin), t)\n\n\nclass ColorWheel(Widget):\n    '''Chromatic wheel for the ColorPicker.\n\n    .. versionchanged:: 1.7.1\n        `font_size`, `font_name` and `foreground_color` have been removed. The\n        sizing is now the same as others widget, based on 'sp'. Orientation is\n        also automatically determined according to the width/height ratio.\n\n    '''\n\n    r = BoundedNumericProperty(0, min=0, max=1)\n    '''The Red value of the color currently selected.\n\n    :attr:`r` is a :class:`~kivy.properties.BoundedNumericProperty` and\n    can be a value from 0 to 1. It defaults to 0.\n    '''\n\n    g = BoundedNumericProperty(0, min=0, max=1)\n    '''The Green value of the color currently selected.\n\n    :attr:`g` is a :class:`~kivy.properties.BoundedNumericProperty`\n    and can be a value from 0 to 1.\n    '''\n\n    b = BoundedNumericProperty(0, min=0, max=1)\n    '''The Blue value of the color currently selected.\n\n    :attr:`b` is a :class:`~kivy.properties.BoundedNumericProperty` and\n    can be a value from 0 to 1.\n    '''\n\n    a = BoundedNumericProperty(0, min=0, max=1)\n    '''The Alpha value of the color currently selected.\n\n    :attr:`a` is a :class:`~kivy.properties.BoundedNumericProperty` and\n    can be a value from 0 to 1.\n    '''\n\n    color = ReferenceListProperty(r, g, b, a)\n    '''The holds the color currently selected.\n\n    :attr:`color` is a :class:`~kivy.properties.ReferenceListProperty` and\n    contains a list of `r`, `g`, `b`, `a` values.\n    '''\n\n    _origin = ListProperty((100, 100))\n    _radius = NumericProperty(100)\n\n    _piece_divisions = NumericProperty(10)\n    _pieces_of_pie = NumericProperty(16)\n\n    _inertia_slowdown = 1.25\n    _inertia_cutoff = .25\n\n    _num_touches = 0\n    _pinch_flag = False\n\n    _hsv = ListProperty([1, 1, 1, 0])\n\n    def __init__(self, **kwargs):\n        super(ColorWheel, self).__init__(**kwargs)\n\n        pdv = self._piece_divisions\n        self.sv_s = [(float(x) / pdv, 1) for x in range(pdv)] + [\n            (1, float(y) / pdv) for y in reversed(range(pdv))]\n\n    def on__origin(self, instance, value):\n        self.init_wheel(None)\n\n    def on__radius(self, instance, value):\n        self.init_wheel(None)\n\n    def init_wheel(self, dt):\n        # initialize list to hold all meshes\n        self.canvas.clear()\n        self.arcs = []\n        self.sv_idx = 0\n        pdv = self._piece_divisions\n        ppie = self._pieces_of_pie\n\n        for r in range(pdv):\n            for t in range(ppie):\n                self.arcs.append(\n                    _ColorArc(\n                        self._radius * (float(r) / float(pdv)),\n                        self._radius * (float(r + 1) / float(pdv)),\n                        2 * pi * (float(t) / float(ppie)),\n                        2 * pi * (float(t + 1) / float(ppie)),\n                        origin=self._origin,\n                        color=(float(t) / ppie,\n                               self.sv_s[self.sv_idx + r][0],\n                               self.sv_s[self.sv_idx + r][1],\n                               1)))\n\n                self.canvas.add(self.arcs[-1])\n\n    def recolor_wheel(self):\n        ppie = self._pieces_of_pie\n        for idx, segment in enumerate(self.arcs):\n            segment.change_color(\n                sv=self.sv_s[int(self.sv_idx + idx / ppie)])\n\n    def change_alpha(self, val):\n        for idx, segment in enumerate(self.arcs):\n            segment.change_color(a=val)\n\n    def inertial_incr_sv_idx(self, dt):\n        # if its already zoomed all the way out, cancel the inertial zoom\n        if self.sv_idx == len(self.sv_s) - self._piece_divisions:\n            return False\n\n        self.sv_idx += 1\n        self.recolor_wheel()\n        if dt * self._inertia_slowdown > self._inertia_cutoff:\n            return False\n        else:\n            Clock.schedule_once(self.inertial_incr_sv_idx,\n                                dt * self._inertia_slowdown)\n\n    def inertial_decr_sv_idx(self, dt):\n        # if its already zoomed all the way in, cancel the inertial zoom\n        if self.sv_idx == 0:\n            return False\n        self.sv_idx -= 1\n        self.recolor_wheel()\n        if dt * self._inertia_slowdown > self._inertia_cutoff:\n            return False\n        else:\n            Clock.schedule_once(self.inertial_decr_sv_idx,\n                                dt * self._inertia_slowdown)\n\n    def on_touch_down(self, touch):\n        r = self._get_touch_r(touch.pos)\n        if r > self._radius:\n            return False\n\n        # code is still set up to allow pinch to zoom, but this is\n        # disabled for now since it was fiddly with small wheels.\n        # Comment out these lines and  adjust on_touch_move to reenable\n        # this.\n        if self._num_touches != 0:\n            return False\n\n        touch.grab(self)\n        self._num_touches += 1\n        touch.ud['anchor_r'] = r\n        touch.ud['orig_sv_idx'] = self.sv_idx\n        touch.ud['orig_time'] = Clock.get_time()\n\n    def on_touch_move(self, touch):\n        if touch.grab_current is not self:\n            return\n        r = self._get_touch_r(touch.pos)\n        goal_sv_idx = (touch.ud['orig_sv_idx']\n                       - int((r - touch.ud['anchor_r'])\n                             / (float(self._radius) / self._piece_divisions)))\n\n        if (\n            goal_sv_idx != self.sv_idx and\n            goal_sv_idx >= 0 and\n            goal_sv_idx <= len(self.sv_s) - self._piece_divisions\n        ):\n            # this is a pinch to zoom\n            self._pinch_flag = True\n            self.sv_idx = goal_sv_idx\n            self.recolor_wheel()\n\n    def on_touch_up(self, touch):\n        if touch.grab_current is not self:\n            return\n        touch.ungrab(self)\n        self._num_touches -= 1\n        if self._pinch_flag:\n            if self._num_touches == 0:\n                # user was pinching, and now both fingers are up. Return\n                # to normal\n                if self.sv_idx > touch.ud['orig_sv_idx']:\n                    Clock.schedule_once(\n                        self.inertial_incr_sv_idx,\n                        (Clock.get_time() - touch.ud['orig_time'])\n                        / (self.sv_idx - touch.ud['orig_sv_idx']))\n\n                if self.sv_idx < touch.ud['orig_sv_idx']:\n                    Clock.schedule_once(\n                        self.inertial_decr_sv_idx,\n                        (Clock.get_time() - touch.ud['orig_time'])\n                        / (self.sv_idx - touch.ud['orig_sv_idx']))\n\n                self._pinch_flag = False\n                return\n            else:\n                # user was pinching, and at least one finger remains. We\n                # don't want to treat the remaining fingers as touches\n                return\n        else:\n            r, theta = rect_to_polar(self._origin, *touch.pos)\n            # if touch up is outside the wheel, ignore\n            if r >= self._radius:\n                return\n            # compute which ColorArc is being touched (they aren't\n            # widgets so we don't get collide_point) and set\n            # _hsv based on the selected ColorArc\n            piece = int((theta / (2 * pi)) * self._pieces_of_pie)\n            division = int((r / self._radius) * self._piece_divisions)\n            self._hsv = \\\n                self.arcs[self._pieces_of_pie * division + piece].color\n\n    def on__hsv(self, instance, value):\n        c_hsv = Color(*value, mode='hsv')\n        self.r = c_hsv.r\n        self.g = c_hsv.g\n        self.b = c_hsv.b\n        self.a = c_hsv.a\n        self.rgba = (self.r, self.g, self.b, self.a)\n\n    def _get_touch_r(self, pos):\n        return distance(pos, self._origin)\n\n\nclass _ColorArc(InstructionGroup):\n    def __init__(self, r_min, r_max, theta_min, theta_max,\n                 color=(0, 0, 1, 1), origin = (0, 0), **kwargs):\n        super(_ColorArc, self).__init__(**kwargs)\n        self.origin = origin\n        self.r_min = r_min\n        self.r_max = r_max\n        self.theta_min = theta_min\n        self.theta_max = theta_max\n        self.color = color\n        self.color_instr = Color(*color, mode='hsv')\n        self.add(self.color_instr)\n        self.mesh = self.get_mesh()\n        self.add(self.mesh)\n\n    def __str__(self):\n        return \"r_min: %s r_max: %s theta_min: %s theta_max: %s color: %s\" % (\n            self.r_min, self.r_max, self.theta_min, self.theta_max, self.color\n        )\n\n    def get_mesh(self):\n        v = []\n        # first calculate the distance between endpoints of the inner\n        # arc, so we know how many steps to use when calculating\n        # vertices\n        end_point_inner = polar_to_rect(\n            self.origin, self.r_min, self.theta_max)\n\n        d_inner = d_outer = 3.\n        theta_step_inner = (self.theta_max - self.theta_min) / d_inner\n\n        end_point_outer = polar_to_rect(\n            self.origin, self.r_max, self.theta_max)\n\n        if self.r_min == 0:\n            theta_step_outer = (self.theta_max - self.theta_min) / d_outer\n            for x in range(int(d_outer)):\n                v += (polar_to_rect(self.origin, 0, 0) * 2)\n                v += (polar_to_rect(\n                    self.origin, self.r_max,\n                    self.theta_min + x * theta_step_outer) * 2)\n        else:\n            for x in range(int(d_inner + 2)):\n                v += (polar_to_rect(\n                    self.origin, self.r_min - 1,\n                    self.theta_min + x * theta_step_inner) * 2)\n                v += (polar_to_rect(\n                    self.origin, self.r_max + 1,\n                    self.theta_min + x * theta_step_inner) * 2)\n\n        v += (end_point_inner * 2)\n        v += (end_point_outer * 2)\n\n        return Mesh(vertices=v, indices=range(int(len(v) / 4)),\n                    mode='triangle_strip')\n\n    def change_color(self, color=None, color_delta=None, sv=None, a=None):\n        self.remove(self.color_instr)\n        if color is not None:\n            self.color = color\n        elif color_delta is not None:\n            self.color = [self.color[i] + color_delta[i] for i in range(4)]\n        elif sv is not None:\n            self.color = (self.color[0], sv[0], sv[1], self.color[3])\n        elif a is not None:\n            self.color = (self.color[0], self.color[1], self.color[2], a)\n        self.color_instr = Color(*self.color, mode='hsv')\n        self.insert(0, self.color_instr)\n\n\nclass ColorPicker(RelativeLayout):\n    '''\n    See module documentation.\n    '''\n\n    font_name = StringProperty('data/fonts/DroidSansMono.ttf')\n    '''Specifies the font used on the ColorPicker.\n\n    :attr:`font_name` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'data/fonts/DroidSansMono.ttf'.\n    '''\n\n    color = ListProperty((1, 1, 1, 1))\n    '''The :attr:`color` holds the color currently selected in rgba format.\n\n    :attr:`color` is a :class:`~kivy.properties.ListProperty` and defaults to\n    (1, 1, 1, 1).\n    '''\n\n    hsv = ListProperty((1, 1, 1))\n    '''The :attr:`hsv` holds the color currently selected in hsv format.\n\n    :attr:`hsv` is a :class:`~kivy.properties.ListProperty` and defaults to\n    (1, 1, 1).\n    '''\n    def _get_hex(self):\n        return get_hex_from_color(self.color)\n\n    def _set_hex(self, value):\n        self.color = get_color_from_hex(value)[:4]\n\n    hex_color = AliasProperty(_get_hex, _set_hex, bind=('color', ))\n    '''The :attr:`hex_color` holds the currently selected color in hex.\n\n    :attr:`hex_color` is an :class:`~kivy.properties.AliasProperty` and\n    defaults to `#ffffffff`.\n    '''\n\n    wheel = ObjectProperty(None)\n    '''The :attr:`wheel` holds the color wheel.\n\n    :attr:`wheel` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    # now used only internally.\n    foreground_color = ListProperty((1, 1, 1, 1))\n\n    def on_color(self, instance, value):\n        if not self._updating_clr:\n            self._updating_clr = True\n            self.hsv = rgb_to_hsv(*value[:3])\n            self._updating_clr = False\n\n    def on_hsv(self, instance, value):\n        if not self._updating_clr:\n            self._updating_clr = True\n            self.color[:3] = hsv_to_rgb(*value)\n            self._updating_clr = False\n\n    def _trigger_update_clr(self, mode, clr_idx, text):\n        self._upd_clr_list = mode, clr_idx, text\n        Clock.unschedule(self._update_clr)\n        Clock.schedule_once(self._update_clr)\n\n    def _update_clr(self, dt):\n        mode, clr_idx, text = self._upd_clr_list\n        try:\n            text = min(255, max(0, float(text)))\n            if mode == 'rgb':\n                self.color[clr_idx] = float(text) / 255.\n            else:\n                self.hsv[clr_idx] = float(text) / 255.\n        except ValueError:\n            Logger.warning('ColorPicker: invalid value : {}'.format(text))\n\n    def _update_hex(self, dt):\n        if len(self._upd_hex_list) != 9:\n            return\n        self.hex_color = self._upd_hex_list\n\n    def _trigger_update_hex(self, text):\n        self._upd_hex_list = text\n        Clock.unschedule(self._update_hex)\n        Clock.schedule_once(self._update_hex)\n\n    def __init__(self, **kwargs):\n        self._updating_clr = False\n        super(ColorPicker, self).__init__(**kwargs)\n\n\nif __name__ in ('__android__', '__main__'):\n    from kivy.app import App\n\n    class ColorPickerApp(App):\n        def build(self):\n            cp = ColorPicker(pos_hint={'center_x': .5, 'center_y': .5},\n                             size_hint=(1, 1))\n            return cp\n    ColorPickerApp().run()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/dropdown.py",
    "content": "'''\nDrop-Down List\n==============\n\n.. versionadded:: 1.4.0\n\nA versatile drop-down list that can be used with custom widgets. It allows you\nto display a list of widgets under a displayed widget. Unlike other toolkits,\nthe list of widgets can contain any type of widget: simple buttons,\nimages etc.\n\nThe positioning of the drop-down list is fully automatic: we will always try to\nplace the dropdown list in a way that the user can select an item in the list.\n\nBasic example\n-------------\n\nA button with a dropdown list of 10 possible values. All the buttons within the\ndropdown list will trigger the dropdown :meth:`DropDown.select` method. After\nbeing called, the main button text will display the selection of the\ndropdown. ::\n\n    from kivy.uix.dropdown import DropDown\n    from kivy.uix.button import Button\n    from kivy.base import runTouchApp\n\n    # create a dropdown with 10 buttons\n    dropdown = DropDown()\n    for index in range(10):\n        # when adding widgets, we need to specify the height manually (disabling\n        # the size_hint_y) so the dropdown can calculate the area it needs.\n        btn = Button(text='Value %d' % index, size_hint_y=None, height=44)\n\n        # for each button, attach a callback that will call the select() method\n        # on the dropdown. We'll pass the text of the button as the data of the\n        # selection.\n        btn.bind(on_release=lambda btn: dropdown.select(btn.text))\n\n        # then add the button inside the dropdown\n        dropdown.add_widget(btn)\n\n    # create a big main button\n    mainbutton = Button(text='Hello', size_hint=(None, None))\n\n    # show the dropdown menu when the main button is released\n    # note: all the bind() calls pass the instance of the caller (here, the\n    # mainbutton instance) as the first argument of the callback (here,\n    # dropdown.open.).\n    mainbutton.bind(on_release=dropdown.open)\n\n    # one last thing, listen for the selection in the dropdown list and\n    # assign the data to the button text.\n    dropdown.bind(on_select=lambda instance, x: setattr(mainbutton, 'text', x))\n\n    runTouchApp(mainbutton)\n\nExtending dropdown in Kv\n------------------------\n\nYou could create a dropdown directly from your kv::\n\n    #:kivy 1.4.0\n    <CustomDropDown>:\n        Button:\n            text: 'My first Item'\n            size_hint_y: None\n            height: 44\n            on_release: root.select('item1')\n        Label:\n            text: 'Unselectable item'\n            size_hint_y: None\n            height: 44\n        Button:\n            text: 'My second Item'\n            size_hint_y: None\n            height: 44\n            on_release: root.select('item2')\n\nAnd then, create the associated python class and use it::\n\n    class CustomDropDown(DropDown):\n        pass\n\n    dropdown = CustomDropDown()\n    mainbutton = Button(text='Hello', size_hint=(None, None))\n    mainbutton.bind(on_release=dropdown.open)\n    dropdown.bind(on_select=lambda instance, x: setattr(mainbutton, 'text', x))\n'''\n\n__all__ = ('DropDown', )\n\nfrom kivy.uix.scrollview import ScrollView\nfrom kivy.properties import ObjectProperty, NumericProperty, BooleanProperty\nfrom kivy.core.window import Window\nfrom kivy.lang import Builder\n\n_grid_kv = '''\nGridLayout:\n    size_hint_y: None\n    height: self.minimum_size[1]\n    cols: 1\n'''\n\n\nclass DropDownException(Exception):\n    '''DropDownException class.\n    '''\n    pass\n\n\nclass DropDown(ScrollView):\n    '''DropDown class. See module documentation for more information.\n\n    :Events:\n        `on_select`: data\n            Fired when a selection is done. The data of the selection is passed\n            in as the first argument and is what you pass in the :meth:`select`\n            method as the first argument.\n        `on_dismiss`:\n            .. versionadded:: 1.8.0\n\n            Fired when the DropDown is dismissed, either on selection or on\n            touching outside the widget.\n    '''\n\n    auto_width = BooleanProperty(True)\n    '''By default, the width of the dropdown will be the same as the width of\n    the attached widget. Set to False if you want to provide your own width.\n    '''\n\n    max_height = NumericProperty(None, allownone=True)\n    '''Indicate the maximum height that the dropdown can take. If None, it will\n    take the maximum height available until the top or bottom of the screen\n    is reached.\n\n    :attr:`max_height` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to None.\n    '''\n\n    dismiss_on_select = BooleanProperty(True)\n    '''By default, the dropdown will be automatically dismissed when a\n    selection has been done. Set to False to prevent the dismiss.\n\n    :attr:`dismiss_on_select` is a :class:`~kivy.properties.BooleanProperty`\n    and defaults to True.\n    '''\n\n    auto_dismiss = BooleanProperty(True)\n    '''By default, the dropdown will be automatically dismissed when a\n    touch happens outside of it, this option allow to disable this\n    feature\n\n    :attr:`auto_dismiss` is a :class:`~kivy.properties.BooleanProperty`\n    and defaults to True.\n\n    .. versionadded:: 1.8.0\n    '''\n\n    attach_to = ObjectProperty(allownone=True)\n    '''(internal) Property that will be set to the widget to which the\n    drop down list is attached.\n\n    The :meth:`open` method will automatically set this property whilst\n    :meth:`dismiss` will set it back to None.\n    '''\n\n    container = ObjectProperty()\n    '''(internal) Property that will be set to the container of the dropdown\n    list. It is a :class:`~kivy.uix.gridlayout.GridLayout` by default.\n    '''\n\n    __events__ = ('on_select', 'on_dismiss')\n\n    def __init__(self, **kwargs):\n        self._win = None\n        if 'container' not in kwargs:\n            c = self.container = Builder.load_string(_grid_kv)\n        else:\n            c = None\n        kwargs.setdefault('do_scroll_x', False)\n        if 'size_hint' not in kwargs:\n            kwargs.setdefault('size_hint_x', None)\n            kwargs.setdefault('size_hint_y', None)\n        super(DropDown, self).__init__(**kwargs)\n        if c is not None:\n            super(DropDown, self).add_widget(c)\n            self.on_container(self, c)\n        Window.bind(on_key_down=self.on_key_down)\n        self.bind(size=self._reposition)\n\n    def on_key_down(self, instance, key, scancode, codepoint, modifiers):\n        if key == 27 and self.get_parent_window():\n            self.dismiss()\n            return True\n\n    def on_container(self, instance, value):\n        if value is not None:\n            self.container.bind(minimum_size=self._container_minimum_size)\n\n    def open(self, widget):\n        '''Open the dropdown list and attach it to a specific widget.\n        Depending on the position of the widget within the window and\n        the height of the dropdown, the dropdown might be above or below\n        that widget.\n        '''\n        # ensure we are not already attached\n        if self.attach_to is not None:\n            self.dismiss()\n\n        # we will attach ourself to the main window, so ensure the\n        # widget we are looking for have a window\n        self._win = widget.get_parent_window()\n        if self._win is None:\n            raise DropDownException(\n                'Cannot open a dropdown list on a hidden widget')\n\n        self.attach_to = widget\n        widget.bind(pos=self._reposition, size=self._reposition)\n        self._reposition()\n\n        # attach ourself to the main window\n        self._win.add_widget(self)\n\n    def dismiss(self, *largs):\n        '''Remove the dropdown widget from the window and detach it from\n        the attached widget.\n        '''\n        if self.parent:\n            self.parent.remove_widget(self)\n        if self.attach_to:\n            self.attach_to.unbind(pos=self._reposition, size=self._reposition)\n            self.attach_to = None\n        self.dispatch('on_dismiss')\n\n    def on_dismiss(self):\n        pass\n\n    def select(self, data):\n        '''Call this method to trigger the `on_select` event with the `data`\n        selection. The `data` can be anything you want.\n        '''\n        self.dispatch('on_select', data)\n        if self.dismiss_on_select:\n            self.dismiss()\n\n    def on_select(self, data):\n        pass\n\n    def _container_minimum_size(self, instance, size):\n        if self.max_height:\n            self.height = min(size[1], self.max_height)\n            self.do_scroll_y = size[1] > self.max_height\n        else:\n            self.height = size[1]\n            self.do_scroll_y = True\n\n    def add_widget(self, *largs):\n        if self.container:\n            return self.container.add_widget(*largs)\n        return super(DropDown, self).add_widget(*largs)\n\n    def remove_widget(self, *largs):\n        if self.container:\n            return self.container.remove_widget(*largs)\n        return super(DropDown, self).remove_widget(*largs)\n\n    def clear_widgets(self):\n        if self.container:\n            return self.container.clear_widgets()\n        return super(DropDown, self).clear_widgets()\n\n    def on_touch_down(self, touch):\n        if super(DropDown, self).on_touch_down(touch):\n            return True\n        if self.collide_point(*touch.pos):\n            return True\n        if self.attach_to and self.attach_to.collide_point(*touch.pos):\n            return True\n        if self.auto_dismiss:\n            self.dismiss()\n\n    def on_touch_up(self, touch):\n        if super(DropDown, self).on_touch_up(touch):\n            return True\n        if 'button' in touch.profile and touch.button.startswith('scroll'):\n            return\n        if self.auto_dismiss:\n            self.dismiss()\n\n    def _reposition(self, *largs):\n        # calculate the coordinate of the attached widget in the window\n        # coordinate system\n        win = self._win\n        widget = self.attach_to\n        if not widget or not win:\n            return\n        wx, wy = widget.to_window(*widget.pos)\n        wright, wtop = widget.to_window(widget.right, widget.top)\n\n        # set width and x\n        if self.auto_width:\n            self.width = wright - wx\n\n        # ensure the dropdown list doesn't get out on the X axis, with a\n        # preference to 0 in case the list is too wide.\n        x = wx\n        if x + self.width > win.width:\n            x = win.width - self.width\n        if x < 0:\n            x = 0\n        self.x = x\n\n        # determine if we display the dropdown upper or lower to the widget\n        h_bottom = wy - self.height\n        h_top = win.height - (wtop + self.height)\n        if h_bottom > 0:\n            self.top = wy\n        elif h_top > 0:\n            self.y = wtop\n        else:\n            # none of both top/bottom have enough place to display the\n            # widget at the current size. Take the best side, and fit to\n            # it.\n            height = max(h_bottom, h_top)\n            if height == h_bottom:\n                self.top = wy\n                self.height = wy\n            else:\n                self.y = wtop\n                self.height = win.height - wtop\n\n\nif __name__ == '__main__':\n    from kivy.uix.button import Button\n    from kivy.base import runTouchApp\n\n    def show_dropdown(button, *largs):\n        dp = DropDown()\n        dp.bind(on_select=lambda instance, x: setattr(button, 'text', x))\n        for i in range(10):\n            item = Button(text='hello %d' % i, size_hint_y=None, height=44)\n            item.bind(on_release=lambda btn: dp.select(btn.text))\n            dp.add_widget(item)\n        dp.open(button)\n\n    def touch_move(instance, touch):\n        instance.center = touch.pos\n\n    btn = Button(text='SHOW', size_hint=(None, None), pos=(300, 200))\n    btn.bind(on_release=show_dropdown, on_touch_move=touch_move)\n\n    runTouchApp(btn)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/effectwidget.py",
    "content": "'''\nEffectWidget\n============\n\n.. versionadded:: 1.9.0\n\n    This code is still experimental, and its API is subject to change in a\n    future version.\n\nThe :class:`EffectWidget` is able to apply a variety of fancy\ngraphical effects to\nits children. It works by rendering to a series of\n:class:`~kivy.graphics.Fbo` instances with custom opengl fragment shaders.\nAs such, effects can freely do almost anything, from inverting the\ncolors of the widget, to antialiasing, to emulating the appearance of a\ncrt monitor!\n\nThe basic usage is as follows::\n\n    w = EffectWidget()\n    w.add_widget(Button(text='Hello!')\n    w.effects = [InvertEffect(), HorizontalBlurEffect(size=2.0)]\n\nThe effects can be a list of effects of any length, and they will be\napplied sequentially.\n\nThe module comes with a range of prebuilt effects, but the interface\nis designed to make it easy to create your own. Instead of writing a\nfull glsl shader, you provide a single function that takes\nsome inputs based on the screen (current pixel color, current widget\ntexture etc.). See the sections below for more information.\n\n.. note:: It is not efficient to resize an :class:`EffectWidget`, as\n          each :class:`~kivy.graphics.Fbo` is recreated every time.\n          If you need to resize frequently, consider doing things a\n          different way.\n\n.. note:: Although some effects have adjustable parameters, it is\n          *not* efficient to animate these, as the entire\n          shader is reconstructed every time. You should use glsl\n          uniform variables instead. The :class:`AdvancedEffectBase`\n          may make this easier.\n\n.. note:: The :class:`EffectWidget` *cannot* draw outside its own\n          widget area (pos -> pos + size), any child widgets\n          overlapping the boundary will be cut off at this point.\n\nProvided Effects\n----------------\n\nThe module comes with several pre-written effects. Some have\nadjustable properties (e.g. blur radius), see the individual\neffect documentation for more details.\n\n- :class:`MonochromeEffect` - makes the widget grayscale.\n- :class:`InvertEffect` - inverts the widget colors.\n- :class:`ChannelMixEffect` - swaps around color channels.\n- :class:`ScanlinesEffect` - displays flickering scanlines.\n- :class:`PixelateEffect` - pixelates the image.\n- :class:`HorizontalBlurEffect` - Gaussuan blurs horizontally.\n- :class:`VerticalBlurEffect` - Gaussuan blurs vertically.\n- :class:`FXAAEffect` - applies a very basic AA.\n\nCreating Effects\n----------------\n\nEffects are designed to make it easy to create and use your own\ntransformations. You do this by creating and using an instance of\n:class:`EffectBase` with your own custom :attr:`EffectBase.glsl`\nproperty.\n\nThe glsl property is a string representing part of a glsl fragment\nshader. You can include as many functions as you like (the string\nis simply spliced into the whole shader), but it\nmust implement a function :code:`effect` as below::\n\n    vec4 effect(vec4 color, sampler2D texture, vec2 tex_coords, vec2 coords)\n    {\n        // ... your code here\n        return something;  // must be a vec4 representing the new color\n    }\n\nThe full shader will calculate the normal pixel color at each point,\nthen call your :code:`effect` function to transform it. The\nparameters are:\n\n- **color**: The normal color of the current pixel (i.e. texture\n  sampled at tex_coords).\n- **texture**: The texture containing the widget's normal background.\n- **tex_coords**: The normal texture_coords used to access texture.\n- **coords**: The pixel indices of the current pixel.\n\nThe shader code also has access to two useful uniform variables,\n:code:`time` containing the time (in seconds) since the program start,\nand :code:`resolution` containing the shape (x pixels, y pixels) of\nthe widget.\n\nFor instance, the following simple string (taken from the `InvertEffect`)\nwould invert the input color but set alpha to 1.0::\n\n    vec4 effect(vec4 color, sampler2D texture, vec2 tex_coords, vec2 coords)\n    {\n        return vec4(1.0 - color.xyz, 1.0);\n    }\n\nYou can also set the glsl by automatically loading the string from a\nfile, simply set the :attr:`EffectBase.source` property of an effect.\n\n'''\n\nfrom kivy.clock import Clock\nfrom kivy.uix.relativelayout import RelativeLayout\nfrom kivy.properties import (StringProperty, ObjectProperty, ListProperty,\n                             NumericProperty, DictProperty)\nfrom kivy.graphics import (RenderContext, Fbo, Color, Rectangle,\n                           Translate, PushMatrix, PopMatrix, ClearColor,\n                           ClearBuffers)\nfrom kivy.event import EventDispatcher\nfrom kivy.base import EventLoop\nfrom kivy.resources import resource_find\n\n__all__ = ('EffectWidget', 'EffectBase', 'AdvancedEffectBase',\n           'MonochromeEffect', 'InvertEffect', 'ChannelMixEffect',\n           'ScanlinesEffect', 'PixelateEffect',\n           'HorizontalBlurEffect', 'VerticalBlurEffect',\n           'FXAAEffect')\n\nshader_header = '''\n#ifdef GL_ES\nprecision highp float;\n#endif\n\n/* Outputs from the vertex shader */\nvarying vec4 frag_color;\nvarying vec2 tex_coord0;\n\n/* uniform texture samplers */\nuniform sampler2D texture0;\n'''\n\nshader_uniforms = '''\nuniform vec2 resolution;\nuniform float time;\n'''\n\nshader_footer_trivial = '''\nvoid main (void){\n     gl_FragColor = frag_color * texture2D(texture0, tex_coord0);\n}\n'''\n\nshader_footer_effect = '''\nvoid main (void){\n    vec4 normal_color = frag_color * texture2D(texture0, tex_coord0);\n    vec4 effect_color = effect(normal_color, texture0, tex_coord0,\n                               gl_FragCoord.xy);\n    gl_FragColor = effect_color;\n}\n'''\n\n\neffect_trivial = '''\nvec4 effect(vec4 color, sampler2D texture, vec2 tex_coords, vec2 coords)\n{\n    return color;\n}\n'''\n\neffect_monochrome = '''\nvec4 effect(vec4 color, sampler2D texture, vec2 tex_coords, vec2 coords)\n{\n    float mag = 1.0/3.0 * (color.x + color.y + color.z);\n    return vec4(mag, mag, mag, color.w);\n}\n'''\n\neffect_invert = '''\nvec4 effect(vec4 color, sampler2D texture, vec2 tex_coords, vec2 coords)\n{\n    return vec4(1.0 - color.xyz, color.w);\n}\n'''\n\neffect_mix = '''\nvec4 effect(vec4 color, sampler2D texture, vec2 tex_coords, vec2 coords)\n{{\n    return vec4(color.{}, color.{}, color.{}, color.w);\n}}\n'''\n\neffect_blur_h = '''\nvec4 effect(vec4 color, sampler2D texture, vec2 tex_coords, vec2 coords)\n{{\n    float dt = ({} / 4.0) * 1.0 / resolution.x;\n    vec4 sum = vec4(0.0);\n    sum += texture2D(texture, vec2(tex_coords.x - 4.0*dt, tex_coords.y))\n                     * 0.05;\n    sum += texture2D(texture, vec2(tex_coords.x - 3.0*dt, tex_coords.y))\n                     * 0.09;\n    sum += texture2D(texture, vec2(tex_coords.x - 2.0*dt, tex_coords.y))\n                     * 0.12;\n    sum += texture2D(texture, vec2(tex_coords.x - dt, tex_coords.y))\n                     * 0.15;\n    sum += texture2D(texture, vec2(tex_coords.x, tex_coords.y))\n                     * 0.16;\n    sum += texture2D(texture, vec2(tex_coords.x + dt, tex_coords.y))\n                     * 0.15;\n    sum += texture2D(texture, vec2(tex_coords.x + 2.0*dt, tex_coords.y))\n                     * 0.12;\n    sum += texture2D(texture, vec2(tex_coords.x + 3.0*dt, tex_coords.y))\n                     * 0.09;\n    sum += texture2D(texture, vec2(tex_coords.x + 4.0*dt, tex_coords.y))\n                     * 0.05;\n    return vec4(sum.xyz, color.w);\n}}\n'''\n\neffect_blur_v = '''\nvec4 effect(vec4 color, sampler2D texture, vec2 tex_coords, vec2 coords)\n{{\n    float dt = ({} / 4.0)\n                     * 1.0 / resolution.x;\n    vec4 sum = vec4(0.0);\n    sum += texture2D(texture, vec2(tex_coords.x, tex_coords.y - 4.0*dt))\n                     * 0.05;\n    sum += texture2D(texture, vec2(tex_coords.x, tex_coords.y - 3.0*dt))\n                     * 0.09;\n    sum += texture2D(texture, vec2(tex_coords.x, tex_coords.y - 2.0*dt))\n                     * 0.12;\n    sum += texture2D(texture, vec2(tex_coords.x, tex_coords.y - dt))\n                     * 0.15;\n    sum += texture2D(texture, vec2(tex_coords.x, tex_coords.y))\n                     * 0.16;\n    sum += texture2D(texture, vec2(tex_coords.x, tex_coords.y + dt))\n                     * 0.15;\n    sum += texture2D(texture, vec2(tex_coords.x, tex_coords.y + 2.0*dt))\n                     * 0.12;\n    sum += texture2D(texture, vec2(tex_coords.x, tex_coords.y + 3.0*dt))\n                     * 0.09;\n    sum += texture2D(texture, vec2(tex_coords.x, tex_coords.y + 4.0*dt))\n                     * 0.05;\n    return vec4(sum.xyz, color.w);\n}}\n'''\n\neffect_postprocessing = '''\nvec4 effect(vec4 color, sampler2D texture, vec2 tex_coords, vec2 coords)\n{\n    vec2 q = tex_coords * vec2(1, -1);\n    vec2 uv = 0.5 + (q-0.5);//*(0.9);// + 0.1*sin(0.2*time));\n\n    vec3 oricol = texture2D(texture,vec2(q.x,1.0-q.y)).xyz;\n    vec3 col;\n\n    col.r = texture2D(texture,vec2(uv.x+0.003,-uv.y)).x;\n    col.g = texture2D(texture,vec2(uv.x+0.000,-uv.y)).y;\n    col.b = texture2D(texture,vec2(uv.x-0.003,-uv.y)).z;\n\n    col = clamp(col*0.5+0.5*col*col*1.2,0.0,1.0);\n\n    //col *= 0.5 + 0.5*16.0*uv.x*uv.y*(1.0-uv.x)*(1.0-uv.y);\n\n    col *= vec3(0.8,1.0,0.7);\n\n    col *= 0.9+0.1*sin(10.0*time+uv.y*1000.0);\n\n    col *= 0.97+0.03*sin(110.0*time);\n\n    float comp = smoothstep( 0.2, 0.7, sin(time) );\n    //col = mix( col, oricol, clamp(-2.0+2.0*q.x+3.0*comp,0.0,1.0) );\n\n    return vec4(col, color.w);\n}\n'''\n\neffect_pixelate = '''\nvec4 effect(vec4 vcolor, sampler2D texture, vec2 texcoord, vec2 pixel_coords)\n{{\n    vec2 pixelSize = {} / resolution;\n\n    vec2 xy = floor(texcoord/pixelSize)*pixelSize + pixelSize/2.0;\n\n    return texture2D(texture, xy);\n}}\n'''\n\neffect_fxaa = '''\nvec4 effect( vec4 color, sampler2D buf0, vec2 texCoords, vec2 coords)\n{\n\n    vec2 frameBufSize = resolution;\n\n    float FXAA_SPAN_MAX = 8.0;\n    float FXAA_REDUCE_MUL = 1.0/8.0;\n    float FXAA_REDUCE_MIN = 1.0/128.0;\n\n    vec3 rgbNW=texture2D(buf0,texCoords+(vec2(-1.0,-1.0)/frameBufSize)).xyz;\n    vec3 rgbNE=texture2D(buf0,texCoords+(vec2(1.0,-1.0)/frameBufSize)).xyz;\n    vec3 rgbSW=texture2D(buf0,texCoords+(vec2(-1.0,1.0)/frameBufSize)).xyz;\n    vec3 rgbSE=texture2D(buf0,texCoords+(vec2(1.0,1.0)/frameBufSize)).xyz;\n    vec3 rgbM=texture2D(buf0,texCoords).xyz;\n\n    vec3 luma=vec3(0.299, 0.587, 0.114);\n    float lumaNW = dot(rgbNW, luma);\n    float lumaNE = dot(rgbNE, luma);\n    float lumaSW = dot(rgbSW, luma);\n    float lumaSE = dot(rgbSE, luma);\n    float lumaM  = dot(rgbM, luma);\n\n    float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));\n    float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));\n\n    vec2 dir;\n    dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));\n    dir.y =  ((lumaNW + lumaSW) - (lumaNE + lumaSE));\n\n    float dirReduce = max(\n        (lumaNW + lumaNE + lumaSW + lumaSE) * (0.25 * FXAA_REDUCE_MUL),\n        FXAA_REDUCE_MIN);\n\n    float rcpDirMin = 1.0/(min(abs(dir.x), abs(dir.y)) + dirReduce);\n\n    dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX),\n          max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),\n          dir * rcpDirMin)) / frameBufSize;\n\n    vec3 rgbA = (1.0/2.0) * (\n        texture2D(buf0, texCoords.xy + dir * (1.0/3.0 - 0.5)).xyz +\n        texture2D(buf0, texCoords.xy + dir * (2.0/3.0 - 0.5)).xyz);\n    vec3 rgbB = rgbA * (1.0/2.0) + (1.0/4.0) * (\n        texture2D(buf0, texCoords.xy + dir * (0.0/3.0 - 0.5)).xyz +\n        texture2D(buf0, texCoords.xy + dir * (3.0/3.0 - 0.5)).xyz);\n    float lumaB = dot(rgbB, luma);\n\n    vec4 return_color;\n    if((lumaB < lumaMin) || (lumaB > lumaMax)){\n        return_color = vec4(rgbA, color.w);\n    }else{\n        return_color = vec4(rgbB, color.w);\n    }\n\n    return return_color;\n}\n'''\n\n\nclass EffectBase(EventDispatcher):\n    '''The base class for GLSL effects. It simply returns its input.\n\n    See module documentation for more details.\n\n    '''\n\n    glsl = StringProperty(effect_trivial)\n    '''The glsl string defining your effect function, see module\n    documentation for more details.\n\n    :attr:`glsl` is a :class:`~kivy.properties.StringProperty` and\n    defaults to\n    a trivial effect that returns its input.\n    '''\n\n    source = StringProperty('')\n    '''The (optional) filename from which to load the :attr:`glsl`\n    string.\n\n    :attr:`source` is a :class:`~kivy.properties.StringProperty` and\n    defaults to ''.\n    '''\n\n    fbo = ObjectProperty(None, allownone=True)\n    '''The fbo currently using this effect. The :class:`EffectBase`\n    automatically handles this.\n\n    :attr:`fbo` is a :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    def __init__(self, *args, **kwargs):\n        super(EffectBase, self).__init__(*args, **kwargs)\n        self.bind(fbo=self.set_fbo_shader)\n        self.bind(glsl=self.set_fbo_shader)\n        self.bind(source=self._load_from_source)\n\n    def set_fbo_shader(self, *args):\n        '''Sets the :class:`~kivy.graphics.Fbo`'s shader by splicing\n        the :attr:`glsl` string into a full fragment shader.\n\n        The full shader is made up of :code:`shader_header +\n        shader_uniforms + self.glsl + shader_footer_effect`.\n        '''\n        if self.fbo is None:\n            return\n        self.fbo.set_fs(shader_header + shader_uniforms + self.glsl +\n                        shader_footer_effect)\n\n    def _load_from_source(self, *args):\n        '''(internal) Loads the glsl string from a source file.'''\n        source = self.source\n        if not source:\n            return\n        filename = resource_find(source)\n        if filename is None:\n            return Logger.error('Error reading file {filename}'.\n                                format(filename=source))\n        with open(filename) as fileh:\n            self.glsl = fileh.read()\n\n\nclass AdvancedEffectBase(EffectBase):\n    '''An :class:`EffectBase` with additional behavior to easily\n    set and update uniform variables in your shader.\n\n    This class is provided for convenience if implementing your own\n    effects, it is not used by any of those provided with Kivy.\n\n    In addition to your base glsl string that must be provided as\n    normal, the :class:`AdvancedEffectBase` has an extra property\n    :attr:`uniforms`, a dictionary of name-value pairs. Whenever\n    a value is changed, the new values for the uniform variable with\n    the given name are uploaded to the shader.\n\n    You must still manually declare your uniform variables at the top\n    of your glsl string.\n    '''\n\n    uniforms = DictProperty({})\n    '''A dictionary of uniform variable names and their values. These\n    are automatically uploaded to the :attr:`fbo` shader if appropriate.\n\n    uniforms is a :class:`~kivy.properties.DictProperty` and\n    defaults to {}.\n    '''\n\n    def __init__(self, *args, **kwargs):\n        super(AdvancedEffectBase, self).__init__(*args, **kwargs)\n        self.bind(uniforms=self._update_uniforms)\n\n    def _update_uniforms(self, *args):\n        if self.fbo is None:\n            return\n        for key, value in self.uniforms.items():\n            self.fbo[key] = value\n\n    def set_fbo_shader(self, *args):\n        super(AdvancedEffectBase, self).set_fbo_shader(*args)\n        self._update_uniforms()\n\n\nclass MonochromeEffect(EffectBase):\n    '''Returns its input colors in monochrome.'''\n    def __init__(self, *args, **kwargs):\n        super(MonochromeEffect, self).__init__(*args, **kwargs)\n        self.glsl = effect_monochrome\n\n\nclass InvertEffect(EffectBase):\n    '''Inverts the colors in the input.'''\n    def __init__(self, *args, **kwargs):\n        super(InvertEffect, self).__init__(*args, **kwargs)\n        self.glsl = effect_invert\n\n\nclass ScanlinesEffect(EffectBase):\n    '''Adds scanlines to the input.'''\n    def __init__(self, *args, **kwargs):\n        super(ScanlinesEffect, self).__init__(*args, **kwargs)\n        self.glsl = effect_postprocessing\n\n\nclass ChannelMixEffect(EffectBase):\n    '''Mixes the color channels of the input according to the order\n    property. Channels may be arbitrarily rearranged or repeated.'''\n\n    order = ListProperty([1, 2, 0])\n    '''The new sorted order of the rgb channels.\n\n    order is a :class:`~kivy.properties.ListProperty` and defaults to\n    [1, 2, 0], corresponding to (g, b, r).\n    '''\n\n    def __init__(self, *args, **kwargs):\n        super(ChannelMixEffect, self).__init__(*args, **kwargs)\n        self.do_glsl()\n\n    def on_order(self, *args):\n        self.do_glsl()\n\n    def do_glsl(self):\n        letters = [{0: 'x', 1: 'y', 2: 'z'}[i] for i in self.order]\n        self.glsl = effect_mix.format(*letters)\n\n\nclass PixelateEffect(EffectBase):\n    '''Pixelates the input according to its\n    :attr:`~PixelateEffect.pixel_size`'''\n\n    pixel_size = NumericProperty(10)\n    '''\n    Sets the size of a new 'pixel' in the effect, in terms of number of\n    'real' pixels.\n\n    pixel_size is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 10.\n    '''\n\n    def __init__(self, *args, **kwargs):\n        super(PixelateEffect, self).__init__(*args, **kwargs)\n        self.do_glsl()\n\n    def on_pixel_size(self, *args):\n        self.do_glsl()\n\n    def do_glsl(self):\n        self.glsl = effect_pixelate.format(float(self.pixel_size))\n\n\nclass HorizontalBlurEffect(EffectBase):\n    '''Blurs the input horizontally, with the width given by\n    :attr:`~HorizontalBlurEffect.size`.'''\n\n    size = NumericProperty(4.0)\n    '''The blur width in pixels.\n\n    size is a :class:`~kivy.properties.NumericProperty` and defaults to\n    4.0.\n    '''\n\n    def __init__(self, *args, **kwargs):\n        super(HorizontalBlurEffect, self).__init__(*args, **kwargs)\n        self.do_glsl()\n\n    def on_size(self, *args):\n        self.do_glsl()\n\n    def do_glsl(self):\n        self.glsl = effect_blur_h.format(float(self.size))\n\n\nclass VerticalBlurEffect(EffectBase):\n    '''Blurs the input vertically, with the width given by\n    :attr:`~VerticalBlurEffect.size`.'''\n\n    size = NumericProperty(4.0)\n    '''The blur width in pixels.\n\n    size is a :class:`~kivy.properties.NumericProperty` and defaults to\n    4.0.\n    '''\n\n    def __init__(self, *args, **kwargs):\n        super(VerticalBlurEffect, self).__init__(*args, **kwargs)\n        self.do_glsl()\n\n    def on_size(self, *args):\n        self.do_glsl()\n\n    def do_glsl(self):\n        self.glsl = effect_blur_v.format(float(self.size))\n\n\nclass FXAAEffect(EffectBase):\n    '''Applies very simple antialiasing via fxaa.'''\n    def __init__(self, *args, **kwargs):\n        super(FXAAEffect, self).__init__(*args, **kwargs)\n        self.glsl = effect_fxaa\n\n\nclass EffectFbo(Fbo):\n    '''An :class:`~kivy.graphics.Fbo` with extra facility to\n    attempt setting a new shader, see :meth:`set_fs`.\n    '''\n    def __init__(self, *args, **kwargs):\n        super(EffectFbo, self).__init__(*args, **kwargs)\n        self.texture_rectangle = None\n\n    def set_fs(self, value):\n        '''Attempt to set the fragment shader to the given value.\n        If setting the shader fails, resets the old one and raises an\n        exception.\n        '''\n        shader = self.shader\n        old_value = shader.fs\n        shader.fs = value\n        if not shader.success:\n            shader.fs = old_value\n            raise Exception('Setting new shader failed.')\n\n\nclass EffectWidget(RelativeLayout):\n    '''\n    Widget with the ability to apply a series of graphical effects to\n    its children. See module documentation for full information on\n    setting effects and creating your own.\n    '''\n\n    background_color = ListProperty((0, 0, 0, 1))\n    '''This defines the background color to be used for the fbo in the\n    EffectWidget.\n\n    :attr:`background_color` is a :class:`ListProperty` defaults to\n    (0, 0, 0, 1)\n    '''\n\n    texture = ObjectProperty(None)\n    '''The output texture of our final :class:`~kivy.graphics.Fbo` after\n    all effects have been applied.\n\n    texture is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    effects = ListProperty([])\n    '''List of all the effects to be applied. These should all be\n    instances of :class:`EffectBase`.\n\n    effects is a :class:`ListProperty` and defaults to [].\n    '''\n\n    fbo_list = ListProperty([])\n    '''(internal) list of all the fbos that are being used to apply\n    the effects.\n\n    fbo_list is a :class:`ListProperty` and defaults to [].\n    '''\n\n    _bound_effects = ListProperty([])\n    '''(internal) list of effect classes that have been given an fbo to\n    manage. This is necessary so that the fbo can be removed it the\n    effect is no longer in use.\n\n    _bound_effects is a :class:`ListProperty` and defaults to [].\n    '''\n\n    def __init__(self, **kwargs):\n        # Make sure opengl context exists\n        EventLoop.ensure_window()\n\n        self.canvas = RenderContext(use_parent_projection=True,\n                                    use_parent_modelview=True)\n\n        with self.canvas:\n            self.fbo = Fbo(size=self.size)\n\n        with self.fbo.before:\n            PushMatrix()\n        with self.fbo:\n            ClearColor(0, 0, 0, 0)\n            ClearBuffers()\n            self._background_color = Color(*self.background_color)\n            self.fbo_rectangle = Rectangle(size=self.size)\n        with self.fbo.after:\n            PopMatrix()\n\n        super(EffectWidget, self).__init__(**kwargs)\n\n        Clock.schedule_interval(self._update_glsl, 0)\n\n        self.bind(size=self.refresh_fbo_setup,\n                  effects=self.refresh_fbo_setup,\n                  background_color=self._refresh_background_color)\n\n        self.refresh_fbo_setup()\n        self._refresh_background_color()  # In case thi was changed in kwargs\n\n    def _refresh_background_color(self, *args):\n        self._background_color.rgba = self.background_color\n\n    def _update_glsl(self, *largs):\n        '''(internal) Passes new time and resolution uniform\n        variables to the shader.\n        '''\n        time = Clock.get_boottime()\n        resolution = [float(size) for size in self.size]\n        self.canvas['time'] = time\n        self.canvas['resolution'] = resolution\n        for fbo in self.fbo_list:\n            fbo['time'] = time\n            fbo['resolution'] = resolution\n\n    def refresh_fbo_setup(self, *args):\n        '''(internal) Creates and assigns one :class:`~kivy.graphics.Fbo`\n        per effect, and makes sure all sizes etc. are correct and\n        consistent.\n        '''\n        # Add/remove fbos until there is one per effect\n        while len(self.fbo_list) < len(self.effects):\n            with self.canvas:\n                new_fbo = EffectFbo(size=self.size)\n            with new_fbo:\n                ClearColor(0, 0, 0, 0)\n                ClearBuffers()\n                Color(1, 1, 1, 1)\n                new_fbo.texture_rectangle = Rectangle(size=self.size)\n\n                new_fbo.texture_rectangle.size = self.size\n            self.fbo_list.append(new_fbo)\n        while len(self.fbo_list) > len(self.effects):\n            old_fbo = self.fbo_list.pop()\n            self.canvas.remove(old_fbo)\n\n        # Remove fbos from unused effects\n        for effect in self._bound_effects:\n            if effect not in self.effects:\n                effect.fbo = None\n        self._bound_effects = self.effects\n\n        # Do resizing etc.\n        self.fbo.size = self.size\n        self.fbo_rectangle.size = self.size\n        for i in range(len(self.fbo_list)):\n            self.fbo_list[i].size = self.size\n            self.fbo_list[i].texture_rectangle.size = self.size\n\n        # If there are no effects, just draw our main fbo\n        if len(self.fbo_list) == 0:\n            self.texture = self.fbo.texture\n            return\n\n        for i in range(1, len(self.fbo_list)):\n            fbo = self.fbo_list[i]\n            fbo.texture_rectangle.texture = self.fbo_list[i - 1].texture\n\n        # Build effect shaders\n        for effect, fbo in zip(self.effects, self.fbo_list):\n            effect.fbo = fbo\n\n        self.fbo_list[0].texture_rectangle.texture = self.fbo.texture\n        self.texture = self.fbo_list[-1].texture\n\n    def add_widget(self, widget):\n        # Add the widget to our Fbo instead of the normal canvas\n        c = self.canvas\n        self.canvas = self.fbo\n        super(EffectWidget, self).add_widget(widget)\n        self.canvas = c\n\n    def remove_widget(self, widget):\n        # Remove the widget from our Fbo instead of the normal canvas\n        c = self.canvas\n        self.canvas = self.fbo\n        super(EffectWidget, self).remove_widget(widget)\n        self.canvas = c\n\n    def clear_widgets(self, children=None):\n        # Clear widgets from our Fbo instead of the normal canvas\n        c = self.canvas\n        self.canvas = self.fbo\n        super(EffectWidget, self).clear_widgets(children)\n        self.canvas = c\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/filechooser.py",
    "content": "'''\nFileChooser\n===========\n\n.. versionadded:: 1.0.5\n\n\n.. versionchanged:: 1.2.0\n    In the chooser template, the `controller` is not a direct reference anymore\n    but a weak-reference.\n    You must update all the notation `root.controller.xxx` to\n    `root.controller().xxx`.\n\nSimple example\n--------------\n\nmain.py\n\n.. include:: ../../examples/RST_Editor/main.py\n    :literal:\n\neditor.kv\n\n.. highlight:: kv\n\n.. include:: ../../examples/RST_Editor/editor.kv\n    :literal:\n\n'''\nfrom kivy.uix.screenmanager import ScreenManager, Screen\n\n__all__ = ('FileChooserListView', 'FileChooserIconView',\n           'FileChooserListLayout', 'FileChooserIconLayout',\n           'FileChooser', 'FileChooserController',\n           'FileChooserProgressBase', 'FileSystemAbstract',\n           'FileSystemLocal')\n\nfrom weakref import ref\nfrom time import time\nfrom kivy.compat import string_types\nfrom kivy.factory import Factory\nfrom kivy.clock import Clock\nfrom kivy.lang import Builder\nfrom kivy.logger import Logger\nfrom kivy.utils import platform as core_platform\nfrom kivy.uix.floatlayout import FloatLayout\nfrom kivy.properties import (\n    StringProperty, ListProperty, BooleanProperty, ObjectProperty,\n    NumericProperty, OptionProperty, AliasProperty)\nfrom os import listdir\nfrom os.path import (\n    basename, join, sep, normpath, expanduser, altsep,\n    splitdrive, realpath, getsize, isdir, abspath, pardir)\nfrom fnmatch import fnmatch\nimport collections\n\nplatform = core_platform\nfilesize_units = ('B', 'KB', 'MB', 'GB', 'TB')\n\n_have_win32file = False\nif platform == 'win':\n    # Import that module here as it's not available on non-windows machines.\n    # See http://bit.ly/i9klJE except that the attributes are defined in\n    # win32file not win32com (bug on page).\n    # Note: For some reason this doesn't work after a os.chdir(), no matter to\n    #       what directory you change from where. Windows weirdness.\n    try:\n        from win32file import FILE_ATTRIBUTE_HIDDEN, GetFileAttributesExW, error\n        _have_win32file = True\n    except ImportError:\n        Logger.error('filechooser: win32file module is missing')\n        Logger.error('filechooser: we cant check if a file is hidden or not')\n\n\ndef alphanumeric_folders_first(files, filesystem):\n    return (sorted(f for f in files if filesystem.is_dir(f)) +\n            sorted(f for f in files if not filesystem.is_dir(f)))\n\n\nclass FileSystemAbstract(object):\n    '''Class for implementing a File System view that can be used with the\n    :class:`FileChooser`.:attr:`~FileChooser.file_system`.\n\n    .. versionadded:: 1.8.0\n    '''\n\n    def listdir(self, fn):\n        '''Return the list of files in the directory `fn`\n        '''\n        pass\n\n    def getsize(self, fn):\n        '''Return the size in bytes of a file\n        '''\n        pass\n\n    def is_hidden(self, fn):\n        '''Return True if the file is hidden\n        '''\n        pass\n\n    def is_dir(self, fn):\n        '''Return True if the argument passed to this method is a directory\n        '''\n        pass\n\n\nclass FileSystemLocal(FileSystemAbstract):\n    '''Implementation of :class:`FileSystemAbstract` for local files\n\n    .. versionadded:: 1.8.0\n    '''\n\n    def listdir(self, fn):\n        return listdir(fn)\n\n    def getsize(self, fn):\n        return getsize(fn)\n\n    def is_hidden(self, fn):\n        if platform == 'win':\n            if not _have_win32file:\n                return False\n            try:\n                return GetFileAttributesExW(fn)[0] & FILE_ATTRIBUTE_HIDDEN\n            except error:\n                # This error can occured when a file is already accessed by\n                # someone else. So don't return to True, because we have lot\n                # of chances to not being able to do anything with it.\n                Logger.exception('unable to access to <%s>' % fn)\n                return True\n\n        return basename(fn).startswith('.')\n\n    def is_dir(self, fn):\n        return isdir(fn)\n\n\nclass FileChooserProgressBase(FloatLayout):\n    '''Base for implementing a progress view. This view is used when too many\n    entries need to be created and are delayed over multiple frames.\n\n    .. versionadded:: 1.2.0\n    '''\n\n    path = StringProperty('')\n    '''Current path of the FileChooser, read-only.\n    '''\n\n    index = NumericProperty(0)\n    '''Current index of :attr:`total` entries to be loaded.\n    '''\n\n    total = NumericProperty(1)\n    '''Total number of entries to load.\n    '''\n\n    def cancel(self, *largs):\n        '''Cancel any action from the FileChooserController.\n        '''\n        if self.parent:\n            self.parent.cancel()\n\n    def on_touch_down(self, touch):\n        if self.collide_point(*touch.pos):\n            super(FileChooserProgressBase, self).on_touch_down(touch)\n            return True\n\n    def on_touch_move(self, touch):\n        if self.collide_point(*touch.pos):\n            super(FileChooserProgressBase, self).on_touch_move(touch)\n            return True\n\n    def on_touch_up(self, touch):\n        if self.collide_point(*touch.pos):\n            super(FileChooserProgressBase, self).on_touch_up(touch)\n            return True\n\n\nclass FileChooserProgress(FileChooserProgressBase):\n    pass\n\n\nclass FileChooserLayout(FloatLayout):\n    '''Base class for file chooser layouts.\n\n    .. versionadded:: 1.9.0\n    '''\n\n    VIEWNAME = 'undefined'\n\n    __events__ = ('on_entry_added', 'on_entries_cleared',\n                  'on_subentry_to_entry', 'on_remove_subentry', 'on_submit')\n\n    controller = ObjectProperty()\n    '''\n    Reference to the controller handling this layout.\n\n    :class:`~kivy.properties.ObjectProperty`\n    '''\n\n    def on_entry_added(self, node, parent=None):\n        pass\n\n    def on_entries_cleared(self):\n        pass\n\n    def on_subentry_to_entry(self, subentry, entry):\n        pass\n\n    def on_remove_subentry(self, subentry, entry):\n        pass\n\n    def on_submit(self, selected, touch=None):\n        pass\n\n\nclass FileChooserListLayout(FileChooserLayout):\n    '''File chooser layout using a list view.\n\n    .. versionadded:: 1.9.0\n    '''\n    VIEWNAME = 'list'\n    _ENTRY_TEMPLATE = 'FileListEntry'\n\n    def __init__(self, **kwargs):\n        super(FileChooserListLayout, self).__init__(**kwargs)\n        self.bind(on_entries_cleared=self.scroll_to_top)\n\n    def scroll_to_top(self, *args):\n        self.ids.scrollview.scroll_y = 1.0\n\n\nclass FileChooserIconLayout(FileChooserLayout):\n    '''File chooser layout using an icon view.\n\n    .. versionadded:: 1.9.0\n    '''\n\n    VIEWNAME = 'icon'\n    _ENTRY_TEMPLATE = 'FileIconEntry'\n\n    def __init__(self, **kwargs):\n        super(FileChooserIconLayout, self).__init__(**kwargs)\n        self.bind(on_entries_cleared=self.scroll_to_top)\n\n    def scroll_to_top(self, *args):\n        self.ids.scrollview.scroll_y = 1.0\n\n\nclass FileChooserController(FloatLayout):\n    '''Base for implementing a FileChooser. Don't use this class directly, but\n    prefer using an implementation such as the :class:`FileChooser`,\n    :class:`FileChooserListView` or :class:`FileChooserIconView`.\n\n    .. versionchanged:: 1.9.0\n\n    :Events:\n        `on_entry_added`: entry, parent\n            Fired when a root-level entry is added to the file list.\n        `on_entries_cleared`\n            Fired when the the entries list is cleared, usually when the\n            root is refreshed.\n        `on_subentry_to_entry`: entry, parent\n            Fired when a sub-entry is added to an existing entry.\n            Fired when entries are removed from an entry, usually when\n            a node is closed.\n        `on_submit`: selection, touch\n            Fired when a file has been selected with a double-tap.\n    '''\n    _ENTRY_TEMPLATE = None\n\n    layout = ObjectProperty(baseclass=FileChooserLayout)\n    '''\n    Reference to the layout widget instance.\n\n    layout is an :class:`~kivy.properties.ObjectProperty`.\n\n    .. versionadded:: 1.9.0\n    '''\n\n    path = StringProperty(u'/')\n    '''\n    :class:`~kivy.properties.StringProperty`, defaults to the current working\n    directory as a unicode string. It specifies the path on the filesystem that\n    this controller should refer to.\n\n    .. warning::\n\n        If a unicode path is specified, all the files returned will be in\n        unicode allowing the display of unicode files and paths. If a bytes\n        path is specified, only files and paths with ascii names will be\n        displayed properly: non-ascii filenames will be displayed and listed\n        with questions marks (?) instead of their unicode characters.\n    '''\n\n    filters = ListProperty([])\n    ''':class:`~kivy.properties.ListProperty`, defaults to [], equal to '\\*'.\n    Specifies the filters to be applied to the files in the directory.\n\n    The filters are not reset when the path changes. You need to do that\n    yourself if desired.\n\n    There are two kinds of filters: patterns and callbacks.\n\n    #. Patterns\n\n        e.g. ['\\*.png'].\n        You can use the following patterns:\n\n            ========== =================================\n            Pattern     Meaning\n            ========== =================================\n            \\*         matches everything\n            ?          matches any single character\n            [seq]      matches any character in seq\n            [!seq]     matches any character not in seq\n            ========== =================================\n\n    #. Callbacks\n\n        You can specify a function that will be called for each file. The\n        callback will be passed the folder and file name as the first\n        and second parameters respectively. It should return True to\n        indicate a match and False otherwise.\n\n    .. versionchanged:: 1.4.0\n        If the filter is a callable (function or method), it will be called\n        with the path and the file name as arguments for each file in the\n        directory.\n        The callable should returns True to indicate a match and False\n        overwise.\n    '''\n\n    filter_dirs = BooleanProperty(False)\n    '''\n    :class:`~kivy.properties.BooleanProperty`, defaults to False.\n    Indicates whether filters should also apply to directories.\n    '''\n\n    sort_func = ObjectProperty(alphanumeric_folders_first)\n    '''\n    :class:`~kivy.properties.ObjectProperty`.\n    Provides a function to be called with a list of filenames, and the\n    filesystem implementation as the second argument.\n    Returns a list of filenames sorted for display in the view.\n\n    .. versionchanged:: 1.8.0\n\n        The signature needs now 2 arguments: first the list of files,\n        second the filesystem class to use.\n    '''\n\n    files = ListProperty([])\n    '''\n    Read-only :class:`~kivy.properties.ListProperty`.\n    The list of files in the directory specified by path after applying the\n    filters.\n    '''\n\n    show_hidden = BooleanProperty(False)\n    '''\n    :class:`~kivy.properties.BooleanProperty`, defaults to False.\n    Determines whether hidden files and folders should be shown.\n    '''\n\n    selection = ListProperty([])\n    '''\n    Read-only :class:`~kivy.properties.ListProperty`.\n    Contains the list of files that are currently selected.\n    '''\n\n    multiselect = BooleanProperty(False)\n    '''\n    :class:`~kivy.properties.BooleanProperty`, defaults to False.\n    Determines whether the user is able to select multiple files or not.\n    '''\n\n    dirselect = BooleanProperty(False)\n    '''\n    :class:`~kivy.properties.BooleanProperty`, defaults to False.\n    Determines whether directories are valid selections or not.\n\n    .. versionadded:: 1.1.0\n    '''\n\n    rootpath = StringProperty(None, allownone=True)\n    '''\n    Root path to use instead of the system root path. If set, it will not show\n    a \"..\" directory to go up to the root path. For example, if you set\n    rootpath to /users/foo, the user will be unable to go to /users or to any\n    other directory not starting with /users/foo.\n\n    .. versionadded:: 1.2.0\n\n    :class:`~kivy.properties.StringProperty`, defaults to None.\n\n    .. note::\n\n        Similar to :attr:`path`, if `rootpath` is specified, whether it's a\n        bytes or unicode string determines the type of the filenames and paths\n        read.\n    '''\n\n    progress_cls = ObjectProperty(FileChooserProgress)\n    '''Class to use for displaying a progress indicator for filechooser\n    loading.\n\n    .. versionadded:: 1.2.0\n\n    :class:`~kivy.properties.ObjectProperty`, defaults to\n    :class:`FileChooserProgress`.\n\n    .. versionchanged:: 1.8.0\n\n        If you set a string, the :class:`~kivy.factory.Factory` will be used to\n        resolve the class.\n\n    '''\n\n    file_encodings = ListProperty(['utf-8', 'latin1', 'cp1252'])\n    '''Possible encodings for decoding a filename to unicode. In the case that\n    the user has a weird filename, undecodable without knowing it's\n    initial encoding, we have no other choice than to guess it.\n\n    Please note that if you encounter an issue because of a missing encoding\n    here, we'll be glad to add it to this list.\n\n    .. versionadded:: 1.3.0\n\n    .. deprecated:: 1.8.0\n       This property is no longer used as the filechooser no longer decodes\n       the file names.\n\n    file_encodings is a :class:`~kivy.properties.ListProperty` and defaults to\n    ['utf-8', 'latin1', 'cp1252'],\n    '''\n\n    file_system = ObjectProperty(FileSystemLocal(),\n                                 baseclass=FileSystemAbstract)\n    '''Implementation to access the file system. Must be an instance of\n    FileSystemAbstract.\n\n    .. versionadded:: 1.8.0\n\n    :class:`~kivy.properties.ObjectProperty`, defaults to\n    :class:`FileSystemLocal()`\n    '''\n\n    __events__ = ('on_entry_added', 'on_entries_cleared',\n                  'on_subentry_to_entry', 'on_remove_subentry', 'on_submit')\n\n    def __init__(self, **kwargs):\n        self._progress = None\n        super(FileChooserController, self).__init__(**kwargs)\n\n        self._items = []\n        self.bind(selection=self._update_item_selection)\n\n        self._previous_path = [self.path]\n        self.bind(path=self._save_previous_path)\n        self.bind(path=self._trigger_update,\n                  filters=self._trigger_update,\n                  rootpath=self._trigger_update)\n        self._trigger_update()\n\n    def on_touch_down(self, touch):\n        # don't respond to touchs outside self\n        if not self.collide_point(*touch.pos):\n            return\n        if self.disabled:\n            return True\n        return super(FileChooserController, self).on_touch_down(touch)\n\n    def on_touch_up(self, touch):\n        # don't respond to touchs outside self\n        if not self.collide_point(*touch.pos):\n            return True\n        if self.disabled:\n            return True\n        return super(FileChooserController, self).on_touch_up(touch)\n\n    def _update_item_selection(self, *args):\n        for item in self._items:\n            item.selected = item.path in self.selection\n\n    def _save_previous_path(self, instance, value):\n        self._previous_path.append(value)\n        self._previous_path = self._previous_path[-2:]\n\n    def _trigger_update(self, *args):\n        Clock.unschedule(self._update_files)\n        Clock.schedule_once(self._update_files)\n\n    def on_entry_added(self, node, parent=None):\n        if self.layout:\n            self.layout.dispatch('on_entry_added', node, parent)\n\n    def on_entries_cleared(self):\n        if self.layout:\n            self.layout.dispatch('on_entries_cleared')\n\n    def on_subentry_to_entry(self, subentry, entry):\n        if self.layout:\n            self.layout.dispatch('on_subentry_to_entry', subentry, entry)\n\n    def on_remove_subentry(self, subentry, entry):\n        if self.layout:\n            self.layout.dispatch('on_remove_subentry', subentry, entry)\n\n    def on_submit(self, selected, touch=None):\n        if self.layout:\n            self.layout.dispatch('on_submit', selected, touch)\n\n    def entry_touched(self, entry, touch):\n        '''(internal) This method must be called by the template when an entry\n        is touched by the user.\n        '''\n        if (\n            'button' in touch.profile and touch.button in (\n                'scrollup', 'scrolldown', 'scrollleft', 'scrollright')):\n            return False\n\n        _dir = self.file_system.is_dir(entry.path)\n        dirselect = self.dirselect\n\n        if _dir and dirselect and touch.is_double_tap:\n            self.open_entry(entry)\n            return\n\n        if self.multiselect:\n            if entry.path in self.selection:\n                self.selection.remove(entry.path)\n            else:\n                if _dir and not self.dirselect:\n                    self.open_entry(entry)\n                    return\n                self.selection.append(entry.path)\n        else:\n            if _dir and not self.dirselect:\n                self.open_entry\n                return\n            self.selection = [entry.path, ]\n\n    def entry_released(self, entry, touch):\n        '''(internal) This method must be called by the template when an entry\n        is touched by the user.\n\n        .. versionadded:: 1.1.0\n        '''\n        if (\n            'button' in touch.profile and touch.button in (\n                'scrollup', 'scrolldown', 'scrollleft', 'scrollright')):\n            return False\n        if not self.multiselect:\n            if self.file_system.is_dir(entry.path) and not self.dirselect:\n                self.open_entry(entry)\n            elif touch.is_double_tap:\n                if self.dirselect and self.file_system.is_dir(entry.path):\n                    self.open_entry(entry)\n                else:\n                    self.dispatch('on_submit', self.selection, touch)\n\n    def open_entry(self, entry):\n        try:\n            # Just check if we can list the directory. This is also what\n            # _add_file does, so if it fails here, it would also fail later\n            # on. Do the check here to prevent setting path to an invalid\n            # directory that we cannot list.\n            self.file_system.listdir(entry.path)\n        except OSError:\n            entry.locked = True\n        else:\n            # If entry.path is to jump to previous directory, update path with\n            # parent directory\n            self.path = abspath(join(self.path, entry.path))\n            self.selection = []\n\n    def _apply_filters(self, files):\n        if not self.filters:\n            return files\n        filtered = []\n        for filt in self.filters:\n            if isinstance(filt, collections.Callable):\n                filtered.extend([fn for fn in files if filt(self.path, fn)])\n            else:\n                filtered.extend([fn for fn in files if fnmatch(fn, filt)])\n        if not self.filter_dirs:\n            dirs = [fn for fn in files if self.file_system.is_dir(fn)]\n            filtered.extend(dirs)\n        return list(set(filtered))\n\n    def get_nice_size(self, fn):\n        '''Pass the filepath. Returns the size in the best human readable\n        format or '' if it is a directory (Don't recursively calculate size.).\n        '''\n        if self.file_system.is_dir(fn):\n            return ''\n        try:\n            size = self.file_system.getsize(fn)\n        except OSError:\n            return '--'\n\n        for unit in filesize_units:\n            if size < 1024.0:\n                return '%1.0f %s' % (size, unit)\n            size /= 1024.0\n\n    def _update_files(self, *args, **kwargs):\n        # trigger to start gathering the files in the new directory\n        # we'll start a timer that will do the job, 10 times per frames\n        # (default)\n        self._gitems = []\n        self._gitems_parent = kwargs.get('parent', None)\n        self._gitems_gen = self._generate_file_entries(\n            path=kwargs.get('path', self.path),\n            parent=self._gitems_parent)\n\n        # cancel any previous clock if exist\n        Clock.unschedule(self._create_files_entries)\n\n        # show the progression screen\n        self._hide_progress()\n        if self._create_files_entries():\n            # not enough for creating all the entries, all a clock to continue\n            # start a timer for the next 100 ms\n            Clock.schedule_interval(self._create_files_entries, .1)\n\n    def _get_file_paths(self, items):\n        return [file.path for file in items]\n\n    def _create_files_entries(self, *args):\n        # create maximum entries during 50ms max, or 10 minimum (slow system)\n        # (on a \"fast system\" (core i7 2700K), we can create up to 40 entries\n        # in 50 ms. So 10 is fine for low system.\n        start = time()\n        finished = False\n        index = total = count = 1\n        while time() - start < 0.05 or count < 10:\n            try:\n                index, total, item = next(self._gitems_gen)\n                self._gitems.append(item)\n                count += 1\n            except StopIteration:\n                finished = True\n                break\n            except TypeError:  # in case _gitems_gen is None\n                finished = True\n                break\n\n        # if this wasn't enough for creating all the entries, show a progress\n        # bar, and report the activity to the user.\n        if not finished:\n            self._show_progress()\n            self._progress.total = total\n            self._progress.index = index\n            return True\n\n        # we created all the files, now push them on the view\n        self._items = items = self._gitems\n        parent = self._gitems_parent\n        if parent is None:\n            self.dispatch('on_entries_cleared')\n            for entry in items:\n                self.dispatch('on_entry_added', entry, parent)\n        else:\n            parent.entries[:] = items\n            for entry in items:\n                self.dispatch('on_subentry_to_entry', entry, parent)\n        self.files[:] = self._get_file_paths(items)\n\n        # stop the progression / creation\n        self._hide_progress()\n        self._gitems = None\n        self._gitems_gen = None\n        Clock.unschedule(self._create_files_entries)\n        return False\n\n    def cancel(self, *largs):\n        '''Cancel any background action started by filechooser, such as loading\n        a new directory.\n\n        .. versionadded:: 1.2.0\n        '''\n        Clock.unschedule(self._create_files_entries)\n        self._hide_progress()\n        if len(self._previous_path) > 1:\n            # if we cancel any action, the path will be set same as the\n            # previous one, so we can safely cancel the update of the previous\n            # path.\n            self.path = self._previous_path[-2]\n            Clock.unschedule(self._update_files)\n\n    def _show_progress(self):\n        if self._progress:\n            return\n        cls = self.progress_cls\n        if isinstance(cls, string_types):\n            cls = Factory.get(cls)\n        self._progress = cls(path=self.path)\n        self._progress.value = 0\n        self.add_widget(self._progress)\n\n    def _hide_progress(self):\n        if self._progress:\n            self.remove_widget(self._progress)\n            self._progress = None\n\n    def _generate_file_entries(self, *args, **kwargs):\n        # Generator that will create all the files entries.\n        # the generator is used via _update_files() and _create_files_entries()\n        # don't use it directly.\n        is_root = False\n        path = kwargs.get('path', self.path)\n        have_parent = kwargs.get('parent', None) is not None\n\n        # Add the components that are always needed\n        if self.rootpath:\n            rootpath = realpath(self.rootpath)\n            path = realpath(path)\n            if not path.startswith(rootpath):\n                self.path = rootpath\n                return\n            elif path == rootpath:\n                is_root = True\n        else:\n            if platform == 'win':\n                is_root = splitdrive(path)[1] in (sep, altsep)\n            elif platform in ('macosx', 'linux', 'android', 'ios'):\n                is_root = normpath(expanduser(path)) == sep\n            else:\n                # Unknown fs, just always add the .. entry but also log\n                Logger.warning('Filechooser: Unsupported OS: %r' % platform)\n        # generate an entries to go back to previous\n        if not is_root and not have_parent:\n            back = '..' + sep\n            pardir = self._create_entry_widget(dict(\n                name=back, size='', path=back, controller=ref(self),\n                isdir=True, parent=None, sep=sep, get_nice_size=lambda: ''))\n            yield 0, 1, pardir\n\n        # generate all the entries for files\n        try:\n            for index, total, item in self._add_files(path):\n                yield index, total, item\n        except OSError:\n            Logger.exception('Unable to open directory <%s>' % self.path)\n            self.files[:] = []\n\n    def _create_entry_widget(self, ctx):\n        template = self.layout._ENTRY_TEMPLATE\\\n            if self.layout else self._ENTRY_TEMPLATE\n        return Builder.template(template, **ctx)\n\n    def _add_files(self, path, parent=None):\n        path = expanduser(path)\n\n        files = []\n        fappend = files.append\n        for f in self.file_system.listdir(path):\n            try:\n                # In the following, use fully qualified filenames\n                fappend(normpath(join(path, f)))\n            except UnicodeDecodeError:\n                Logger.exception('unable to decode <{}>'.format(f))\n            except UnicodeEncodeError:\n                Logger.exception('unable to encode <{}>'.format(f))\n        # Apply filename filters\n        files = self._apply_filters(files)\n        # Sort the list of files\n        files = self.sort_func(files, self.file_system)\n        is_hidden = self.file_system.is_hidden\n        if not self.show_hidden:\n            files = [x for x in files if not is_hidden(x)]\n        self.files[:] = files\n        total = len(files)\n        wself = ref(self)\n        for index, fn in enumerate(files):\n\n            def get_nice_size():\n                # Use a closure for lazy-loading here\n                return self.get_nice_size(fn)\n\n            ctx = {'name': basename(fn),\n                   'get_nice_size': get_nice_size,\n                   'path': fn,\n                   'controller': wself,\n                   'isdir': self.file_system.is_dir(fn),\n                   'parent': parent,\n                   'sep': sep}\n            entry = self._create_entry_widget(ctx)\n            yield index, total, entry\n\n    def entry_subselect(self, entry):\n        if not self.file_system.is_dir(entry.path):\n            return\n        self._update_files(path=entry.path, parent=entry)\n\n    def close_subselection(self, entry):\n        for subentry in entry.entries:\n            self.dispatch('on_remove_subentry', subentry, entry)\n\n\nclass FileChooserListView(FileChooserController):\n    '''Implementation of :class:`FileChooserController` using a list view.\n\n    .. versionadded:: 1.9.0\n    '''\n    _ENTRY_TEMPLATE = 'FileListEntry'\n\n\nclass FileChooserIconView(FileChooserController):\n    '''Implementation of :class:`FileChooserController` using an icon view.\n\n    .. versionadded:: 1.9.0\n    '''\n    _ENTRY_TEMPLATE = 'FileIconEntry'\n\n\nclass FileChooser(FileChooserController):\n    '''Implementation of :class:`FileChooserController` which supports\n    switching between multiple, synced layout views.\n\n    .. versionadded:: 1.9.0\n    '''\n\n    manager = ObjectProperty()\n    '''\n    Reference to the :class:`~kivy.uix.screenmanager.ScreenManager` instance.\n\n    :class:`~kivy.properties.ObjectProperty`\n    '''\n\n    _view_list = ListProperty()\n\n    def get_view_list(self):\n        return self._view_list\n\n    view_list = AliasProperty(get_view_list, bind=('_view_list',))\n    '''\n    List of views added to this FileChooser.\n\n    :class:`~kivy.properties.AliasProperty` of type :class:`list`.\n    '''\n\n    _view_mode = StringProperty()\n\n    def get_view_mode(self):\n        return self._view_mode\n\n    def set_view_mode(self, mode):\n        if mode not in self._view_list:\n            raise ValueError('unknown view mode %r' % mode)\n        self._view_mode = mode\n\n    view_mode = AliasProperty(\n        get_view_mode, set_view_mode, bind=('_view_mode',))\n    '''\n    Current layout view mode.\n\n    :class:`~kivy.properties.AliasProperty` of type :class:`str`.\n    '''\n\n    @property\n    def _views(self):\n        return [screen.children[0] for screen in self.manager.screens]\n\n    def __init__(self, **kwargs):\n        super(FileChooser, self).__init__(**kwargs)\n\n        self.manager = ScreenManager()\n        super(FileChooser, self).add_widget(self.manager)\n\n        self.trigger_update_view = Clock.create_trigger(self.update_view)\n\n        self.bind(view_mode=self.trigger_update_view)\n\n    def add_widget(self, widget, **kwargs):\n        if widget is self._progress:\n            super(FileChooser, self).add_widget(widget, **kwargs)\n        elif hasattr(widget, 'VIEWNAME'):\n            name = widget.VIEWNAME + 'view'\n            screen = Screen(name=name)\n            widget.controller = self\n            screen.add_widget(widget)\n            self.manager.add_widget(screen)\n\n            self.trigger_update_view()\n        else:\n            raise ValueError(\n                'widget must be a FileChooserLayout,'\n                ' not %s' % type(widget).__name__)\n\n    def rebuild_views(self):\n        views = [view.VIEWNAME for view in self._views]\n        if views != self._view_list:\n            self._view_list = views\n            if self._view_mode not in self._view_list:\n                self._view_mode = self._view_list[0]\n            self._trigger_update()\n\n    def update_view(self, *args):\n        self.rebuild_views()\n\n        sm = self.manager\n        viewlist = self._view_list\n        view = self.view_mode\n        current = sm.current[:-4]\n\n        viewindex = viewlist.index(view) if view in viewlist else 0\n        currentindex = viewlist.index(current) if current in viewlist else 0\n\n        direction = 'left' if currentindex < viewindex else 'right'\n\n        sm.transition.direction = direction\n        sm.current = view + 'view'\n\n    def _create_entry_widget(self, ctx):\n        return [Builder.template(view._ENTRY_TEMPLATE, **ctx)\n                for view in self._views]\n\n    def _get_file_paths(self, items):\n        if self._views:\n            return [file[0].path for file in items]\n        return []\n\n    def _update_item_selection(self, *args):\n        for viewitem in self._items:\n            selected = viewitem[0].path in self.selection\n            for item in viewitem:\n                item.selected = selected\n\n    def on_entry_added(self, node, parent=None):\n        for index, view in enumerate(self._views):\n            view.dispatch(\n                'on_entry_added',\n                node[index], parent[index] if parent else None)\n\n    def on_entries_cleared(self):\n        for view in self._views:\n            view.dispatch('on_entries_cleared')\n\n    def on_subentry_to_entry(self, subentry, entry):\n        for index, view in enumerate(self._views):\n            view.dispatch('on_subentry_to_entry', subentry[index], entry)\n\n    def on_remove_subentry(self, subentry, entry):\n        for index, view in enumerate(self._views):\n            view.dispatch('on_remove_subentry', subentry[index], entry)\n\n    def on_submit(self, selected, touch=None):\n        view_mode = self.view_mode\n        for view in self._views:\n            if view_mode == view.VIEWNAME:\n                view.dispatch('on_submit', selected, touch)\n                return\n\n\nif __name__ == '__main__':\n    from kivy.app import App\n    from kivy.lang import Builder\n    from pprint import pprint\n    import textwrap\n    import sys\n\n    root = Builder.load_string(textwrap.dedent('''\\\n    BoxLayout:\n        orientation: 'vertical'\n\n        BoxLayout:\n            size_hint_y: None\n            height: sp(52)\n\n            Button:\n                text: 'Icon View'\n                on_press: fc.view_mode = 'icon'\n            Button:\n                text: 'List View'\n                on_press: fc.view_mode = 'list'\n\n        FileChooser:\n            id: fc\n\n            FileChooserIconLayout\n            FileChooserListLayout\n    '''))\n\n    class FileChooserApp(App):\n\n        def build(self):\n            v = root.ids.fc\n            if len(sys.argv) > 1:\n                v.path = sys.argv[1]\n\n            v.bind(selection=lambda *x: pprint(\"selection: %s\" % x[1:]))\n            v.bind(path=lambda *x: pprint(\"path: %s\" % x[1:]))\n\n            return root\n\n    FileChooserApp().run()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/floatlayout.py",
    "content": "'''\nFloat Layout\n============\n\nThe :class:`FloatLayout` class honors only the :attr:`Widget.pos_hint` and\n:attr:`Widget.size_hint` attributes.\n\n.. only:: html\n\n    .. image:: images/floatlayout.gif\n        :align: right\n\n.. only:: latex\n\n    .. image:: images/floatlayout.png\n        :align: right\n\nFor example, a FloatLayout with a size of (300, 300) is created::\n\n    layout = FloatLayout(size=(300, 300))\n\nBy default, all widgets have their size_hint=(1, 1), so this button will adopt\nthe same size as the layout::\n\n    button = Button(text='Hello world')\n    layout.add_widget(button)\n\nTo create a button 50% of the width and 25% of the height of the layout and\npositioned at (20, 20), you can do::\n\n    button = Button(\n        text='Hello world',\n        size_hint=(.5, .25),\n        pos=(20, 20))\n\nIf you want to create a button that will always be the size of layout minus\n20% on each side::\n\n    button = Button(text='Hello world', size_hint=(.6, .6),\n                    pos_hint={'x':.2, 'y':.2})\n\n.. note::\n\n    This layout can be used for an application. Most of the time, you will\n    use the size of Window.\n\n.. warning::\n\n    If you are not using pos_hint, you must handle the positioning of the\n    children: if the float layout is moving, you must handle moving the\n    children too.\n\n'''\n\n__all__ = ('FloatLayout', )\n\nfrom kivy.uix.layout import Layout\n\n\nclass FloatLayout(Layout):\n    '''Float layout class. See module documentation for more information.\n    '''\n\n    def __init__(self, **kwargs):\n        kwargs.setdefault('size', (1, 1))\n        super(FloatLayout, self).__init__(**kwargs)\n        self.bind(\n            children=self._trigger_layout,\n            pos=self._trigger_layout,\n            pos_hint=self._trigger_layout,\n            size_hint=self._trigger_layout,\n            size=self._trigger_layout)\n\n    def do_layout(self, *largs, **kwargs):\n        # optimization, until the size is 1, 1, don't do layout\n        if self.size == [1, 1]:\n            return\n        # optimize layout by preventing looking at the same attribute in a loop\n        w, h = kwargs.get('size', self.size)\n        x, y = kwargs.get('pos', self.pos)\n        for c in self.children:\n            # size\n            shw, shh = c.size_hint\n            if shw and shh:\n                c.size = w * shw, h * shh\n            elif shw:\n                c.width = w * shw\n            elif shh:\n                c.height = h * shh\n\n            # pos\n            for key, value in c.pos_hint.items():\n                if key == 'x':\n                    c.x = x + value * w\n                elif key == 'right':\n                    c.right = x + value * w\n                elif key == 'pos':\n                    c.pos = x + value[0] * w, y + value[1] * h\n                elif key == 'y':\n                    c.y = y + value * h\n                elif key == 'top':\n                    c.top = y + value * h\n                elif key == 'center':\n                    c.center = x + value[0] * w, y + value[1] * h\n                elif key == 'center_x':\n                    c.center_x = x + value * w\n                elif key == 'center_y':\n                    c.center_y = y + value * h\n\n    def add_widget(self, widget, index=0):\n        widget.bind(\n            #size=self._trigger_layout,\n            #size_hint=self._trigger_layout,\n            pos=self._trigger_layout,\n            pos_hint=self._trigger_layout)\n        return super(FloatLayout, self).add_widget(widget, index)\n\n    def remove_widget(self, widget):\n        widget.unbind(\n            #size=self._trigger_layout,\n            #size_hint=self._trigger_layout,\n            pos=self._trigger_layout,\n            pos_hint=self._trigger_layout)\n        return super(FloatLayout, self).remove_widget(widget)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/gesturesurface.py",
    "content": "'''\nGesture Surface\n===============\n\n.. versionadded::\n    1.9.0\n\n.. warning::\n\n    This is experimental and subject to change as long as this warning notice\n    is present.\n\nSee :file:`kivy/examples/demo/multistroke/main.py` for a complete application\nexample.\n'''\n__all__ = ('GestureSurface', 'GestureContainer')\n\nfrom random import random\nfrom kivy.event import EventDispatcher\nfrom kivy.clock import Clock\nfrom kivy.vector import Vector\nfrom kivy.uix.floatlayout import FloatLayout\nfrom kivy.graphics import Color, Line, Rectangle\nfrom kivy.properties import (NumericProperty, BooleanProperty,\n                             DictProperty, ListProperty)\nfrom colorsys import hsv_to_rgb\n\n# Clock undershoot margin, FIXME: this is probably too high?\nUNDERSHOOT_MARGIN = 0.1\n\n\nclass GestureContainer(EventDispatcher):\n    '''Container object that stores information about a gesture. It has\n    various properties that are updated by `GestureSurface` as drawing\n    progresses.\n\n    :Arguments:\n        `touch`\n            Touch object (as received by on_touch_down) used to initialize\n            the gesture container. Required.\n\n    :Properties:\n        `active`\n            Set to False once the gesture is complete (meets\n            `max_stroke` setting or `GestureSurface.temporal_window`)\n\n            :attr:`active` is a\n            :class:`~kivy.properties.BooleanProperty`\n\n        `active_strokes`\n            Number of strokes currently active in the gesture, ie\n            concurrent touches associated with this gesture.\n\n            :attr:`active_strokes` is a\n            :class:`~kivy.properties.NumericProperty`\n\n        `max_strokes`\n            Max number of strokes allowed in the gesture. This\n            is set by `GestureSurface.max_strokes` but can\n            be overridden for example from `on_gesture_start`.\n\n            :attr:`max_strokes` is a\n            :class:`~kivy.properties.NumericProperty`\n\n        `was_merged`\n            Indicates that this gesture has been merged with another\n            gesture and should be considered discarded.\n\n            :attr:`was_merged` is a\n            :class:`~kivy.properties.BooleanProperty`\n\n        `bbox`\n            Dictionary with keys minx, miny, maxx, maxy. Represents the size\n            of the gesture bounding box.\n\n            :attr:`bbox` is a\n            :class:`~kivy.properties.DictProperty`\n\n        `width`\n            Represents the width of the gesture.\n\n            :attr:`width` is a\n            :class:`~kivy.properties.NumericProperty`\n\n        `height`\n            Represents the height of the gesture.\n\n            :attr:`height` is a\n            :class:`~kivy.properties.NumericProperty`\n    '''\n    active = BooleanProperty(True)\n    active_strokes = NumericProperty(0)\n    max_strokes = NumericProperty(0)\n    was_merged = BooleanProperty(False)\n    bbox = DictProperty({'minx': float('inf'), 'miny': float('inf'),\n                         'maxx': float('-inf'), 'maxy': float('-inf')})\n    width = NumericProperty(0)\n    height = NumericProperty(0)\n\n    def __init__(self, touch, **kwargs):\n        super(GestureContainer, self).__init__(**kwargs)\n\n        # This is the touch.uid of the oldest touch represented\n        self.id = str(touch.uid)\n\n        # Store various timestamps for decision making\n        self._create_time = Clock.get_time()\n        self._update_time = None\n        self._cleanup_time = None\n        self._cache_time = 0\n\n        # We can cache the candidate here to save zip()/Vector instantiation\n        self._vectors = None\n\n        # The color is applied to all canvas items of this gesture\n        col = kwargs.get('color', None)\n        if col is not None:\n            self.color = col\n        else:\n            self.color = [1.0, 1.0, 1.0]\n\n        # Key is touch.uid; value is a kivy.graphics.Line(); it's used even\n        # if line_width is 0 (ie not actually drawn anywhere)\n        self._strokes = {}\n\n        # Make sure the bbox is up to date with the first touch position\n        self.update_bbox(touch)\n\n    def get_vectors(self, **kwargs):\n        '''Return strokes in a format that is acceptable for\n        `kivy.multistroke.Recognizer` as a gesture candidate or template. The\n        result is cached automatically; the cache is invalidated at the start\n        and end of a stroke and if `update_bbox` is called. If you are going\n        to analyze a gesture mid-stroke, you may need to set the `no_cache`\n        argument to True.'''\n        if self._cache_time == self._update_time and not kwargs.get('no_cache'):\n            return self._vectors\n\n        vecs = []\n        append = vecs.append\n        for tuid, l in self._strokes.items():\n            lpts = l.points\n            append([Vector(*pts) for pts in zip(lpts[::2], lpts[1::2])])\n\n        self._vectors = vecs\n        self._cache_time = self._update_time\n        return vecs\n\n    def handles(self, touch):\n        '''Returns True if this container handles the given touch'''\n        if not self.active:\n            return False\n        return str(touch.uid) in self._strokes\n\n    def accept_stroke(self, count=1):\n        '''Returns True if this container can accept `count` new strokes'''\n        if not self.max_strokes:\n            return True\n        return len(self._strokes) + count <= self.max_strokes\n\n    def update_bbox(self, touch):\n        '''Update gesture bbox from a touch coordinate'''\n        x, y = touch.x, touch.y\n        bb = self.bbox\n        if x < bb['minx']:\n            bb['minx'] = x\n        if y < bb['miny']:\n            bb['miny'] = y\n        if x > bb['maxx']:\n            bb['maxx'] = x\n        if y > bb['maxy']:\n            bb['maxy'] = y\n        self.width = bb['maxx'] - bb['minx']\n        self.height = bb['maxy'] - bb['miny']\n        self._update_time = Clock.get_time()\n\n    def add_stroke(self, touch, line):\n        '''Associate a list of points with a touch.uid; the line itself is\n        created by the caller, but subsequent move/up events look it\n        up via us. This is done to avoid problems during merge.'''\n        self._update_time = Clock.get_time()\n        self._strokes[str(touch.uid)] = line\n        self.active_strokes += 1\n\n    def complete_stroke(self):\n        '''Called on touch up events to keep track of how many strokes\n        are active in the gesture (we only want to dispatch event when\n        the *last* stroke in the gesture is released)'''\n        self._update_time = Clock.get_time()\n        self.active_strokes -= 1\n\n    def single_points_test(self):\n        '''Returns True if the gesture consists only of single-point strokes,\n        we must discard it in this case, or an exception will be raised'''\n        for tuid, l in self._strokes.items():\n            if len(l.points) > 2:\n                return False\n        return True\n\n\nclass GestureSurface(FloatLayout):\n    '''Simple gesture surface to track/draw touch movements. Typically used\n    to gather user input suitable for :class:`kivy.multistroke.Recognizer`.\n\n    :Properties:\n        `temporal_window`\n            Time to wait from the last touch_up event before attempting\n            to recognize the gesture. If you set this to 0, the\n            `on_gesture_complete` event is not fired unless the\n            :attr:`max_strokes` condition is met.\n\n            :attr:`temporal_window` is a\n            :class:`~kivy.properties.NumericProperty` and defaults to 2.0\n\n        `max_strokes`\n            Max number of strokes in a single gesture; if this is reached,\n            recognition will start immediately on the final touch_up event.\n            If this is set to 0, the `on_gesture_complete` event is not\n            fired unless the :attr:`temporal_window` expires.\n\n            :attr:`max_strokes` is a\n            :class:`~kivy.properties.NumericProperty` and defaults to 2.0\n\n        `bbox_margin`\n            Bounding box margin for detecting gesture collisions, in\n            pixels.\n\n            :attr:`bbox_margin` is a\n            :class:`~kivy.properties.NumericProperty` and defaults to 30\n\n        `draw_timeout`\n            Number of seconds to keep lines/bbox on canvas after the\n            `on_gesture_complete` event is fired. If this is set to 0,\n            gestures are immediately removed from the surface when\n            complete.\n\n            :attr:`draw_timeout` is a\n            :class:`~kivy.properties.NumericProperty` and defaults to 3.0\n\n        `color`\n            Color used to draw the gesture, in RGB. This option does not\n            have an effect if :attr:`use_random_color` is True.\n\n            :attr:`draw_timeout` is a\n            :class:`~kivy.properties.ListProperty` and defaults to\n            [1, 1, 1] (white)\n\n        `use_random_color`\n            Set to True to pick a random color for each gesture, if you do\n            this then `color` is ignored. Defaults to False.\n\n            :attr:`use_random_color` is a\n            :class:`~kivy.properties.BooleanProperty` and defaults to False\n\n        `line_width`\n            Line width used for tracing touches on the surface. Set to 0\n            if you only want to detect gestures without drawing anything.\n            If you use 1.0, OpenGL GL_LINE is used for drawing; values > 1\n            will use an internal drawing method based on triangles (less\n            efficient), see :mod:`kivy.graphics`.\n\n            :attr:`line_width` is a\n            :class:`~kivy.properties.NumericProperty` and defaults to 2\n\n        `draw_bbox`\n            Set to True if you want to draw bounding box behind gestures.\n            This only works if `line_width` >= 1. Default is False.\n\n            :attr:`draw_bbox` is a\n            :class:`~kivy.properties.BooleanProperty` and defaults to True\n\n        `bbox_alpha`\n            Opacity for bounding box if `draw_bbox` is True. Default 0.1\n\n            :attr:`bbox_alpha` is a\n            :class:`~kivy.properties.NumericProperty` and defaults to 0.1\n\n    :Events:\n        `on_gesture_start` :class:`GestureContainer`\n            Fired when a new gesture is initiated on the surface, ie the\n            first on_touch_down that does not collide with an existing\n            gesture on the surface.\n\n        `on_gesture_extend` :class:`GestureContainer`\n            Fired when a touch_down event occurs within an existing gesture.\n\n        `on_gesture_merge` :class:`GestureContainer`, :class:`GestureContainer`\n            Fired when two gestures collide and get merged to one gesture.\n            The first argument is the gesture that has been merged (no longer\n            valid); the second is the combined (resulting) gesture.\n\n        `on_gesture_complete` :class:`GestureContainer`\n            Fired when a set of strokes is considered a complete gesture,\n            this happens when `temporal_window` expires or `max_strokes`\n            is reached. Typically you will bind to this event and use\n            the provided `GestureContainer` get_vectors() method to\n            match against your gesture database.\n\n        `on_gesture_cleanup` :class:`GestureContainer`\n            Fired `draw_timeout` seconds after `on_gesture_complete`,\n            The gesture will be removed from the canvas (if line_width > 0 or\n            draw_bbox is True) and the internal gesture list before this.\n\n        `on_gesture_discard` :class:`GestureContainer`\n            Fired when a gesture does not meet the minimum size requirements\n            for recognition (width/height < 5, or consists only of single-\n            point strokes).\n    '''\n\n    temporal_window = NumericProperty(2.0)\n    draw_timeout = NumericProperty(3.0)\n    max_strokes = NumericProperty(4)\n    bbox_margin = NumericProperty(30)\n\n    line_width = NumericProperty(2)\n    color = ListProperty([1., 1., 1.])\n    use_random_color = BooleanProperty(False)\n    draw_bbox = BooleanProperty(False)\n    bbox_alpha = NumericProperty(0.1)\n\n    def __init__(self, **kwargs):\n        super(GestureSurface, self).__init__(**kwargs)\n        # A list of GestureContainer objects (all gestures on the surface)\n        self._gestures = []\n        self.register_event_type('on_gesture_start')\n        self.register_event_type('on_gesture_extend')\n        self.register_event_type('on_gesture_merge')\n        self.register_event_type('on_gesture_complete')\n        self.register_event_type('on_gesture_cleanup')\n        self.register_event_type('on_gesture_discard')\n\n# -----------------------------------------------------------------------------\n# Touch Events\n# -----------------------------------------------------------------------------\n    def on_touch_down(self, touch):\n        '''When a new touch is registered, the first thing we do is to test if\n        it collides with the bounding box of another known gesture. If so, it\n        is assumed to be part of that gesture.\n        '''\n        # If the touch originates outside the surface, ignore it.\n        if not self.collide_point(touch.x, touch.y):\n            return\n\n        touch.grab(self)\n\n        # Add the stroke to existing gesture, or make a new one\n        g = self.find_colliding_gesture(touch)\n        new = False\n        if g is None:\n            g = self.init_gesture(touch)\n            new = True\n\n        # We now belong to a gesture (new or old); start a new stroke.\n        self.init_stroke(g, touch)\n\n        if new:\n            self.dispatch('on_gesture_start', g, touch)\n        else:\n            self.dispatch('on_gesture_extend', g, touch)\n\n        return True\n\n    def on_touch_move(self, touch):\n        '''When a touch moves, we add a point to the line on the canvas so the\n        path is updated. We must also check if the new point collides with the\n        bouonding box of another gesture - if so, they should be merged.'''\n        if touch.grab_current is not self:\n            return\n        if not self.collide_point(touch.y, touch.y):\n            return\n\n        # Retrieve the GestureContainer object that handles this touch, and\n        # test for colliding gestures. If found, merge them to one.\n        g = self.get_gesture(touch)\n        collision = self.find_colliding_gesture(touch)\n        if collision is not None and g.accept_stroke(len(collision._strokes)):\n            merge = self.merge_gestures(g, collision)\n            if g.was_merged:\n                self.dispatch('on_gesture_merge', g, collision)\n            else:\n                self.dispatch('on_gesture_merge', collision, g)\n            g = merge\n        else:\n            g.update_bbox(touch)\n\n        # Add the new point to gesture stroke list and update the canvas line\n        g._strokes[str(touch.uid)].points += (touch.x, touch.y)\n\n        # Draw the gesture bounding box; if it is a single press that\n        # does not trigger a move event, we would miss it otherwise.\n        if self.draw_bbox:\n            self._update_canvas_bbox(g)\n        return True\n\n    def on_touch_up(self, touch):\n        if touch.grab_current is not self:\n            return\n        touch.ungrab(self)\n\n        g = self.get_gesture(touch)\n        g.complete_stroke()\n\n        # If this stroke hit the maximum limit, dispatch immediately\n        if not g.accept_stroke():\n            self._complete_dispatcher(0)\n\n        # dispatch later only if we have a window\n        elif self.temporal_window > 0:\n            Clock.schedule_once(self._complete_dispatcher, self.temporal_window)\n\n# -----------------------------------------------------------------------------\n# Gesture related methods\n# -----------------------------------------------------------------------------\n    def init_gesture(self, touch):\n        '''Create a new gesture from touch, ie it's the first on\n        surface, or was not close enough to any existing gesture (yet)'''\n        col = self.color\n        if self.use_random_color is True:\n            col = hsv_to_rgb(random(), 1., 1.)\n\n        g = GestureContainer(touch, max_strokes=self.max_strokes,\n                             line_width=self.line_width, color=col)\n\n        # Create the bounding box Rectangle for the gesture\n        if self.draw_bbox:\n            bb = g.bbox\n            with self.canvas:\n                Color(col[0], col[1], col[2], self.bbox_alpha, mode='rgba',\n                      group=g.id)\n\n                g._bbrect = Rectangle(\n                    group=g.id,\n                    pos=(bb['minx'], bb['miny']),\n                    size=(bb['maxx'] - bb['minx'],\n                          bb['maxy'] - bb['miny']))\n\n        self._gestures.append(g)\n        return g\n\n    def init_stroke(self, g, touch):\n        l = [touch.x, touch.y]\n        col = g.color\n\n        new_line = Line(\n            points=l,\n            width=self.line_width,\n            group=g.id)\n        g._strokes[str(touch.uid)] = new_line\n\n        if self.line_width:\n            canvas_add = self.canvas.add\n            canvas_add(Color(col[0], col[1], col[2], mode='rgb', group=g.id))\n            canvas_add(new_line)\n\n        # Update the bbox in case; this will normally be done in on_touch_move,\n        # but we want to update it also for a single press, force that here:\n        g.update_bbox(touch)\n        if self.draw_bbox:\n            self._update_canvas_bbox(g)\n\n        # Register the stroke in GestureContainer so we can look it up later\n        g.add_stroke(touch, new_line)\n\n    def get_gesture(self, touch):\n        '''Returns GestureContainer associated with given touch'''\n        for g in self._gestures:\n            if g.active and g.handles(touch):\n                return g\n        raise Exception('get_gesture() failed to identify ' + str(touch.uid))\n\n    def find_colliding_gesture(self, touch):\n        '''Checks if a touch x/y collides with the bounding box of an existing\n        gesture. If so, return it (otherwise returns None)\n        '''\n        touch_x, touch_y = touch.pos\n        for g in self._gestures:\n            if g.active and not g.handles(touch) and g.accept_stroke():\n                bb = g.bbox\n                margin = self.bbox_margin\n                minx = bb['minx'] - margin\n                miny = bb['miny'] - margin\n                maxx = bb['maxx'] + margin\n                maxy = bb['maxy'] + margin\n                if minx <= touch_x <= maxx and miny <= touch_y <= maxy:\n                    return g\n        return None\n\n    def merge_gestures(self, g, other):\n        '''Merges two gestures together, the oldest one is retained and the\n        newer one gets the `GestureContainer.was_merged` flag raised.'''\n        # Swap order depending on gesture age (the merged gesture gets\n        # the color from the oldest one of the two).\n        swap = other._create_time < g._create_time\n        a = swap and other or g\n        b = swap and g or other\n\n        # Apply the outer limits of bbox to the merged gesture\n        abbox = a.bbox\n        bbbox = b.bbox\n        if bbbox['minx'] < abbox['minx']:\n            abbox['minx'] = bbbox['minx']\n        if bbbox['miny'] < abbox['miny']:\n            abbox['miny'] = bbbox['miny']\n        if bbbox['maxx'] > abbox['maxx']:\n            abbox['maxx'] = bbbox['maxx']\n        if bbbox['maxy'] > abbox['maxy']:\n            abbox['maxy'] = bbbox['maxy']\n\n        # Now transfer the coordinates from old to new gesture;\n        # FIXME: This can probably be copied more efficiently?\n        astrokes = a._strokes\n        lw = self.line_width\n        a_id = a.id\n        col = a.color\n\n        self.canvas.remove_group(b.id)\n        canv_add = self.canvas.add\n        for uid, old in b._strokes.items():\n            # FIXME: Can't figure out how to change group= for existing Line()\n            new_line = Line(\n                points=old.points,\n                width=old.width,\n                group=a_id)\n            astrokes[uid] = new_line\n            if lw:\n                canv_add(Color(col[0], col[1], col[2], mode='rgb', group=a_id))\n                canv_add(new_line)\n\n        b.active = False\n        b.was_merged = True\n        a.active_strokes += b.active_strokes\n        a._update_time = Clock.get_time()\n        return a\n\n    def _update_canvas_bbox(self, g):\n        # If draw_bbox is changed while two gestures are active,\n        # we might not have a bbrect member\n        if not hasattr(g, '_bbrect'):\n            return\n\n        bb = g.bbox\n        g._bbrect.pos = (bb['minx'], bb['miny'])\n        g._bbrect.size = (bb['maxx'] - bb['minx'],\n                          bb['maxy'] - bb['miny'])\n\n# -----------------------------------------------------------------------------\n# Timeout callbacks\n# -----------------------------------------------------------------------------\n    def _complete_dispatcher(self, dt):\n        '''This method is scheduled on all touch up events. It will dispatch\n        the `on_gesture_complete` event for all completed gestures, and remove\n        merged gestures from the internal gesture list.'''\n        need_cleanup = False\n        gest = self._gestures\n        timeout = self.draw_timeout\n        twin = self.temporal_window\n        get_time = Clock.get_time\n\n        for idx, g in enumerate(gest):\n            # Gesture is part of another gesture, just delete it\n            if g.was_merged:\n                del gest[idx]\n                continue\n\n            # Not active == already handled, or has active strokes (it cannot\n            # possibly be complete). Proceed to next gesture on surface.\n            if not g.active or g.active_strokes != 0:\n                continue\n\n            t1 = g._update_time + twin\n            t2 = get_time() + UNDERSHOOT_MARGIN\n\n            # max_strokes reached, or temporal window has expired. The gesture\n            # is complete; need to dispatch _complete or _discard event.\n            if not g.accept_stroke() or t1 <= t2:\n                discard = False\n                if g.width < 5 and g.height < 5:\n                    discard = True\n                elif g.single_points_test():\n                    discard = True\n\n                need_cleanup = True\n                g.active = False\n                g._cleanup_time = get_time() + timeout\n\n                if discard:\n                    self.dispatch('on_gesture_discard', g)\n                else:\n                    self.dispatch('on_gesture_complete', g)\n\n        if need_cleanup:\n            Clock.schedule_once(self._cleanup, timeout)\n\n    def _cleanup(self, dt):\n        '''This method is scheduled from _complete_dispatcher to clean up the\n        canvas and internal gesture list after a gesture is completed.'''\n        m = UNDERSHOOT_MARGIN\n        rg = self.canvas.remove_group\n        gestures = self._gestures\n        for idx, g in enumerate(gestures):\n            if g._cleanup_time is None:\n                continue\n            if g._cleanup_time <= Clock.get_time() + m:\n                rg(g.id)\n                del gestures[idx]\n                self.dispatch('on_gesture_cleanup', g)\n\n    def on_gesture_start(self, *l):\n        pass\n\n    def on_gesture_extend(self, *l):\n        pass\n\n    def on_gesture_merge(self, *l):\n        pass\n\n    def on_gesture_complete(self, *l):\n        pass\n\n    def on_gesture_discard(self, *l):\n        pass\n\n    def on_gesture_cleanup(self, *l):\n        pass\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/gridlayout.py",
    "content": "'''\nGrid Layout\n===========\n\n.. only:: html\n\n    .. image:: images/gridlayout.gif\n        :align: right\n\n.. only:: latex\n\n    .. image:: images/gridlayout.png\n        :align: right\n\n.. versionadded:: 1.0.4\n\nThe :class:`GridLayout` arranges children in a matrix. It takes the available\nspace and divides it into columns and rows, then adds widgets to the resulting\n\"cells\".\n\n.. versionchanged:: 1.0.7\n    The implementation has changed to use the widget size_hint for calculating\n    column/row sizes. `uniform_width` and `uniform_height` have been removed\n    and other properties have added to give you more control.\n\nBackground\n----------\n\nUnlike many other toolkits, you cannot explicitly place a widget in a specific\ncolumn/row. Each child is automatically assigned a position determined by the\nlayout configuration and the child's index in the children list.\n\nA GridLayout must always have at least one input constraint:\n:attr:`GridLayout.cols` or :attr:`GridLayout.rows`. If you do not specify cols\nor rows, the Layout will throw an exception.\n\nColumn Width and Row Height\n---------------------------\n\nThe column width/row height are determined in 3 steps:\n\n    - The initial size is given by the :attr:`col_default_width` and\n      :attr:`row_default_height` properties. To customize the size of a single\n      column or row, use :attr:`cols_minimum` or :attr:`rows_minimum`.\n    - The `size_hint_x`/`size_hint_y` of the children are taken into account.\n      If no widgets have a size hint, the maximum size is used for all\n      children.\n    - You can force the default size by setting the :attr:`col_force_default`\n      or :attr:`row_force_default` property. This will force the layout to\n      ignore the `width` and `size_hint` properties of children and use the\n      default size.\n\nUsing a GridLayout\n------------------\n\nIn the example below, all widgets will have an equal size. By default, the\n`size_hint` is (1, 1), so a Widget will take the full size of the parent::\n\n    layout = GridLayout(cols=2)\n    layout.add_widget(Button(text='Hello 1'))\n    layout.add_widget(Button(text='World 1'))\n    layout.add_widget(Button(text='Hello 2'))\n    layout.add_widget(Button(text='World 2'))\n\n.. image:: images/gridlayout_1.jpg\n\nNow, let's fix the size of Hello buttons to 100px instead of using\nsize_hint_x=1::\n\n    layout = GridLayout(cols=2)\n    layout.add_widget(Button(text='Hello 1', size_hint_x=None, width=100))\n    layout.add_widget(Button(text='World 1'))\n    layout.add_widget(Button(text='Hello 2', size_hint_x=None, width=100))\n    layout.add_widget(Button(text='World 2'))\n\n.. image:: images/gridlayout_2.jpg\n\nNext, let's fix the row height to a specific size::\n\n    layout = GridLayout(cols=2, row_force_default=True, row_default_height=40)\n    layout.add_widget(Button(text='Hello 1', size_hint_x=None, width=100))\n    layout.add_widget(Button(text='World 1'))\n    layout.add_widget(Button(text='Hello 2', size_hint_x=None, width=100))\n    layout.add_widget(Button(text='World 2'))\n\n.. image:: images/gridlayout_3.jpg\n\n'''\n\n__all__ = ('GridLayout', 'GridLayoutException')\n\nfrom kivy.logger import Logger\nfrom kivy.uix.layout import Layout\nfrom kivy.properties import NumericProperty, BooleanProperty, DictProperty, \\\n    BoundedNumericProperty, ReferenceListProperty, VariableListProperty\nfrom math import ceil\n\n\ndef nmax(*args):\n    '''(internal) Implementation of a max() function that supports None.\n    '''\n    # merge into one list\n    args = [x for x in args if x is not None]\n    return max(args)\n\n\nclass GridLayoutException(Exception):\n    '''Exception for errors if the grid layout manipulation fails.\n    '''\n    pass\n\n\nclass GridLayout(Layout):\n    '''Grid layout class. See module documentation for more information.\n    '''\n\n    spacing = VariableListProperty([0, 0], length=2)\n    '''Spacing between children: [spacing_horizontal, spacing_vertical].\n\n    spacing also accepts a one argument form [spacing].\n\n    :attr:`spacing` is a\n    :class:`~kivy.properties.VariableListProperty` and defaults to [0, 0].\n    '''\n\n    padding = VariableListProperty([0, 0, 0, 0])\n    '''Padding between the layout box and it's children: [padding_left,\n    padding_top, padding_right, padding_bottom].\n\n    padding also accepts a two argument form [padding_horizontal,\n    padding_vertical] and a one argument form [padding].\n\n    .. versionchanged:: 1.7.0\n        Replaced NumericProperty with VariableListProperty.\n\n    :attr:`padding` is a :class:`~kivy.properties.VariableListProperty` and\n    defaults to [0, 0, 0, 0].\n    '''\n\n    cols = BoundedNumericProperty(None, min=0, allownone=True)\n    '''Number of columns in the grid.\n\n    .. versionchanged:: 1.0.8\n        Changed from a NumericProperty to BoundedNumericProperty. You can no\n        longer set this to a negative value.\n\n    :attr:`cols` is a :class:`~kivy.properties.NumericProperty` and defaults to\n    0.\n    '''\n\n    rows = BoundedNumericProperty(None, min=0, allownone=True)\n    '''Number of rows in the grid.\n\n    .. versionchanged:: 1.0.8\n        Changed from a NumericProperty to a BoundedNumericProperty. You can no\n        longer set this to a negative value.\n\n    :attr:`rows` is a :class:`~kivy.properties.NumericProperty` and defaults to\n    0.\n    '''\n\n    col_default_width = NumericProperty(0)\n    '''Default minimum size to use for a column.\n\n    .. versionadded:: 1.0.7\n\n    :attr:`col_default_width` is a :class:`~kivy.properties.NumericProperty`\n    and defaults to 0.\n    '''\n\n    row_default_height = NumericProperty(0)\n    '''Default minimum size to use for row.\n\n    .. versionadded:: 1.0.7\n\n    :attr:`row_default_height` is a :class:`~kivy.properties.NumericProperty`\n    and defaults to 0.\n    '''\n\n    col_force_default = BooleanProperty(False)\n    '''If True, ignore the width and size_hint_x of the child and use the\n    default column width.\n\n    .. versionadded:: 1.0.7\n\n    :attr:`col_force_default` is a :class:`~kivy.properties.BooleanProperty`\n    and defaults to False.\n    '''\n\n    row_force_default = BooleanProperty(False)\n    '''If True, ignore the height and size_hint_y of the child and use the\n    default row height.\n\n    .. versionadded:: 1.0.7\n\n    :attr:`row_force_default` is a :class:`~kivy.properties.BooleanProperty`\n    and defaults to False.\n    '''\n\n    cols_minimum = DictProperty({})\n    '''List of minimum sizes for each column.\n\n    .. versionadded:: 1.0.7\n\n    :attr:`cols_minimum` is a :class:`~kivy.properties.DictProperty` and\n    defaults to {}.\n    '''\n\n    rows_minimum = DictProperty({})\n    '''List of minimum sizes for each row.\n\n    .. versionadded:: 1.0.7\n\n    :attr:`rows_minimum` is a :class:`~kivy.properties.DictProperty` and\n    defaults to {}.\n    '''\n\n    minimum_width = NumericProperty(0)\n    '''Minimum width needed to contain all children.\n\n    .. versionadded:: 1.0.8\n\n    :attr:`minimum_width` is a :class:`kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    minimum_height = NumericProperty(0)\n    '''Minimum height needed to contain all children.\n\n    .. versionadded:: 1.0.8\n\n    :attr:`minimum_height` is a :class:`kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    minimum_size = ReferenceListProperty(minimum_width, minimum_height)\n    '''Minimum size needed to contain all children.\n\n    .. versionadded:: 1.0.8\n\n    :attr:`minimum_size` is a\n    :class:`~kivy.properties.ReferenceListProperty` of\n    (:attr:`minimum_width`, :attr:`minimum_height`) properties.\n    '''\n\n    def __init__(self, **kwargs):\n        self._cols = self._rows = None\n        super(GridLayout, self).__init__(**kwargs)\n\n        self.bind(\n            col_default_width=self._trigger_layout,\n            row_default_height=self._trigger_layout,\n            col_force_default=self._trigger_layout,\n            row_force_default=self._trigger_layout,\n            cols=self._trigger_layout,\n            rows=self._trigger_layout,\n            parent=self._trigger_layout,\n            spacing=self._trigger_layout,\n            padding=self._trigger_layout,\n            children=self._trigger_layout,\n            size=self._trigger_layout,\n            pos=self._trigger_layout)\n\n    def get_max_widgets(self):\n        if self.cols and not self.rows:\n            return None\n        if self.rows and not self.cols:\n            return None\n        if not self.cols and not self.rows:\n            return None\n        return self.rows * self.cols\n\n    def on_children(self, instance, value):\n        # if that makes impossible to construct things with deffered method,\n        # migrate this test in do_layout, and/or issue a warning.\n        smax = self.get_max_widgets()\n        if smax and len(value) > smax:\n            raise GridLayoutException(\n                'Too many children in GridLayout. Increase rows/cols!')\n\n    def update_minimum_size(self, *largs):\n        # the goal here is to calculate the minimum size of every cols/rows\n        # and determine if they have stretch or not\n        current_cols = self.cols\n        current_rows = self.rows\n        children = self.children\n        len_children = len(children)\n\n        # if no cols or rows are set, we can't calculate minimum size.\n        # the grid must be contrained at least on one side\n        if not current_cols and not current_rows:\n            Logger.warning('%r have no cols or rows set, '\n                           'layout is not triggered.' % self)\n            return None\n        if current_cols is None:\n            current_cols = int(ceil(len_children / float(current_rows)))\n        elif current_rows is None:\n            current_rows = int(ceil(len_children / float(current_cols)))\n\n        current_cols = max(1, current_cols)\n        current_rows = max(1, current_rows)\n\n        cols = [self.col_default_width] * current_cols\n        cols_sh = [None] * current_cols\n        rows = [self.row_default_height] * current_rows\n        rows_sh = [None] * current_rows\n\n        # update minimum size from the dicts\n        # FIXME index might be outside the bounds ?\n        for index, value in self.cols_minimum.items():\n            cols[index] = value\n        for index, value in self.rows_minimum.items():\n            rows[index] = value\n\n        # calculate minimum size for each columns and rows\n        i = len_children - 1\n        for row in range(current_rows):\n            for col in range(current_cols):\n\n                # don't go further is we don't have child left\n                if i < 0:\n                    break\n\n                # get initial information from the child\n                c = children[i]\n                shw = c.size_hint_x\n                shh = c.size_hint_y\n                w = c.width\n                h = c.height\n\n                # compute minimum size / maximum stretch needed\n                if shw is None:\n                    cols[col] = nmax(cols[col], w)\n                else:\n                    cols_sh[col] = nmax(cols_sh[col], shw)\n                if shh is None:\n                    rows[row] = nmax(rows[row], h)\n                else:\n                    rows_sh[row] = nmax(rows_sh[row], shh)\n\n                # next child\n                i = i - 1\n\n        # calculate minimum width/height needed, starting from padding +\n        # spacing\n        padding_x = self.padding[0] + self.padding[2]\n        padding_y = self.padding[1] + self.padding[3]\n        spacing_x, spacing_y = self.spacing\n        width = padding_x + spacing_x * (current_cols - 1)\n        height = padding_y + spacing_y * (current_rows - 1)\n        # then add the cell size\n        width += sum(cols)\n        height += sum(rows)\n\n        # remember for layout\n        self._cols = cols\n        self._rows = rows\n        self._cols_sh = cols_sh\n        self._rows_sh = rows_sh\n\n        # finally, set the minimum size\n        self.minimum_size = (width, height)\n\n    def do_layout(self, *largs):\n        self.update_minimum_size()\n        if self._cols is None:\n            return\n        if self.cols is None and self.rows is None:\n            raise GridLayoutException('Need at least cols or rows constraint.')\n\n        children = self.children\n        len_children = len(children)\n        if len_children == 0:\n            return\n\n        # speedup\n        padding_left = self.padding[0]\n        padding_top = self.padding[1]\n        spacing_x, spacing_y = self.spacing\n        selfx = self.x\n        selfw = self.width\n        selfh = self.height\n\n        # resolve size for each column\n        if self.col_force_default:\n            cols = [self.col_default_width] * len(self._cols)\n            for index, value in self.cols_minimum.items():\n                cols[index] = value\n        else:\n            cols = self._cols[:]\n            cols_sh = self._cols_sh\n            cols_weigth = sum([x for x in cols_sh if x])\n            strech_w = max(0, selfw - self.minimum_width)\n            for index in range(len(cols)):\n                # if the col don't have strech information, nothing to do\n                col_stretch = cols_sh[index]\n                if col_stretch is None:\n                    continue\n                # calculate the column stretch, and take the maximum from\n                # minimum size and the calculated stretch\n                col_width = cols[index]\n                col_width = max(col_width,\n                                strech_w * col_stretch / cols_weigth)\n                cols[index] = col_width\n\n        # same algo for rows\n        if self.row_force_default:\n            rows = [self.row_default_height] * len(self._rows)\n            for index, value in self.rows_minimum.items():\n                rows[index] = value\n        else:\n            rows = self._rows[:]\n            rows_sh = self._rows_sh\n            rows_weigth = sum([x for x in rows_sh if x])\n            strech_h = max(0, selfh - self.minimum_height)\n            for index in range(len(rows)):\n                # if the row don't have strech information, nothing to do\n                row_stretch = rows_sh[index]\n                if row_stretch is None:\n                    continue\n                # calculate the row stretch, and take the maximum from minimum\n                # size and the calculated stretch\n                row_height = rows[index]\n                row_height = max(row_height,\n                                 strech_h * row_stretch / rows_weigth)\n                rows[index] = row_height\n\n        # reposition every child\n        i = len_children - 1\n        y = self.top - padding_top\n        for row_height in rows:\n            x = selfx + padding_left\n            for col_width in cols:\n                if i < 0:\n                    break\n                c = children[i]\n                c.x = x\n                c.y = y - row_height\n                c.width = col_width\n                c.height = row_height\n                i = i - 1\n                x = x + col_width + spacing_x\n            y -= row_height + spacing_y\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/image.py",
    "content": "'''\nImage\n=====\n\nThe :class:`Image` widget is used to display an image::\n\n    wimg = Image(source='mylogo.png')\n\nAsynchronous Loading\n--------------------\n\nTo load an image asynchronously (for example from an external webserver), use\nthe :class:`AsyncImage` subclass::\n\n    aimg = AsyncImage(source='http://mywebsite.com/logo.png')\n\nThis can be useful as it prevents your application from waiting until the image\nis loaded. If you want to display large images or retrieve them from URL's,\nusing :class:`AsyncImage` will allow these resources to be retrieved on a\nbackground thread without blocking your application.\n\nAlignment\n---------\n\nBy default, the image is centered and fits inside the widget bounding box.\nIf you don't want that, you can set `allow_stretch` to True and `keep_ratio`\nto False.\n\nYou can also inherit from Image and create your own style.\n\n\nFor example, if you want your image to be greater than,the size of your widget,\nyou could do::\n\n    class FullImage(Image):\n        pass\n\nAnd in your kivy language file::\n\n    <-FullImage>:\n        canvas:\n            Color:\n                rgb: (1, 1, 1)\n            Rectangle:\n                texture: self.texture\n                size: self.width + 20, self.height + 20\n                pos: self.x - 10, self.y - 10\n\n'''\n\n__all__ = ('Image', 'AsyncImage')\n\nfrom kivy.uix.widget import Widget\nfrom kivy.core.image import Image as CoreImage\nfrom kivy.resources import resource_find\nfrom kivy.properties import StringProperty, ObjectProperty, ListProperty, \\\n    AliasProperty, BooleanProperty, NumericProperty\nfrom kivy.logger import Logger\n\n# delayed imports\nLoader = None\n\n\nclass Image(Widget):\n    '''Image class, see module documentation for more information.\n    '''\n\n    source = StringProperty(None)\n    '''Filename / source of your image.\n\n    :attr:`source` is a :class:`~kivy.properties.StringProperty` and\n    defaults to None.\n    '''\n\n    texture = ObjectProperty(None, allownone=True)\n    '''Texture object of the image.\n\n    Depending of the texture creation, the value will be a\n    :class:`~kivy.graphics.texture.Texture` or a\n    :class:`~kivy.graphics.texture.TextureRegion` object.\n\n    :attr:`texture` is a :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    texture_size = ListProperty([0, 0])\n    '''Texture size of the image.\n\n    .. warning::\n\n        The texture size is set after the texture property. So if you listen to\n        the change on :attr:`texture`, the property texture_size will not be\n        up-to-date. Use self.texture.size instead.\n    '''\n\n    def get_image_ratio(self):\n        if self.texture:\n            return self.texture.width / float(self.texture.height)\n        return 1.\n\n    mipmap = BooleanProperty(False)\n    '''Indicate if you want OpenGL mipmapping to be applied to the texture.\n    Read :ref:`mipmap` for more information.\n\n    .. versionadded:: 1.0.7\n\n    :attr:`mipmap` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    image_ratio = AliasProperty(get_image_ratio, None, bind=('texture', ))\n    '''Ratio of the image (width / float(height).\n\n    :attr:`image_ratio` is a :class:`~kivy.properties.AliasProperty` and is\n    read-only.\n    '''\n\n    color = ListProperty([1, 1, 1, 1])\n    '''Image color, in the format (r, g, b, a). This attribute can be used to\n    'tint' an image. Be careful: if the source image is not gray/white, the\n    color will not really work as expected.\n\n    .. versionadded:: 1.0.6\n\n    :attr:`color` is a :class:`~kivy.properties.ListProperty` and defaults to\n    [1, 1, 1, 1].\n    '''\n\n    allow_stretch = BooleanProperty(False)\n    '''If True, the normalized image size will be maximized to fit in the image\n    box. Otherwise, if the box is too tall, the image will not be\n    stretched more than 1:1 pixels.\n\n    .. versionadded:: 1.0.7\n\n    :attr:`allow_stretch` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    keep_ratio = BooleanProperty(True)\n    '''If False along with allow_stretch being True, the normalized image\n    size will be maximized to fit in the image box and ignores the aspect\n    ratio of the image.\n    Otherwise, if the box is too tall, the image will not be stretched more\n    than 1:1 pixels.\n\n    .. versionadded:: 1.0.8\n\n    :attr:`keep_ratio` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n\n    keep_data = BooleanProperty(False)\n    '''If True, the underlaying _coreimage will store the raw image data.\n    This is useful when performing pixel based collision detection.\n\n    .. versionadded:: 1.3.0\n\n    :attr:`keep_data` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    anim_delay = NumericProperty(.25)\n    '''Delay the animation if the image is sequenced (like an animated gif).\n    If anim_delay is set to -1, the animation will be stopped.\n\n    .. versionadded:: 1.0.8\n\n    :attr:`anim_delay` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.25 (4 FPS).\n    '''\n\n    anim_loop = NumericProperty(0)\n    '''Number of loops to play then stop animating. 0 means keep animating.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`anim_loop` is a :class:`~kivy.properties.NumericProperty` defaults\n    to 0.\n    '''\n\n    nocache = BooleanProperty(False)\n    '''If this property is set True, the image will not be added to the\n    internal cache. The cache will simply ignore any calls trying to\n    append the core image.\n\n    .. versionadded:: 1.6.0\n\n    :attr:`nocache` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    def get_norm_image_size(self):\n        if not self.texture:\n            return self.size\n        ratio = self.image_ratio\n        w, h = self.size\n        tw, th = self.texture.size\n\n        # ensure that the width is always maximized to the containter width\n        if self.allow_stretch:\n            if not self.keep_ratio:\n                return w, h\n            iw = w\n        else:\n            iw = min(w, tw)\n        # calculate the appropriate height\n        ih = iw / ratio\n        # if the height is too higher, take the height of the container\n        # and calculate appropriate width. no need to test further. :)\n        if ih > h:\n            if self.allow_stretch:\n                ih = h\n            else:\n                ih = min(h, th)\n            iw = ih * ratio\n\n        return iw, ih\n\n    norm_image_size = AliasProperty(get_norm_image_size, None, bind=(\n        'texture', 'size', 'image_ratio', 'allow_stretch'))\n    '''Normalized image size within the widget box.\n\n    This size will always fit the widget size and will preserve the image\n    ratio.\n\n    :attr:`norm_image_size` is a :class:`~kivy.properties.AliasProperty` and is\n    read-only.\n    '''\n\n    def __init__(self, **kwargs):\n        self._coreimage = None\n        self._loops = 0\n        super(Image, self).__init__(**kwargs)\n        self.bind(source=self.texture_update,\n                  mipmap=self.texture_update)\n        if self.source:\n            self.texture_update()\n\n    def texture_update(self, *largs):\n        if not self.source:\n            self.texture = None\n        else:\n            filename = resource_find(self.source)\n            self._loops = 0\n            if filename is None:\n                return Logger.error('Image: Error reading file {filename}'.\n                                    format(filename=self.source))\n            mipmap = self.mipmap\n            if self._coreimage is not None:\n                self._coreimage.unbind(on_texture=self._on_tex_change)\n            try:\n                self._coreimage = ci = CoreImage(filename, mipmap=mipmap,\n                                                 anim_delay=self.anim_delay,\n                                                 keep_data=self.keep_data,\n                                                 nocache=self.nocache)\n            except:\n                self._coreimage = ci = None\n\n            if ci:\n                ci.bind(on_texture=self._on_tex_change)\n                self.texture = ci.texture\n\n    def on_anim_delay(self, instance, value):\n        self._loop = 0\n        if self._coreimage is None:\n            return\n        self._coreimage.anim_delay = value\n        if value < 0:\n            self._coreimage.anim_reset(False)\n\n    def on_texture(self, instance, value):\n        if value is not None:\n            self.texture_size = list(value.size)\n\n    def _on_tex_change(self, *largs):\n        # update texture from core image\n        self.texture = self._coreimage.texture\n        ci = self._coreimage\n        if self.anim_loop and ci._anim_index == len(ci._image.textures) - 1:\n            self._loops += 1\n            if self.anim_loop == self._loops:\n                ci.anim_reset(False)\n                self._loops = 0\n\n    def reload(self):\n        '''Reload image from disk. This facilitates re-loading of\n        images from disk in case the image content changes.\n\n        .. versionadded:: 1.3.0\n\n        Usage::\n\n            im = Image(source = '1.jpg')\n            # -- do something --\n            im.reload()\n            # image will be re-loaded from disk\n\n        '''\n        self._coreimage.remove_from_cache()\n        olsource = self.source\n        self.source = ''\n        self.source = olsource\n\n    def on_nocache(self, *args):\n        if self.nocache and self._coreimage:\n            self._coreimage.remove_from_cache()\n            self._coreimage._nocache = True\n\n\nclass AsyncImage(Image):\n    '''Asynchronous Image class. See the module documentation for more\n    information.\n\n    .. note::\n\n        The AsyncImage is a specialized form of the Image class. You may\n        want to refer to the :mod:`~kivy.loader` documentation and in\n        particular, the :class:`~kivy.loader.ProxyImage` for more detail\n        on how to handle events around asynchronous image loading.\n    '''\n\n    def __init__(self, **kwargs):\n        self._coreimage = None\n        super(AsyncImage, self).__init__(**kwargs)\n        global Loader\n        if not Loader:\n            from kivy.loader import Loader\n        self.bind(source=self._load_source)\n        if self.source:\n            self._load_source()\n\n    def _load_source(self, *args):\n        source = self.source\n        if not source:\n            if self._coreimage is not None:\n                self._coreimage.unbind(on_texture=self._on_tex_change)\n            self.texture = None\n            self._coreimage = None\n        else:\n            if not self.is_uri(source):\n                source = resource_find(source)\n            self._coreimage = image = Loader.image(source,\n                nocache=self.nocache, mipmap=self.mipmap,\n                anim_delay=self.anim_delay)\n            image.bind(on_load=self._on_source_load)\n            image.bind(on_texture=self._on_tex_change)\n            self.texture = image.texture\n\n    def _on_source_load(self, value):\n        image = self._coreimage.image\n        if not image:\n            return\n        self.texture = image.texture\n\n    def is_uri(self, filename):\n        proto = filename.split('://', 1)[0]\n        return proto in ('http', 'https', 'ftp', 'smb')\n\n    def _on_tex_change(self, *largs):\n        if self._coreimage:\n            self.texture = self._coreimage.texture\n\n    def texture_update(self, *largs):\n        pass\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/label.py",
    "content": "'''\nLabel\n=====\n\nThe :class:`Label` widget is for rendering text. It supports ascii and unicode\nstrings::\n\n    # hello world text\n    l = Label(text='Hello world')\n\n    # unicode text; can only display glyphs that are available in the font\n    l = Label(text=u'Hello world ' + unichr(2764))\n\n    # multiline text\n    l = Label(text='Multi\\\\nLine')\n\n    # size\n    l = Label(text='Hello world', font_size='20sp')\n\nMarkup text\n-----------\n\n.. versionadded:: 1.1.0\n\nYou can change the style of the text using :doc:`api-kivy.core.text.markup`.\nThe syntax is similar to the bbcode syntax but only the inline styling is\nallowed::\n\n    # hello world with world in bold\n    l = Label(text='Hello [b]World[/b]', markup=True)\n\n    # hello in red, world in blue\n    l = Label(text='[color=ff3333]Hello[/color][color=3333ff]World[/color]',\n        markup = True)\n\nIf you need to escape the markup from the current text, use\n:func:`kivy.utils.escape_markup`::\n\n    text = 'This is an important message [1]'\n    l = Label(text='[b]' + escape_markup(text) + '[/b]', markup=True)\n\nThe following tags are available:\n\n``[b][/b]``\n    Activate bold text\n``[i][/i]``\n    Activate italic text\n``[font=<str>][/font]``\n    Change the font\n``[size=<integer>][/size]``\n    Change the font size\n``[color=#<color>][/color]``\n    Change the text color\n``[ref=<str>][/ref]``\n    Add an interactive zone. The reference + bounding box inside the\n    reference will be available in :attr:`Label.refs`\n``[anchor=<str>]``\n    Put an anchor in the text. You can get the position of your anchor within\n    the text with :attr:`Label.anchors`\n``[sub][/sub]``\n    Display the text at a subscript position relative to the text before it.\n``[sup][/sup]``\n    Display the text at a superscript position relative to the text before it.\n\nIf you want to render the markup text with a [ or ] or & character, you need to\nescape them. We created a simple syntax::\n\n    [   -> &bl;\n    ]   -> &br;\n    &   -> &amp;\n\nThen you can write::\n\n    \"[size=24]Hello &bl;World&bt;[/size]\"\n\nInteractive Zone in Text\n------------------------\n\n.. versionadded:: 1.1.0\n\nYou can now have definable \"links\" using text markup. The idea is to be able\nto detect when the user clicks on part of the text and to react.\nThe tag ``[ref=xxx]`` is used for that.\n\nIn this example, we are creating a reference on the word \"World\". When\nthis word is clicked, the function ``print_it`` will be called with the\nname of the reference::\n\n    def print_it(instance, value):\n        print('User clicked on', value)\n    widget = Label(text='Hello [ref=world]World[/ref]', markup=True)\n    widget.bind(on_ref_press=print_it)\n\nFor prettier rendering, you could add a color for the reference. Replace the\n``text=`` in the previous example with::\n\n    'Hello [ref=world][color=0000ff]World[/color][/ref]'\n\nUsage example\n-------------\n\nThe following example marks the anchors and references contained in a label::\n\n    from kivy.app import App\n    from kivy.uix.label import Label\n    from kivy.clock import Clock\n    from kivy.graphics import Color, Rectangle\n\n\n    class TestApp(App):\n\n        @staticmethod\n        def get_x(label, ref_x):\n            \"\"\" Return the x value of the ref/anchor relative to the canvas \"\"\"\n            return label.center_x - label.texture_size[0] * 0.5 + ref_x\n\n        @staticmethod\n        def get_y(label, ref_y):\n            \"\"\" Return the y value of the ref/anchor relative to the canvas \"\"\"\n            # Note the inversion of direction, as y values start at the top of\n            # the texture and increase downwards\n            return label.center_y + label.texture_size[1] * 0.5 - ref_y\n\n        def show_marks(self, label):\n\n            # Indicate the position of the anchors with a red top marker\n            for name, anc in label.anchors.items():\n                with label.canvas:\n                    Color(1, 0, 0)\n                    Rectangle(pos=(self.get_x(label, anc[0]),\n                                   self.get_y(label, anc[1])),\n                              size=(3, 3))\n\n            # Draw a green surround around the refs. Note the sizes y inversion\n            for name, boxes in label.refs.items():\n                for box in boxes:\n                    with label.canvas:\n                        Color(0, 1, 0, 0.25)\n                        Rectangle(pos=(self.get_x(label, box[0]),\n                                       self.get_y(label, box[1])),\n                                  size=(box[2] - box[0],\n                                        box[1] - box[3]))\n\n        def build(self):\n            label = Label(\n                text='[anchor=a]a\\\\nChars [anchor=b]b\\\\n[ref=myref]ref[/ref]',\n                markup=True)\n            Clock.schedule_once(lambda dt: self.show_marks(label), 1)\n            return label\n\n    TestApp().run()\n\n'''\n\n__all__ = ('Label', )\n\nfrom functools import partial\nfrom kivy.clock import Clock\nfrom kivy.uix.widget import Widget\nfrom kivy.core.text import Label as CoreLabel\nfrom kivy.core.text.markup import MarkupLabel as CoreMarkupLabel\nfrom kivy.properties import StringProperty, OptionProperty, \\\n    NumericProperty, BooleanProperty, ReferenceListProperty, \\\n    ListProperty, ObjectProperty, DictProperty\nfrom kivy.utils import get_hex_from_color\n\n\nclass Label(Widget):\n    '''Label class, see module documentation for more information.\n\n    :Events:\n        `on_ref_press`\n            Fired when the user clicks on a word referenced with a\n            ``[ref]`` tag in a text markup.\n    '''\n\n    __events__ = ['on_ref_press']\n\n    _font_properties = ('text', 'font_size', 'font_name', 'bold', 'italic',\n                        'halign', 'valign', 'padding_x', 'padding_y',\n                        'text_size', 'shorten', 'mipmap', 'markup',\n                        'line_height', 'max_lines', 'strip', 'shorten_from',\n                        'split_str', 'unicode_errors')\n\n    def __init__(self, **kwargs):\n        self._trigger_texture = Clock.create_trigger(self.texture_update, -1)\n        super(Label, self).__init__(**kwargs)\n\n        # bind all the property for recreating the texture\n        d = Label._font_properties\n        dkw = {}\n        for x in d:\n            dkw[x] = partial(self._trigger_texture_update, x)\n        self.bind(**dkw)\n\n        self._label = None\n        self._create_label()\n\n        # force the texture creation\n        self._trigger_texture()\n\n    def _create_label(self):\n        # create the core label class according to markup value\n        if self._label is not None:\n            cls = self._label.__class__\n        else:\n            cls = None\n        markup = self.markup\n        if (markup and cls is not CoreMarkupLabel) or \\\n           (not markup and cls is not CoreLabel):\n            # markup have change, we need to change our rendering method.\n            d = Label._font_properties\n            dkw = dict(list(zip(d, [getattr(self, x) for x in d])))\n            if markup:\n                self._label = CoreMarkupLabel(**dkw)\n            else:\n                self._label = CoreLabel(**dkw)\n\n    def _trigger_texture_update(self, name=None, source=None, value=None):\n        # check if the label core class need to be switch to a new one\n        if name == 'markup':\n            self._create_label()\n        if source:\n            if name == 'text':\n                self._label.text = value\n            elif name == 'text_size':\n                self._label.usersize = value\n            elif name == 'font_size':\n                self._label.options[name] = value\n            else:\n                self._label.options[name] = value\n        self._trigger_texture()\n\n    def texture_update(self, *largs):\n        '''Force texture recreation with the current Label properties.\n\n        After this function call, the :attr:`texture` and :attr:`texture_size`\n        will be updated in this order.\n        '''\n        mrkup = self._label.__class__ is CoreMarkupLabel\n        self.texture = None\n\n        if (not self._label.text or (self.halign[-1] == 'y' or self.strip) and\n            not self._label.text.strip()):\n            self.texture_size = (0, 0)\n            if mrkup:\n                self.refs, self._label._refs = {}, {}\n                self.anchors, self._label._anchors = {}, {}\n        else:\n            if mrkup:\n                text = self._label.text\n                # we must strip here, otherwise, if the last line is empty,\n                # markup will retain the last empty line since it only strips\n                # line by line within markup\n                if self.halign[-1] == 'y' or self.strip:\n                    text = text.strip()\n                self._label.text = ''.join(('[color=',\n                                            get_hex_from_color(self.color),\n                                            ']', text, '[/color]'))\n                self._label.refresh()\n                # force the rendering to get the references\n                if self._label.texture:\n                    self._label.texture.bind()\n                self.refs = self._label.refs\n                self.anchors = self._label.anchors\n            else:\n                self._label.refresh()\n            texture = self._label.texture\n            if texture is not None:\n                self.texture = self._label.texture\n                self.texture_size = list(self.texture.size)\n\n    def on_touch_down(self, touch):\n        if super(Label, self).on_touch_down(touch):\n            return True\n        if not len(self.refs):\n            return False\n        tx, ty = touch.pos\n        tx -= self.center_x - self.texture_size[0] / 2.\n        ty -= self.center_y - self.texture_size[1] / 2.\n        ty = self.texture_size[1] - ty\n        for uid, zones in self.refs.items():\n            for zone in zones:\n                x, y, w, h = zone\n                if x <= tx <= w and y <= ty <= h:\n                    self.dispatch('on_ref_press', uid)\n                    return True\n        return False\n\n    def on_ref_press(self, ref):\n        pass\n\n    #\n    # Properties\n    #\n\n    disabled_color = ListProperty([1, 1, 1, .3])\n    '''Text color, in the format (r, g, b, a)\n\n    .. versionadded:: 1.8.0\n\n    :attr:`disabled_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [1, 1, 1, .5].\n    '''\n\n    text = StringProperty('')\n    '''Text of the label.\n\n    Creation of a simple hello world::\n\n        widget = Label(text='Hello world')\n\n    If you want to create the widget with an unicode string, use::\n\n        widget = Label(text=u'My unicode string')\n\n    :attr:`text` is a :class:`~kivy.properties.StringProperty` and defaults to\n    ''.\n    '''\n\n    text_size = ListProperty([None, None])\n    '''By default, the label is not constrained to any bounding box.\n    You can set the size constraint of the label with this property.\n    The text will autoflow into the constrains. So although the font size\n    will not be reduced, the text will be arranged to fit into the box as best\n    as possible, with any text still outside the box clipped.\n\n    This sets and clips :attr:`texture_size` to text_size if not None.\n\n    .. versionadded:: 1.0.4\n\n    For example, whatever your current widget size is, if you want the label to\n    be created in a box with width=200 and unlimited height::\n\n        Label(text='Very big big line', text_size=(200, None))\n\n    .. note::\n\n        This text_size property is the same as the\n        :attr:`~kivy.core.text.Label.usersize` property in the\n        :class:`~kivy.core.text.Label` class. (It is named size= in the\n        constructor.)\n\n    :attr:`text_size` is a :class:`~kivy.properties.ListProperty` and\n    defaults to (None, None), meaning no size restriction by default.\n    '''\n\n    font_name = StringProperty('DroidSans')\n    '''Filename of the font to use. The path can be absolute or relative.\n    Relative paths are resolved by the :func:`~kivy.resources.resource_find`\n    function.\n\n    .. warning::\n\n        Depending of your text provider, the font file can be ignored. However,\n        you can mostly use this without problems.\n\n        If the font used lacks the glyphs for the particular language/symbols\n        you are using, you will see '[]' blank box characters instead of the\n        actual glyphs. The solution is to use a font that has the glyphs you\n        need to display. For example, to display |unicodechar|, use a font such\n        as freesans.ttf that has the glyph.\n\n        .. |unicodechar| image:: images/unicode-char.png\n\n    :attr:`font_name` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'DroidSans'.\n    '''\n\n    font_size = NumericProperty('15sp')\n    '''Font size of the text, in pixels.\n\n    :attr:`font_size` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 15sp.\n    '''\n\n    line_height = NumericProperty(1.0)\n    '''Line Height for the text. e.g. line_height = 2 will cause the spacing\n    between lines to be twice the size.\n\n    :attr:`line_height` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 1.0.\n\n    .. versionadded:: 1.5.0\n    '''\n\n    bold = BooleanProperty(False)\n    '''Indicates use of the bold version of your font.\n\n    .. note::\n\n        Depending of your font, the bold attribute may have no impact on your\n        text rendering.\n\n    :attr:`bold` is a :class:`~kivy.properties.BooleanProperty` and defaults to\n    False.\n    '''\n\n    italic = BooleanProperty(False)\n    '''Indicates use of the italic version of your font.\n\n    .. note::\n\n        Depending of your font, the italic attribute may have no impact on your\n        text rendering.\n\n    :attr:`italic` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    padding_x = NumericProperty(0)\n    '''Horizontal padding of the text inside the widget box.\n\n    :attr:`padding_x` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n\n    .. versionchanged:: 1.9.0\n        `padding_x` has been fixed to work as expected.\n        In the past, the text was padded by the negative of its values.\n    '''\n\n    padding_y = NumericProperty(0)\n    '''Vertical padding of the text inside the widget box.\n\n    :attr:`padding_y` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n\n    .. versionchanged:: 1.9.0\n        `padding_y` has been fixed to work as expected.\n        In the past, the text was padded by the negative of its values.\n    '''\n\n    padding = ReferenceListProperty(padding_x, padding_y)\n    '''Padding of the text in the format (padding_x, padding_y)\n\n    :attr:`padding` is a :class:`~kivy.properties.ReferenceListProperty` of\n    (:attr:`padding_x`, :attr:`padding_y`) properties.\n    '''\n\n    halign = OptionProperty('left', options=['left', 'center', 'right',\n                            'justify'])\n    '''Horizontal alignment of the text.\n\n    :attr:`halign` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to 'left'. Available options are : left, center, right and\n    justify.\n\n    .. warning::\n\n        This doesn't change the position of the text texture of the Label\n        (centered), only the position of the text in this texture. You probably\n        want to bind the size of the Label to the :attr:`texture_size` or set a\n        :attr:`text_size`.\n\n    .. versionchanged:: 1.6.0\n        A new option was added to :attr:`halign`, namely `justify`.\n    '''\n\n    valign = OptionProperty('bottom', options=['bottom', 'middle', 'top'])\n    '''Vertical alignment of the text.\n\n    :attr:`valign` is an :class:`~kivy.properties.OptionProperty` and defaults\n    to 'bottom'. Available options are : bottom, middle and top.\n\n    .. warning::\n\n        This doesn't change the position of the text texture of the Label\n        (centered), only the position of the text within this texture. You\n        probably want to bind the size of the Label to the :attr:`texture_size`\n        or set a :attr:`text_size` to change this behavior.\n    '''\n\n    color = ListProperty([1, 1, 1, 1])\n    '''Text color, in the format (r, g, b, a)\n\n    :attr:`color` is a :class:`~kivy.properties.ListProperty` and defaults to\n    [1, 1, 1, 1].\n    '''\n\n    texture = ObjectProperty(None, allownone=True)\n    '''Texture object of the text.\n    The text is rendered automatically when a property changes. The OpenGL\n    texture created in this operation is stored in this property. You can use\n    this :attr:`texture` for any graphics elements.\n\n    Depending on the texture creation, the value will be a\n    :class:`~kivy.graphics.texture.Texture` or\n    :class:`~kivy.graphics.texture.TextureRegion` object.\n\n    .. warning::\n\n        The :attr:`texture` update is scheduled for the next frame. If you need\n        the texture immediately after changing a property, you have to call\n        the :meth:`texture_update` method before accessing :attr:`texture`::\n\n            l = Label(text='Hello world')\n            # l.texture is good\n            l.font_size = '50sp'\n            # l.texture is not updated yet\n            l.texture_update()\n            # l.texture is good now.\n\n    :attr:`texture` is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    texture_size = ListProperty([0, 0])\n    '''Texture size of the text. The size is determined by the font size and\n    text. If :attr:`text_size` is [None, None], the texture will be the size\n    required to fit the text, otherwise it's clipped to fit :attr:`text_size`.\n\n    When :attr:`text_size` is [None, None], one can bind to texture_size\n    and rescale it proportionally to fit the size of the label in order to\n    make the text fit maximally in the label.\n\n    .. warning::\n\n        The :attr:`texture_size` is set after the :attr:`texture`\n        property. If you listen for changes to :attr:`texture`,\n        :attr:`texture_size` will not be up-to-date in your callback.\n        Bind to :attr:`texture_size` instead.\n    '''\n\n    mipmap = BooleanProperty(False)\n    '''Indicates whether OpenGL mipmapping is applied to the texture or not.\n    Read :ref:`mipmap` for more information.\n\n    .. versionadded:: 1.0.7\n\n    :attr:`mipmap` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    shorten = BooleanProperty(False)\n    '''\n    Indicates whether the label should attempt to shorten its textual contents\n    as much as possible if a :attr:`text_size` is given. Setting this to True\n    without an appropriately set :attr:`text_size` will lead to unexpected\n    results.\n\n    :attr:`shorten_from` and :attr:`split_str` control the direction from\n    which the :attr:`text` is split, as well as where in the :attr:`text` we\n    are allowed to split.\n\n    :attr:`shorten` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    shorten_from = OptionProperty('center', options=['left', 'center',\n                                                     'right'])\n    '''The side from which we should shorten the text from, can be left,\n    right, or center.\n\n    For example, if left, the ellipsis will appear towards the left side and we\n    will display as much text starting from the right as possible. Similar to\n    :attr:`shorten`, this option only applies when :attr:`text_size` [0] is\n    not None, In this case, the string is shortened to fit within the specified\n    width.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`shorten_from` is a :class:`~kivy.properties.OptionProperty` and\n    defaults to `center`.\n    '''\n\n    split_str = StringProperty('')\n    '''The string used to split the :attr:`text` while shortening the string\n    when :attr:`shorten` is True.\n\n    For example, if it's a space, the string will be broken into words and as\n    many whole words that can fit into a single line will be displayed. If\n    :attr:`shorten_from` is the empty string, `''`, we split on every character\n    fitting as much text as possible into the line.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`split_str` is a :class:`~kivy.properties.StringProperty` and\n    defaults to `''` (the empty string).\n    '''\n\n    unicode_errors = OptionProperty(\n        'replace', options=('strict', 'replace', 'ignore'))\n    '''How to handle unicode decode errors. Can be `'strict'`, `'replace'` or\n    `'ignore'`.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`unicode_errors` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to `'replace'`.\n    '''\n\n    markup = BooleanProperty(False)\n    '''\n    .. versionadded:: 1.1.0\n\n    If True, the text will be rendered using the\n    :class:`~kivy.core.text.markup.MarkupLabel`: you can change the\n    style of the text using tags. Check the\n    :doc:`api-kivy.core.text.markup` documentation for more information.\n\n    :attr:`markup` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    refs = DictProperty({})\n    '''\n    .. versionadded:: 1.1.0\n\n    List of ``[ref=xxx]`` markup items in the text with the bounding box of\n    all the words contained in a ref, available only after rendering.\n\n    For example, if you wrote::\n\n        Check out my [ref=hello]link[/ref]\n\n    The refs will be set with::\n\n        {'hello': ((64, 0, 78, 16), )}\n\n    The references marked \"hello\" have a bounding box at (x1, y1, x2, y2).\n    These co-ordinates are relative to the top left corner of the text, with\n    the y value increasing downwards. You can define multiple refs with the same\n    name: each occurence will be added as another (x1, y1, x2, y2) tuple to\n    this list.\n\n    The current Label implementation uses these references if they exist in\n    your markup text, automatically doing the collision with the touch and\n    dispatching an `on_ref_press` event.\n\n    You can bind a ref event like this::\n\n        def print_it(instance, value):\n            print('User click on', value)\n        widget = Label(text='Hello [ref=world]World[/ref]', markup=True)\n        widget.on_ref_press(print_it)\n\n    .. note::\n\n        This works only with markup text. You need :attr:`markup` set to\n        True.\n    '''\n\n    anchors = DictProperty({})\n    '''\n    .. versionadded:: 1.1.0\n\n    Position of all the ``[anchor=xxx]`` markup in the text.\n    These co-ordinates are relative to the top left corner of the text, with\n    the y value increasing downwards. Anchors names should be unique and only\n    the first occurence of any duplicate anchors will be recorded.\n\n\n    You can place anchors in your markup text as follows::\n\n        text = \"\"\"\n            [anchor=title1][size=24]This is my Big title.[/size]\n            [anchor=content]Hello world\n        \"\"\"\n\n    Then, all the ``[anchor=]`` references will be removed and you'll get all\n    the anchor positions in this property (only after rendering)::\n\n        >>> widget = Label(text=text, markup=True)\n        >>> widget.texture_update()\n        >>> widget.anchors\n        {\"content\": (20, 32), \"title1\": (20, 16)}\n\n    .. note::\n\n        This works only with markup text. You need :attr:`markup` set to\n        True.\n\n    '''\n\n    max_lines = NumericProperty(0)\n    '''Maximum number of lines to use, defaults to 0, which means unlimited.\n    Please note that :attr:`shorten` take over this property. (with\n    shorten, the text is always one line.)\n\n    .. versionadded:: 1.8.0\n\n    :attr:`max_lines` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    strip = BooleanProperty(False)\n    '''Whether leading and trailing spaces and newlines should be stripped from\n    each displayed line. If True, every line will start at the right or left\n    edge, depending on :attr:`halign`. If :attr:`halign` is `justify` it is\n    implicitly True.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`strip` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/layout.py",
    "content": "'''\nLayout\n======\n\nLayouts are used to calculate and assign widget positions.\n\nThe :class:`Layout` class itself cannot be used directly.\nYou should use one of the following layout classes:\n\n- Anchor layout: :class:`kivy.uix.anchorlayout.AnchorLayout`\n- Box layout: :class:`kivy.uix.boxlayout.BoxLayout`\n- Float layout: :class:`kivy.uix.floatlayout.FloatLayout`\n- Grid layout: :class:`kivy.uix.gridlayout.GridLayout`\n- Page Layout: :class:`kivy.uix.pagelayout.PageLayout`\n- Relative layout: :class:`kivy.uix.relativelayout.RelativeLayout`\n- Scatter layout: :class:`kivy.uix.scatterlayout.ScatterLayout`\n- Stack layout: :class:`kivy.uix.stacklayout.StackLayout`\n\n\nUnderstanding the `size_hint` Property in `Widget`\n--------------------------------------------------\n\nThe :attr:`~kivy.uix.Widget.size_hint` is a tuple of values used by\nlayouts to manage the sizes of their children. It indicates the size\nrelative to the layout's size instead of an absolute size (in\npixels/points/cm/etc). The format is::\n\n    widget.size_hint = (width_percent, height_percent)\n\nThe percent is specified as a floating point number in the range 0-1. For\nexample, 0.5 is 50%, 1 is 100%.\n\nIf you want a widget's width to be half of the parent's width and the\nheight to be identical to the parent's height, you would do::\n\n    widget.size_hint = (0.5, 1.0)\n\nIf you don't want to use a size_hint for either the width or height, set the\nvalue to None. For example, to make a widget that is 250px wide and 30%\nof the parent's height, do::\n\n    widget.size_hint = (None, 0.3)\n    widget.width = 250\n\n.. versionchanged:: 1.4.1\n    The `reposition_child` internal method (made public by mistake) has\n    been removed.\n\n'''\n\n__all__ = ('Layout', )\n\nfrom kivy.clock import Clock\nfrom kivy.uix.widget import Widget\n\n\nclass Layout(Widget):\n    '''Layout interface class, used to implement every layout. See module\n    documentation for more information.\n    '''\n\n    def __init__(self, **kwargs):\n        if self.__class__ == Layout:\n            raise Exception('The Layout class cannot be used.')\n        self._trigger_layout = Clock.create_trigger(self.do_layout, -1)\n        super(Layout, self).__init__(**kwargs)\n\n    def do_layout(self, *largs):\n        '''This function is called when a layout is needed by a trigger.\n        If you are writing a new Layout subclass, don't call this function\n        directly but use :meth:`_trigger_layout` instead.\n\n        .. versionadded:: 1.0.8\n        '''\n        pass\n\n    def add_widget(self, widget, index=0):\n        widget.bind(\n            size=self._trigger_layout,\n            size_hint=self._trigger_layout)\n        return super(Layout, self).add_widget(widget, index)\n\n    def remove_widget(self, widget):\n        widget.unbind(\n            size=self._trigger_layout,\n            size_hint=self._trigger_layout)\n        return super(Layout, self).remove_widget(widget)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/listview.py",
    "content": "'''\nList View\n===========\n\n.. versionadded:: 1.5\n\n.. warning::\n\n    This code is still experimental, and its API is subject to change in a\n    future version.\n\nThe :class:`~kivy.uix.listview.ListView` implements an\n:class:`~kivy.uix.abstractview.AbstractView` as\na vertical, scrollable,pannable list clipped to the scrollview's bounding box\nand contains list item view instances.\n\nThe :class:`AbstractView` has one property: :class:`~kivy.adapters.adapter`.\nThe adapter can be one of the following: a\n:class:`~kivy.adapters.simplelistadapter.SimpleListAdapter`, a\n:class:`~kivy.adapters.listadapter.ListAdapter` or a\n:class:`~kivy.adapters.dictadapter.DictAdapter`. The :class:`Adapter` can make\nuse of :mod:`~kivy.adapters.args_converters` to prepare you data for passing\ninto the constructor for each item view instantiation.\n\nFor an overview of how all these components fit together, please see the\n:mod:`~kivy.adapters` module documentation.\n\nIntroduction\n------------\n\nLists are central parts of many software projects. Kivy's approach to lists\nincludes providing solutions for simple lists, along with a substantial\nframework for building lists of moderate to advanced complexity. For a new\nuser, it can be difficult to ramp up from simple to advanced. For\nthis reason, Kivy provides an extensive set of examples (with the Kivy package)\nthat you may wish to run first, to get a taste of the range of functionality\noffered. You can tell from the names of the examples that they illustrate the\n\"ramping up\" from simple to advanced:\n\n\n    * `kivy/examples/widgets/lists/list_simple.py <https://github.com/\\\nkivy/kivy/tree/master/examples/widgets/lists/list_simple.py>`_\n    * `kivy/examples/widgets/lists/list_simple_in_kv.py <https://github.com/\\\nkivy/kivy/tree/master/examples/widgets/lists/list_simple_in_kv.py>`_\n    * `kivy/examples/widgets/lists/list_simple_in_kv_2.py <https://github.com/\\\nkivy/kivy/tree/master/examples/widgets/lists/list_simple_in_kv_2.py>`_\n    * `kivy/examples/widgets/lists/list_master_detail.py <https://github.com/\\\nkivy/kivy/tree/master/examples/widgets/lists/list_master_detail.py>`_\n    * `kivy/examples/widgets/lists/list_two_up.py <https://github.com/\\\nkivy/kivy/tree/master/examples/widgets/lists/list_two_up.py>`_\n    * `kivy/examples/widgets/lists/list_kv.py <https://github.com/\\\nkivy/kivy/tree/master/examples/widgets/lists/list_kv.py>`_\n    * `kivy/examples/widgets/lists/list_composite.py <https://github.com/\\\nkivy/kivy/tree/master/examples/widgets/lists/list_composite.py>`_\n    * `kivy/examples/widgets/lists/list_cascade.py <https://github.com/\\\nkivy/kivy/tree/master/examples/widgets/lists/list_cascade.py>`_\n    * `kivy/examples/widgets/lists/list_cascade_dict.py <https://github.com/\\\nkivy/kivy/tree/master/examples/widgets/lists/list_cascade_dict.py>`_\n    * `kivy/examples/widgets/lists/list_cascade_images.py <https://github.com/\\\nkivy/kivy/tree/master/examples/widgets/lists/list_cascade_images.py>`_\n    * `kivy/examples/widgets/lists/list_ops.py <https://github.com/\\\nkivy/kivy/tree/master/examples/widgets/lists/list_ops.py>`_\n\nMany of the examples feature selection, some restricting selection to single\nselection, where only one item at at time can be selected, and others allowing\nmultiple item selection. Many of the examples illustrate how selection in one\nlist can be connected to actions and selections in another view or another list.\n\nFind your own way of reading the documentation here, examining the source code\nfor the example apps and running the examples. Some may prefer to read the\ndocumentation through first, others may want to run the examples and view their\ncode. No matter what you do, going back and forth will likely be needed.\n\nBasic Example\n-------------\n\nIn its simplest form, we make a listview with 100 items::\n\n    from kivy.uix.listview import ListView\n    from kivy.base import runTouchApp\n\n\n    class MainView(ListView):\n        def __init__(self, **kwargs):\n            super(MainView, self).__init__(\n                item_strings=[str(index) for index in range(100)])\n\n    if __name__ == '__main__':\n        runTouchApp(MainView())\n\nOr, we could declare the listview using the kv language::\n\n    from kivy.uix.boxlayout import BoxLayout\n    from kivy.lang import Builder\n    from kivy.base import runTouchApp\n\n    Builder.load_string(\"\"\"\n    <MyListView>:\n        ListView:\n            item_strings: [str(index) for index in range(100)]\n    \"\"\")\n\n\n    class MyListView(BoxLayout):\n        pass\n\n    if __name__ == '__main__':\n        runTouchApp(MyListView())\n\nUsing an Adapter\n-------------------\n\nBehind the scenes, the basic example above uses the\n:class:`~kivy.adapters.simplelistadapter.SimpleListAdapter`. When the\nconstructor for the :class:`~kivy.uix.listview.ListView` sees that only a list\nof\nstrings is provided as an argument (called item_strings), it creates a\n:class:`~kivy.adapters.simplelistadapter.SimpleListAdapter` using the\nlist of strings.\n\n\"Simple\" in :class:`~kivy.adapters.simplelistadapter.SimpleListAdapter` means\n*without selection support*. It is a scrollable list of items that does not\nrespond to touch events.\n\nTo use a :class:`SimpleListAdaper` explicitly when creating a ListView instance,\ndo::\n\n    simple_list_adapter = SimpleListAdapter(\n            data=[\"Item #{0}\".format(i) for i in range(100)],\n            cls=Label)\n\n    list_view = ListView(adapter=simple_list_adapter)\n\nThe instance of :class:`~kivy.adapters.simplelistadapter.SimpleListAdapter` has\na required data argument which contains data items to use for instantiating\n:class:`~kivy.uix.label.Label` views for the list view (note the cls=Label\nargument). The data items are strings. Each item string is set by the\n:class:`~kivy.adapters.simplelistadapter.SimpleListAdapter` as the *text*\nargument for each Label instantiation.\n\nYou can declare a ListView with an adapter in a kv file with special attention\ngiven to the way longer python blocks are indented::\n\n    from kivy.uix.boxlayout import BoxLayout\n    from kivy.base import runTouchApp\n    from kivy.lang import Builder\n\n    # Note the special nature of indentation in the adapter declaration, where\n    # the adapter: is on one line, then the value side must be given at one\n    # level of indentation.\n\n    Builder.load_string(\"\"\"\n    #:import label kivy.uix.label\n    #:import sla kivy.adapters.simplelistadapter\n\n    <MyListView>:\n        ListView:\n            adapter:\n                sla.SimpleListAdapter(\n                data=[\"Item #{0}\".format(i) for i in range(100)],\n                cls=label.Label)\n    \"\"\")\n\n\n    class MyListView(BoxLayout):\n        pass\n\n    if __name__ == '__main__':\n        runTouchApp(MyListView())\n\nListAdapter and DictAdapter\n---------------------------\n\nFor most use cases, your data is more complex than a simple list of strings.\nSelection functionality is also often needed.\nThe :class:`~kivy.adapters.listadapter.ListAdapter` and\n:class:`~kivy.adapters.dictadapter.DictAdapter` cover these more elaborate\nneeds.\n\nThe :class:`~kivy.adapters.listadapter.ListAdapter` is the base class for\n:class:`~kivy.adapters.dictadapter.DictAdapter`, so we can start with it.\n\nRefer to the :class:`~kivy.adapters.listadapter.ListAdapter` docs for details,\nbut here is a synopses of its arguments:\n\n* :attr:`~kivy.adapters.adapter.Adapter.data`:\n  strings, class instances, dicts, etc. that form the base data\n  for instantiating views.\n\n* :attr:`~kivy.adapters.adapter.Adapter.cls`:\n  a Kivy view that is to be instantiated for each list item. There\n  are several built-in types available, including ListItemLabel and\n  ListItemButton, or you can make your own class that mixes in the\n  required :class:`~kivy.uix.listview.SelectableView`.\n\n* :attr:`~kivy.adapters.adapter.Adapter.template`:\n  the name of a Kivy language (kv) template that defines the\n  Kivy view for each list item.\n\n.. note::\n\n    Pick only one, cls or template, to provide as an argument.\n\n* :attr:`~kivy.adapters.args_converters`: a function that takes a data item\n  object as input and\n  uses it to build and return an args dict, ready\n  to be used in a call to instantiate item views using the item view cls\n  or template. In the case of cls, the args dict becomes a kwargs constructor\n  argument. For a template, it is treated as a context\n  (ctx) but is essentially similar in form to the kwargs usage.\n\n* :attr:`~kivy.adapters.listadapter.ListAdapter.selection_mode`:\n  a string with the value 'single',\n  'multiple' or other.\n\n* :attr:`~kivy.adapters.listadapter.ListAdapter.allow_empty_selection`:\n  a boolean, which if False (the default), forces\n  there to always be a selection if there is data\n  available. If True, selection happens only as a\n  result of user action.\n\nIn narrative, we can summarize as follows:\n\n    A listview's adapter takes data items and uses an args_converter\n    function to transform them into arguments for creating list item view\n    instances, using either a cls or a kv template.\n\nIn a graphic, a summary of the relationship between a listview and its\ncomponents can be summarized as follows:\n\n.. image:: images/adapters.png\n\nPlease refer to the :mod:`~kivy.adapters` documentation for more details.\n\nA :class:`~kivy.adapters.dictadapter.DictAdapter` has the same arguments and\nrequirements as a :class:`~kivy.adapters.listadapter.ListAdapter` except for two\nthings:\n\n1) There is an additional argument, sorted_keys, which must meet the\n   requirements of normal python dictionary keys.\n\n2) The data argument is, as you would expect, a dict. Keys in the dict\n   must include the keys in the sorted_keys argument, but they may form a\n   superset of the keys in sorted_keys. Values may be strings, class\n   instances, dicts, etc. (The args_converter uses it accordingly).\n\nUsing an Args Converter\n-----------------------\n\nA :class:`~kivy.uix.listview.ListView` allows use of built-in list item views,\nsuch as :class:`~kivy.uix.listview.ListItemButton`, your own custom item view\nclass or a custom kv template. Whichever type of list item view is used, an\n:doc:`args_converter <api-kivy.adapters.args_converters>` function is needed to\nprepare, per list data item, kwargs for the cls or the ctx for the template.\n\n.. note::\n\n    Only the ListItemLabel, ListItemButton or custom classes like them (and\n    not the simple Label or Button classes) are to be used in the listview\n    system.\n\n.. warning::\n\n    ListItemButton inherits the `background_normal` and `background_down`\n    properties from the Button widget, so the `selected_color` and\n    `deselected_color` are not represented faithfully by default.\n\nHere is an args_converter for use with the built-in\n:class:`~kivy.uix.listview.ListItemButton` specified as a normal Python\nfunction::\n\n    def args_converter(row_index, an_obj):\n        return {'text': an_obj.text,\n                'size_hint_y': None,\n                'height': 25}\n\nand as a lambda::\n\n    args_converter = lambda row_index, an_obj: {'text': an_obj.text,\n                                                'size_hint_y': None,\n                                                'height': 25}\n\nIn the args converter example above, the data item is assumed to be an object\n(class instance), hence the reference an_obj.text.\n\nHere is an example of an args converter that works with list data items that\nare dicts::\n\n    args_converter = lambda row_index, obj: {'text': obj['text'],\n                                             'size_hint_y': None,\n                                             'height': 25}\n\nSo, it is the responsibility of the developer to code the args_converter\naccording to the data at hand. The row_index argument can be useful in some\ncases, such as when custom labels are needed.\n\nAn Example ListView\n-------------------\n\nNow, to some example code::\n\n    from kivy.adapters.listadapter import ListAdapter\n    from kivy.uix.listview import ListItemButton, ListView\n\n    data = [{'text': str(i), 'is_selected': False} for i in range(100)]\n\n    args_converter = lambda row_index, rec: {'text': rec['text'],\n                                             'size_hint_y': None,\n                                             'height': 25}\n\n    list_adapter = ListAdapter(data=data,\n                               args_converter=args_converter,\n                               cls=ListItemButton,\n                               selection_mode='single',\n                               allow_empty_selection=False)\n\n    list_view = ListView(adapter=list_adapter)\n\nThis listview will show 100 buttons with text of 0 to 100. The args_converter\nfunction converts the dict items in the data and instantiates ListItemButton\nviews by passing these converted items into it's constructor. The\nlistview will only allow single selection and the first item will already be\nselected as allow_empty_selection is False. For a complete discussion on these\narguments, please see the :class:`~kivy.adapters.listadapter.ListAdapter`\ndocumentation.\n\nThe :class:`~kivy.uix.listview.ListItemLabel` works in much the same way as the\n:class:`~kivy.uix.listview.ListItemButton`.\n\nUsing a Custom Item View Class\n------------------------------\n\nThe data used in an adapter can be any of the normal Python types or custom\nclasses, as shown below. It is up to the programmer to assure that the\nargs_converter performs the appropriate conversions.\n\nHere we make a simple DataItem class that has the required text and\nis_selected properties::\n\n    from kivy.uix.listview import ListItemButton\n    from kivy.adapters.listadapter import ListAdapter\n\n\n    class DataItem(object):\n        def __init__(self, text='', is_selected=False):\n            self.text = text\n            self.is_selected = is_selected\n\n    data_items = [DataItem(text='cat'),\n                  DataItem(text='dog'),\n                  DataItem(text='frog')]\n\n    list_item_args_converter = lambda row_index, obj: {'text': obj.text,\n                                                       'size_hint_y': None,\n                                                       'height': 25}\n\n    list_adapter = ListAdapter(data=data_items,\n                               args_converter=list_item_args_converter,\n                               propagate_selection_to_data=True,\n                               cls=ListItemButton)\n\n    list_view = ListView(adapter=list_adapter)\n\nThe data is passed to the :class:`~kivy.adapters.listadapter.ListAdapter` along\nwith an args_converter function. The propagation setting means that\nthe is_selected property for each data item will be set and kept in sync with\nthe list item views. This setting should be set to True if you wish to\ninitialize the view with item views already selected.\n\nYou may also use the provided :class:`~kivy.adapters.models.SelectableDataItem`\nmixin to make a custom class. Instead of the \"manually-constructed\" DataItem\nclass above, we could do::\n\n    from kivy.adapters.models import SelectableDataItem\n\n    class DataItem(SelectableDataItem):\n        # Add properties here.\n        pass\n\n:class:`~kivy.adapters.models.SelectableDataItem` is a simple mixin class that\nhas an is_selected property.\n\nUsing an Item View Template\n---------------------------\n\n:class:`~kivy.uix.listview.SelectableView` is another simple mixin class that\nhas required properties for a list item: text, and is_selected. To make your\nown template, mix it in as follows::\n\n    from kivy.lang import Builder\n\n    Builder.load_string(\"\"\"\n    [CustomListItem@SelectableView+BoxLayout]:\n        size_hint_y: ctx.size_hint_y\n        height: ctx.height\n        ListItemButton:\n            text: ctx.text\n            is_selected: ctx.is_selected\n    \"\"\")\n\nA class called CustomListItem can then be instantiated for each list item. Note\nthat it subclasses a :class:`~kivy.uix.boxlayout.BoxLayout` and is thus a type\nof :mod:`~kivy.uix.layout`. It contains a\n:class:`~kivy.uix.listview.ListItemButton` instance.\n\nUsing the power of the Kivy language (kv), you can easily build composite list\nitems: in addition to ListItemButton, you could have a ListItemLabel or a\ncustom class you have defined and registered via the\n:class:`~kivy.factory.Factory`.\n\nAn args_converter needs to be constructed that goes along with such a kv\ntemplate. For example, to use the kv template above::\n\n    list_item_args_converter = \\\\\n            lambda row_index, rec: {'text': rec['text'],\n                                    'is_selected': rec['is_selected'],\n                                    'size_hint_y': None,\n                                    'height': 25}\n    integers_dict = \\\\\n        { str(i): {'text': str(i), 'is_selected': False} for i in range(100)}\n\n    dict_adapter = DictAdapter(sorted_keys=[str(i) for i in range(100)],\n                               data=integers_dict,\n                               args_converter=list_item_args_converter,\n                               template='CustomListItem')\n\n    list_view = ListView(adapter=dict_adapter)\n\nA dict adapter is created with 1..100 integer strings as sorted_keys, and an\nintegers_dict as data. integers_dict has the integer strings as keys and dicts\nwith text and is_selected properties. The CustomListItem defined above in the\nBuilder.load_string() call is set as the kv template for the list item views.\nThe list_item_args_converter lambda function will take each dict in\nintegers_dict and will return an args dict, ready for passing as the context\n(ctx) for the template.\n\nUsing CompositeListItem\n-----------------------\n\nThe class :class:`~kivy.uix.listview.CompositeListItem` is another option for\nbuilding advanced composite list items. The kv language approach has its\nadvantages, but here we build a composite list view using a plain Python::\n\n    args_converter = lambda row_index, rec: \\\\\n        {'text': rec['text'],\n        'size_hint_y': None,\n        'height': 25,\n        'cls_dicts': [{'cls': ListItemButton,\n                        'kwargs': {'text': rec['text']}},\n                    {'cls': ListItemLabel,\n                        'kwargs': {'text': \"Middle-{0}\".format(rec['text']),\n                                'is_representing_cls': True}},\n                    {'cls': ListItemButton,\n                        'kwargs': {'text': rec['text']}}]}\n\n    item_strings = [\"{0}\".format(index) for index in range(100)]\n\n    integers_dict = \\\\\n        {str(i): {'text': str(i), 'is_selected': False} for i in range(100)}\n\n    dict_adapter = DictAdapter(sorted_keys=item_strings,\n                               data=integers_dict,\n                               args_converter=args_converter,\n                               selection_mode='single',\n                               allow_empty_selection=False,\n                               cls=CompositeListItem)\n\n    list_view = ListView(adapter=dict_adapter)\n\nThe args_converter is somewhat complicated, so we should go through the\ndetails. Observe in the :class:`~kivy.adapters.dictadapter.DictAdapter`\ninstantiation that :class:`~kivy.uix.listview.CompositeListItem` instance is\nset as the cls to be instantiated for each list item component. The\nargs_converter will\nmake args dicts for this cls. In the args_converter, the first three items,\ntext, size_hint_y, and height, are arguments for the CompositeListItem itself.\nAfter that you see a cls_dicts list that contains argument sets for each of the\nmember widgets for this composite: 2\n:class:`ListItemButtons <kivy.uix.listview.ListItemButton>` and a\n:class:`~kivy.uix.listview.ListItemLabel`. This is a similar approach to\nusing a kv template described above.\n\nFor details on how :class:`~kivy.uix.listview.CompositeListItem` works,\nexamine the code, looking for how parsing of the cls_dicts list and kwargs\nprocessing is done.\n\nUses for Selection\n------------------\n\nWhat can we do with selection? Combining selection with the system of bindings\nin Kivy, we can build a wide range of user interface designs.\n\nWe could make data items that contain the names of dog breeds, and connect\nthe selection of dog breed to the display of details in another view, which\nwould update automatically on selection. This is done via a binding to the\n:attr:`~kivy.adapters.listadapter.ListAdapter.on_selection_change` event::\n\n    list_adapter.bind(on_selection_change=callback_function)\n\nwhere callback_function() gets passed the adapter as an argument and does\nwhatever is needed for the update. See the\nexample called list_master_detail.py, and imagine that the list on the left\ncould be a list of dog breeds, and the detail view on the right could show\ndetails for a selected dog breed.\n\nIn another example, we could set the selection_mode of a listview to\n'multiple', and load it with a list of answers to a multiple-choice question.\nThe question could have several correct answers. A color swatch view could be\nbound to selection change, as above, so that it turns green as soon as the\ncorrect choices are made, unless the number of touches exeeds a limit, then the\nanswer session could be terminated. See the examples that feature thumbnail\nimages to get some ideas, e.g., list_cascade_dict.py.\n\nIn a more involved example, we could chain together three listviews, where\nselection in the first controls the items shown in the second, and selection in\nthe second controls the items shown in the third. If allow_empty_selection were\nset to False for these listviews, a dynamic system of selection \"cascading\"\nfrom one list to the next, would result.\n\nThere are so many ways that listviews and Kivy bindings functionality can be\nused, that we have only scratched the surface here. For on-disk examples, see::\n\n    kivy/examples/widgets/lists/list_*.py\n\nSeveral examples show the \"cascading\" behavior described above. Others\ndemonstrate the use of kv templates and composite list views.\n\n'''\n\n__all__ = ('SelectableView', 'ListItemButton', 'ListItemLabel',\n           'CompositeListItem', 'ListView', )\n\nfrom kivy.event import EventDispatcher\nfrom kivy.clock import Clock\nfrom kivy.compat import PY2\nfrom kivy.uix.widget import Widget\nfrom kivy.uix.button import Button\nfrom kivy.uix.label import Label\nfrom kivy.uix.boxlayout import BoxLayout\nfrom kivy.adapters.simplelistadapter import SimpleListAdapter\nfrom kivy.uix.abstractview import AbstractView\nfrom kivy.properties import ObjectProperty, DictProperty, \\\n        NumericProperty, ListProperty, BooleanProperty\nfrom kivy.lang import Builder\nfrom math import ceil, floor\n\n\nclass SelectableView(object):\n    '''The :class:`~kivy.uix.listview.SelectableView` mixin is used to design\n    list items and other classes that are to be instantiated by an adapter for\n    use in a listview. The :class:`~kivy.adapters.listadapter.ListAdapter`\n    and :class:`~kivy.adapters.dictadapter.DictAdapter` adapters are\n    selection-enabled. select() and deselect() are to be overridden with\n    display code to mark items as selected or not, if desired.\n    '''\n\n    index = NumericProperty(-1)\n    '''The index into the underlying data list or the data item this view\n    represents.\n\n    :attr:`index` is a :class:`~kivy.properties.NumericProperty`, default\n    to -1.\n    '''\n\n    is_selected = BooleanProperty(False)\n    '''A SelectableView instance carries this property, which should be kept\n    in sync with the equivalent property in the data item it represents.\n\n    :attr:`is_selected` is a :class:`~kivy.properties.BooleanProperty`, default\n    to False.\n    '''\n\n    def __init__(self, **kwargs):\n        super(SelectableView, self).__init__(**kwargs)\n\n    def select(self, *args):\n        '''The list item is responsible for updating the display for\n        being selected, if desired.\n        '''\n        self.is_selected = True\n\n    def deselect(self, *args):\n        '''The list item is responsible for updating the display for\n        being unselected, if desired.\n        '''\n        self.is_selected = False\n\n\nclass ListItemReprMixin(Label):\n    if PY2:\n        def __repr__(self):\n            text = self.text.encode('utf-8') if isinstance(self.text, unicode) \\\n                else self.text\n            return '<%s text=%s>' % (self.__class__.__name__, text)\n    else:\n        def __repr__(self):\n            return '<%s text=%s>' % (self.__class__.__name__, self.text)\n\n\nclass ListItemButton(ListItemReprMixin, SelectableView, Button):\n    ''':class:`~kivy.uix.listview.ListItemButton` mixes\n    :class:`~kivy.uix.listview.SelectableView` with\n    :class:`~kivy.uix.button.Button` to produce a button suitable for use in\n    :class:`~kivy.uix.listview.ListView`.\n    '''\n\n    selected_color = ListProperty([1., 0., 0., 1])\n    '''\n    :attr:`selected_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [1., 0., 0., 1].\n    '''\n\n    deselected_color = ListProperty([0., 1., 0., 1])\n    '''\n    :attr:`deselected_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [0., 1., 0., 1].\n    '''\n\n    def __init__(self, **kwargs):\n        super(ListItemButton, self).__init__(**kwargs)\n\n        # Set Button bg color to be deselected_color.\n        self.background_color = self.deselected_color\n\n    def select(self, *args):\n        self.background_color = self.selected_color\n        if isinstance(self.parent, CompositeListItem):\n            self.parent.select_from_child(self, *args)\n\n    def deselect(self, *args):\n        self.background_color = self.deselected_color\n        if isinstance(self.parent, CompositeListItem):\n            self.parent.deselect_from_child(self, *args)\n\n    def select_from_composite(self, *args):\n        self.background_color = self.selected_color\n\n    def deselect_from_composite(self, *args):\n        self.background_color = self.deselected_color\n\n\n# [TODO] Why does this mix in SelectableView -- that makes it work like\n#        button, which is redundant.\n\nclass ListItemLabel(ListItemReprMixin, SelectableView, Label):\n    ''':class:`~kivy.uix.listview.ListItemLabel` mixes\n    :class:`~kivy.uix.listview.SelectableView` with\n    :class:`~kivy.uix.label.Label` to produce a label suitable for use in\n    :class:`~kivy.uix.listview.ListView`.\n    '''\n\n    def __init__(self, **kwargs):\n        super(ListItemLabel, self).__init__(**kwargs)\n\n    def select(self, *args):\n        self.bold = True\n        if isinstance(self.parent, CompositeListItem):\n            self.parent.select_from_child(self, *args)\n\n    def deselect(self, *args):\n        self.bold = False\n        if isinstance(self.parent, CompositeListItem):\n            self.parent.deselect_from_child(self, *args)\n\n    def select_from_composite(self, *args):\n        self.bold = True\n\n    def deselect_from_composite(self, *args):\n        self.bold = False\n\n\nclass CompositeListItem(SelectableView, BoxLayout):\n    ''':class:`~kivy.uix.listview.CompositeListItem` mixes\n    :class:`~kivy.uix.listview.SelectableView` with :class:`BoxLayout` for a\n    generic container-style list item, to be used in\n    :class:`~kivy.uix.listview.ListView`.\n    '''\n\n    background_color = ListProperty([1, 1, 1, 1])\n    '''ListItem sublasses Button, which has background_color, but\n    for a composite list item, we must add this property.\n\n    :attr:`background_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [1, 1, 1, 1].\n    '''\n\n    selected_color = ListProperty([1., 0., 0., 1])\n    '''\n    :attr:`selected_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [1., 0., 0., 1].\n    '''\n\n    deselected_color = ListProperty([.33, .33, .33, 1])\n    '''\n    :attr:`deselected_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [.33, .33, .33, 1].\n    '''\n\n    representing_cls = ObjectProperty(None)\n    '''Which component view class, if any, should represent for the\n    composite list item in __repr__()?\n\n    :attr:`representing_cls` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    def __init__(self, **kwargs):\n        super(CompositeListItem, self).__init__(**kwargs)\n\n        # Example data:\n        #\n        #    'cls_dicts': [{'cls': ListItemButton,\n        #                   'kwargs': {'text': \"Left\"}},\n        #                   'cls': ListItemLabel,\n        #                   'kwargs': {'text': \"Middle\",\n        #                              'is_representing_cls': True}},\n        #                   'cls': ListItemButton,\n        #                   'kwargs': {'text': \"Right\"}]\n\n        # There is an index to the data item this composite list item view\n        # represents. Get it from kwargs and pass it along to children in the\n        # loop below.\n        index = kwargs['index']\n\n        for cls_dict in kwargs['cls_dicts']:\n            cls = cls_dict['cls']\n            cls_kwargs = cls_dict.get('kwargs', None)\n\n            if cls_kwargs:\n                cls_kwargs['index'] = index\n\n                if 'selection_target' not in cls_kwargs:\n                    cls_kwargs['selection_target'] = self\n\n                if 'text' not in cls_kwargs:\n                    cls_kwargs['text'] = kwargs['text']\n\n                if 'is_representing_cls' in cls_kwargs:\n                    self.representing_cls = cls\n\n                self.add_widget(cls(**cls_kwargs))\n            else:\n                cls_kwargs = {}\n                cls_kwargs['index'] = index\n                if 'text' in kwargs:\n                    cls_kwargs['text'] = kwargs['text']\n                self.add_widget(cls(**cls_kwargs))\n\n    def select(self, *args):\n        self.background_color = self.selected_color\n\n    def deselect(self, *args):\n        self.background_color = self.deselected_color\n\n    def select_from_child(self, child, *args):\n        for c in self.children:\n            if c is not child:\n                c.select_from_composite(*args)\n\n    def deselect_from_child(self, child, *args):\n        for c in self.children:\n            if c is not child:\n                c.deselect_from_composite(*args)\n\n    def __repr__(self):\n        if self.representing_cls is not None:\n            return '<%r>, representing <%s>' % (\n                self.representing_cls, self.__class__.__name__)\n        else:\n            return '<%s>' % (self.__class__.__name__)\n\n\nBuilder.load_string('''\n<ListView>:\n    container: container\n    ScrollView:\n        pos: root.pos\n        on_scroll_y: root._scroll(args[1])\n        do_scroll_x: False\n        GridLayout:\n            cols: 1\n            id: container\n            size_hint_y: None\n''')\n\n\nclass ListView(AbstractView, EventDispatcher):\n    ''':class:`~kivy.uix.listview.ListView` is a primary high-level widget,\n    handling the common task of presenting items in a scrolling list.\n    Flexibility is afforded by use of a variety of adapters to interface with\n    data.\n\n    The adapter property comes via the mixed in\n    :class:`~kivy.uix.abstractview.AbstractView` class.\n\n    :class:`~kivy.uix.listview.ListView` also subclasses\n    :class:`EventDispatcher` for scrolling. The event *on_scroll_complete* is\n    used in refreshing the main view.\n\n    For a simple list of string items, without selection, use\n    :class:`~kivy.adapters.simplelistadapter.SimpleListAdapter`. For list items\n    that respond to selection, ranging from simple items to advanced\n    composites, use :class:`~kivy.adapters.listadapter.ListAdapter`. For an\n    alternate powerful adapter, use\n    :class:`~kivy.adapters.dictadapter.DictAdapter`, rounding out the choice\n    for designing highly interactive lists.\n\n    :Events:\n        `on_scroll_complete`: (boolean, )\n            Fired when scrolling completes.\n    '''\n\n    divider = ObjectProperty(None)\n    '''[TODO] Not used.\n    '''\n\n    divider_height = NumericProperty(2)\n    '''[TODO] Not used.\n    '''\n\n    container = ObjectProperty(None)\n    '''The container is a :class:`~kivy.uix.gridlayout.GridLayout` widget held\n    within a :class:`~kivy.uix.scrollview.ScrollView` widget.  (See the\n    associated kv block in the Builder.load_string() setup). Item view\n    instances managed and provided by the adapter are added to this container.\n    The container is cleared with a call to clear_widgets() when the list is\n    rebuilt by the populate() method. A padding\n    :class:`~kivy.uix.widget.Widget` instance is also added as needed,\n    depending on the row height calculations.\n\n    :attr:`container` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    row_height = NumericProperty(None)\n    '''The row_height property is calculated on the basis of the height of the\n    container and the count of items.\n\n    :attr:`row_height` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to None.\n    '''\n\n    item_strings = ListProperty([])\n    '''If item_strings is provided, create an instance of\n    :class:`~kivy.adapters.simplelistadapter.SimpleListAdapter` with this list\n    of strings, and use it to manage a no-selection list.\n\n    :attr:`item_strings` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [].\n    '''\n\n    scrolling = BooleanProperty(False)\n    '''If the scroll_to() method is called while scrolling operations are\n    happening, a call recursion error can occur. scroll_to() checks to see that\n    scrolling is False before calling populate(). scroll_to() dispatches a\n    scrolling_complete event, which sets scrolling back to False.\n\n    :attr:`scrolling` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    _index = NumericProperty(0)\n    _sizes = DictProperty({})\n    _count = NumericProperty(0)\n\n    _wstart = NumericProperty(0)\n    _wend = NumericProperty(-1)\n\n    __events__ = ('on_scroll_complete', )\n\n    def __init__(self, **kwargs):\n        # Check for an adapter argument. If it doesn't exist, we\n        # check for item_strings in use with SimpleListAdapter\n        # to make a simple list.\n        if 'adapter' not in kwargs:\n            if 'item_strings' not in kwargs:\n                # Could be missing, or it could be that the ListView is\n                # declared in a kv file. If kv is in use, and item_strings is\n                # declared there, then item_strings will not be set until after\n                # __init__(). So, the data=[] set will temporarily serve for\n                # SimpleListAdapter instantiation, with the binding to\n                # item_strings_changed() handling the eventual set of the\n                # item_strings property from the application of kv rules.\n                list_adapter = SimpleListAdapter(data=[],\n                                                 cls=Label)\n            else:\n                list_adapter = SimpleListAdapter(data=kwargs['item_strings'],\n                                                 cls=Label)\n            kwargs['adapter'] = list_adapter\n\n        super(ListView, self).__init__(**kwargs)\n\n        self._trigger_populate = Clock.create_trigger(self._spopulate, -1)\n        self._trigger_reset_populate = \\\n            Clock.create_trigger(self._reset_spopulate, -1)\n\n        self.bind(size=self._trigger_populate,\n                  pos=self._trigger_populate,\n                  item_strings=self.item_strings_changed,\n                  adapter=self._trigger_populate)\n\n        self._trigger_bind_adapter = Clock.create_trigger(\n            lambda dt: self.adapter.bind_triggers_to_view(\n                self._trigger_reset_populate),\n            -1)\n        self.bind(adapter=self._trigger_bind_adapter)\n\n        # The bindings setup above sets self._trigger_populate() to fire\n        # when the adapter changes, but we also need this binding for when\n        # adapter.data and other possible triggers change for view updating.\n        # We don't know that these are, so we ask the adapter to set up the\n        # bindings back to the view updating function here.\n        self._trigger_bind_adapter()\n\n    # Added to set data when item_strings is set in a kv template, but it will\n    # be good to have also if item_strings is reset generally.\n    def item_strings_changed(self, *args):\n        self.adapter.data = self.item_strings\n\n    def _scroll(self, scroll_y):\n        if self.row_height is None:\n            return\n        self._scroll_y = scroll_y\n        scroll_y = 1 - min(1, max(scroll_y, 0))\n        container = self.container\n        mstart = (container.height - self.height) * scroll_y\n        mend = mstart + self.height\n\n        # convert distance to index\n        rh = self.row_height\n        istart = int(ceil(mstart / rh))\n        iend = int(floor(mend / rh))\n\n        istart = max(0, istart - 1)\n        iend = max(0, iend - 1)\n\n        if istart < self._wstart:\n            rstart = max(0, istart - 10)\n            self.populate(rstart, iend)\n            self._wstart = rstart\n            self._wend = iend\n        elif iend > self._wend:\n            self.populate(istart, iend + 10)\n            self._wstart = istart\n            self._wend = iend + 10\n\n    def _spopulate(self, *args):\n        self.populate()\n\n    def _reset_spopulate(self, *args):\n        self._wend = -1\n        self.populate()\n        # simulate the scroll again, only if we already scrolled before\n        # the position might not be the same, mostly because we don't know the\n        # size of the new item.\n        if hasattr(self, '_scroll_y'):\n            self._scroll(self._scroll_y)\n\n    def populate(self, istart=None, iend=None):\n        container = self.container\n        sizes = self._sizes\n        rh = self.row_height\n\n        # ensure we know what we want to show\n        if istart is None:\n            istart = self._wstart\n            iend = self._wend\n\n        # clear the view\n        container.clear_widgets()\n\n        # guess only ?\n        if iend is not None and iend != -1:\n\n            # fill with a \"padding\"\n            fh = 0\n            for x in range(istart):\n                fh += sizes[x] if x in sizes else rh\n            container.add_widget(Widget(size_hint_y=None, height=fh))\n\n            # now fill with real item_view\n            index = istart\n            while index <= iend:\n                item_view = self.adapter.get_view(index)\n                index += 1\n                if item_view is None:\n                    continue\n                sizes[index] = item_view.height\n                container.add_widget(item_view)\n        else:\n            available_height = self.height\n            real_height = 0\n            index = self._index\n            count = 0\n            while available_height > 0:\n                item_view = self.adapter.get_view(index)\n                if item_view is None:\n                    break\n                sizes[index] = item_view.height\n                index += 1\n                count += 1\n                container.add_widget(item_view)\n                available_height -= item_view.height\n                real_height += item_view.height\n\n            self._count = count\n\n            # extrapolate the full size of the container from the size\n            # of view instances in the adapter\n            if count:\n                container.height = \\\n                    real_height / count * self.adapter.get_count()\n                if self.row_height is None:\n                    self.row_height = real_height / count\n\n    def scroll_to(self, index=0):\n        if not self.scrolling:\n            self.scrolling = True\n            self._index = index\n            self.populate()\n            self.dispatch('on_scroll_complete')\n\n    def on_scroll_complete(self, *args):\n        self.scrolling = False\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/modalview.py",
    "content": "'''\nModalView\n=========\n\n.. versionadded:: 1.4.0\n\nThe :class:`ModalView` widget is used to create modal views. By default, the\nview will cover the whole \"parent\" window.\n\nRemember that the default size of a Widget is size_hint=(1, 1). If you don't\nwant your view to be fullscreen, either use size hints with values lower than\n1 (for instance size_hint=(.8, .8)) or deactivate the size_hint and use fixed\nsize attributes.\n\nExamples\n--------\n\nExample of a simple 400x400 Hello world view::\n\n    view = ModalView(size_hint=(None, None), size=(400, 400))\n    view.add_widget(Label(text='Hello world'))\n\nBy default, any click outside the view will dismiss it. If you don't\nwant that, you can set :attr:`ModalView.auto_dismiss` to False::\n\n    view = ModalView(auto_dismiss=False)\n    view.add_widget(Label(text='Hello world'))\n    view.open()\n\nTo manually dismiss/close the view, use the :meth:`ModalView.dismiss` method of\nthe ModalView instance::\n\n    view.dismiss()\n\nBoth :meth:`ModalView.open` and :meth:`ModalView.dismiss` are bindable. That\nmeans you can directly bind the function to an action, e.g. to a button's\non_press ::\n\n    # create content and add it to the view\n    content = Button(text='Close me!')\n    view = ModalView(auto_dismiss=False)\n    view.add_widget(content)\n\n    # bind the on_press event of the button to the dismiss function\n    content.bind(on_press=view.dismiss)\n\n    # open the view\n    view.open()\n\n\nModalView Events\n----------------\n\nThere are two events available: `on_open` which is raised when the view is\nopening, and `on_dismiss` which is raised when the view is closed.\nFor `on_dismiss`, you can prevent the view from closing by explictly returning\nTrue from your callback. ::\n\n    def my_callback(instance):\n        print('ModalView', instance, 'is being dismissed, but is prevented!')\n        return True\n    view = ModalView()\n    view.add_widget(Label(text='Hello world'))\n    view.bind(on_dismiss=my_callback)\n    view.open()\n\n\n.. versionchanged:: 1.5.0\n    The ModalView can be closed by hitting the escape key on the\n    keyboard if the :attr:`ModalView.auto_dismiss` property is True (the\n    default).\n\n'''\n\n__all__ = ('ModalView', )\n\nfrom kivy.logger import Logger\nfrom kivy.animation import Animation\nfrom kivy.uix.anchorlayout import AnchorLayout\nfrom kivy.properties import StringProperty, BooleanProperty, ObjectProperty, \\\n    NumericProperty, ListProperty\n\n\nclass ModalView(AnchorLayout):\n    '''ModalView class. See module documentation for more information.\n\n    :Events:\n        `on_open`:\n            Fired when the ModalView is opened.\n        `on_dismiss`:\n            Fired when the ModalView is closed. If the callback returns True,\n            the dismiss will be canceled.\n    '''\n\n    auto_dismiss = BooleanProperty(True)\n    '''This property determines if the view is automatically\n    dismissed when the user clicks outside it.\n\n    :attr:`auto_dismiss` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n\n    attach_to = ObjectProperty(None)\n    '''If a widget is set on attach_to, the view will attach to the nearest\n    parent window of the widget. If none is found, it will attach to the\n    main/global Window.\n\n    :attr:`attach_to` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    background_color = ListProperty([0, 0, 0, .7])\n    '''Background color in the format (r, g, b, a).\n\n    :attr:`background_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [0, 0, 0, .7].\n    '''\n\n    background = StringProperty(\n        'atlas://data/images/defaulttheme/modalview-background')\n    '''Background image of the view used for the view background.\n\n    :attr:`background` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/modalview-background'.\n    '''\n\n    border = ListProperty([16, 16, 16, 16])\n    '''Border used for :class:`~kivy.graphics.vertex_instructions.BorderImage`\n    graphics instruction. Used for the :attr:`background_normal` and the\n    :attr:`background_down` properties. Can be used when using custom\n    backgrounds.\n\n    It must be a list of four values: (top, right, bottom, left). Read the\n    BorderImage instructions for more information about how to use it.\n\n    :attr:`border` is a :class:`~kivy.properties.ListProperty` and defaults to\n    (16, 16, 16, 16).\n    '''\n\n    # Internals properties used for graphical representation.\n\n    _anim_alpha = NumericProperty(0)\n\n    _anim_duration = NumericProperty(.1)\n\n    _window = ObjectProperty(None, allownone=True)\n\n    __events__ = ('on_open', 'on_dismiss')\n\n    def __init__(self, **kwargs):\n        self._parent = None\n        super(ModalView, self).__init__(**kwargs)\n\n    def _search_window(self):\n        # get window to attach to\n        window = None\n        if self.attach_to is not None:\n            window = self.attach_to.get_parent_window()\n            if not window:\n                window = self.attach_to.get_root_window()\n        if not window:\n            from kivy.core.window import Window\n            window = Window\n        return window\n\n    def open(self, *largs):\n        '''Show the view window from the :attr:`attach_to` widget. If set, it\n        will attach to the nearest window. If the widget is not attached to any\n        window, the view will attach to the global\n        :class:`~kivy.core.window.Window`.\n        '''\n        if self._window is not None:\n            Logger.warning('ModalView: you can only open once.')\n            return self\n        # search window\n        self._window = self._search_window()\n        if not self._window:\n            Logger.warning('ModalView: cannot open view, no window found.')\n            return self\n        self._window.add_widget(self)\n        self._window.bind(\n            on_resize=self._align_center,\n            on_keyboard=self._handle_keyboard)\n        self.center = self._window.center\n        self.bind(size=self._update_center)\n        a = Animation(_anim_alpha=1., d=self._anim_duration)\n        a.bind(on_complete=lambda *x: self.dispatch('on_open'))\n        a.start(self)\n        return self\n\n    def _update_center(self, *args):\n        if not self._window:\n            return\n        # XXX HACK DONT REMOVE OR FOUND AND FIX THE ISSUE\n        # It seems that if we don't access to the center before assigning a new\n        # value, no dispatch will be done >_>\n        self.center = self._window.center\n\n    def dismiss(self, *largs, **kwargs):\n        '''Close the view if it is open. If you really want to close the\n        view, whatever the on_dismiss event returns, you can use the *force*\n        argument:\n        ::\n\n            view = ModalView(...)\n            view.dismiss(force=True)\n\n        When the view is dismissed, it will be faded out before being\n        removed from the parent. If you don't want animation, use::\n\n            view.dismiss(animation=False)\n\n        '''\n        if self._window is None:\n            return self\n        if self.dispatch('on_dismiss') is True:\n            if kwargs.get('force', False) is not True:\n                return self\n        if kwargs.get('animation', True):\n            Animation(_anim_alpha=0., d=self._anim_duration).start(self)\n        else:\n            self._anim_alpha = 0\n            self._real_remove_widget()\n        return self\n\n    def on_size(self, instance, value):\n        self._align_center()\n\n    def _align_center(self, *l):\n        if self._window:\n            self.center = self._window.center\n            # hack to resize dark background on window resize\n            _window = self._window\n            self._window = None\n            self._window = _window\n\n    def on_touch_down(self, touch):\n        if not self.collide_point(*touch.pos):\n            if self.auto_dismiss:\n                self.dismiss()\n                return True\n        super(ModalView, self).on_touch_down(touch)\n        return True\n\n    def on_touch_move(self, touch):\n        super(ModalView, self).on_touch_move(touch)\n        return True\n\n    def on_touch_up(self, touch):\n        super(ModalView, self).on_touch_up(touch)\n        return True\n\n    def on__anim_alpha(self, instance, value):\n        if value == 0 and self._window is not None:\n            self._real_remove_widget()\n\n    def _real_remove_widget(self):\n        if self._window is None:\n            return\n        self._window.remove_widget(self)\n        self._window.unbind(\n            on_resize=self._align_center,\n            on_keyboard=self._handle_keyboard)\n        self._window = None\n\n    def on_open(self):\n        pass\n\n    def on_dismiss(self):\n        pass\n\n    def _handle_keyboard(self, window, key, *largs):\n        if key == 27 and self.auto_dismiss:\n            self.dismiss()\n            return True\n\n\nif __name__ == '__main__':\n    from kivy.base import runTouchApp\n    from kivy.uix.button import Button\n    from kivy.uix.label import Label\n    from kivy.uix.gridlayout import GridLayout\n    from kivy.core.window import Window\n\n    # add view\n    content = GridLayout(cols=1)\n    content.add_widget(Label(text='This is a hello world'))\n    view = ModalView(size_hint=(None, None), size=(256, 256),\n                     auto_dismiss=True)\n    view.add_widget(content)\n\n    def open_view(btn):\n        view.open()\n\n    layout = GridLayout(cols=3)\n    for x in range(9):\n        btn = Button(text='click me %s' % x)\n        btn.bind(on_release=view.open)\n        layout.add_widget(btn)\n    Window.add_widget(layout)\n\n    view.open()\n\n    runTouchApp()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/pagelayout.py",
    "content": "\"\"\"\nPageLayout\n==========\n\nThe :class:`PageLayout` class is used to create a simple multi-page\nlayout, in a way that allows easy flipping from one page to another using\nborders.\n\n:class:`PageLayout` does not currently honor\n:attr:`~kivy.uix.widget.Widget.size_hint` or\n:attr:`~kivy.uix.widget.Widget.pos_hint` properties.\n\n.. versionadded:: 1.8.0\n\nExample::\n\n    PageLayout:\n        Button:\n            text: 'page1'\n        Button:\n            text: 'page2'\n        Button:\n            text: 'page3'\n\nTransitions from one page to the next are made by swiping in from the border\nareas on the right or left hand side. If you wish to display multiple widgets\nin a page, we suggest you use a containing layout. Ideally, each page should\nconsist of a single :mod:`~kivy.uix.layout` widget that contains the remaining\nwidgets on that page.\n\"\"\"\n\n__all__ = ('PageLayout', )\n\nfrom kivy.uix.layout import Layout\nfrom kivy.properties import NumericProperty\nfrom kivy.animation import Animation\n\n\nclass PageLayout(Layout):\n    '''PageLayout class. See module documentation for more information.\n    '''\n\n    page = NumericProperty(0)\n    '''The currently displayed page.\n\n    :data:`page` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 0.\n    '''\n\n    border = NumericProperty('50dp')\n    '''The width of the border around the current page used to display\n    the previous/next page swipe areas when needed.\n\n    :data:`border` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 50dp.\n    '''\n\n    swipe_threshold = NumericProperty(.5)\n    '''The thresold used to trigger swipes as percentage of the widget\n    size.\n\n    :data:`swipe_threshold` is a :class:`~kivy.properties.NumericProperty`\n    and defaults to .5.\n    '''\n\n    def __init__(self, **kwargs):\n        super(PageLayout, self).__init__(**kwargs)\n\n        self.bind(\n            border=self._trigger_layout,\n            page=self._trigger_layout,\n            parent=self._trigger_layout,\n            children=self._trigger_layout,\n            size=self._trigger_layout,\n            pos=self._trigger_layout)\n\n    def do_layout(self, *largs):\n        l_children = len(self.children) - 1\n        h = self.height\n        x_parent, y_parent = self.pos\n        p = self.page\n        border = self.border\n        half_border = border / 2.\n        right = self.right\n        width = self.width - border\n        for i, c in enumerate(reversed(self.children)):\n            not i or i == l_children\n\n            if i < p:\n                x = x_parent\n            elif i == p:\n                if not p:  # it's first page\n                    x = x_parent\n                elif p != l_children:  # not first, but there are post pages\n                    x = x_parent + half_border\n                else:  # not first and there are no post pages\n                    x = x_parent + border\n            elif i == p + 1:\n                if not p:  # second page - no left margin\n                    x = right - border\n                else:  # there's already a left margin\n                    x = right - half_border\n            else:\n                x = right\n\n            c.height = h\n            c.width = width\n\n            Animation(\n                x=x,\n                y=y_parent,\n                d=.5, t='in_quad').start(c)\n\n    def on_touch_down(self, touch):\n        if (self.disabled or not self.collide_point(*touch.pos) or\n            not self.children):\n            return\n\n        page = self.children[-self.page - 1]\n        if self.x <= touch.x < page.x:\n            touch.ud['page'] = 'previous'\n            touch.grab(self)\n            return True\n        elif page.right <= touch.x < self.right:\n            touch.ud['page'] = 'next'\n            touch.grab(self)\n            return True\n        return page.on_touch_down(touch)\n\n    def on_touch_move(self, touch):\n        if touch.grab_current != self:\n            return\n\n        p = self.page\n        border = self.border\n        half_border = border / 2.\n        page = self.children[-p - 1]\n        if touch.ud['page'] == 'previous':\n            # move next page upto right edge\n            if p < len(self.children) - 1:\n                self.children[-p - 2].x = min(\n                    self.right - self.border * (1 - (touch.sx - touch.osx)),\n                    self.right)\n\n            # move current page until edge hits the right border\n            if p >= 1:\n                b_right = half_border if p > 1 else border\n                b_left = half_border if p < len(self.children) - 1 else border\n                self.children[-p - 1].x = max(min(\n                    self.x + b_left + (touch.x - touch.ox),\n                    self.right - b_right),\n                    self.x + b_left)\n\n            # move previous page left edge upto left border\n            if p > 1:\n                self.children[-p].x = min(\n                    self.x + half_border * (touch.sx - touch.osx),\n                    self.x + half_border)\n\n        elif touch.ud['page'] == 'next':\n            # move current page upto left edge\n            if p >= 1:\n                self.children[-p - 1].x = max(\n                    self.x + half_border * (1 - (touch.osx - touch.sx)),\n                    self.x)\n\n            # move next page until its edge hit the left border\n            if p < len(self.children) - 1:\n                b_right = half_border if p >= 1 else border\n                b_left = half_border if p < len(self.children) - 2 else border\n                self.children[-p - 2].x = min(max(\n                    self.right - b_right + (touch.x - touch.ox),\n                    self.x + b_left),\n                    self.right - b_right)\n\n            # move second next page upto right border\n            if p < len(self.children) - 2:\n                self.children[-p - 3].x = max(\n                    self.right + half_border * (touch.sx - touch.osx),\n                    self.right - half_border)\n\n        return page.on_touch_move(touch)\n\n    def on_touch_up(self, touch):\n        if touch.grab_current == self:\n            if (\n                touch.ud['page'] == 'previous' and\n                abs(touch.x - touch.ox) / self.width > self.swipe_threshold\n            ):\n                self.page -= 1\n            elif (\n                touch.ud['page'] == 'next' and\n                abs(touch.x - touch.ox) / self.width > self.swipe_threshold\n            ):\n                self.page += 1\n            else:\n                self._trigger_layout()\n\n            touch.ungrab(self)\n        return self.children[-self.page + 1].on_touch_up(touch)\n\n\nif __name__ == '__main__':\n    from kivy.base import runTouchApp\n    from kivy.uix.button import Button\n\n    pl = PageLayout()\n    for i in range(1, 4):\n        b = Button(text='page%s' % i)\n        pl.add_widget(b)\n\n    runTouchApp(pl)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/popup.py",
    "content": "'''\nPopup\n=====\n\n.. versionadded:: 1.0.7\n\n.. image:: images/popup.jpg\n    :align: right\n\nThe :class:`Popup` widget is used to create modal popups. By default, the popup\nwill cover the whole \"parent\" window. When you are creating a popup, you\nmust at least set a :attr:`Popup.title` and :attr:`Popup.content`.\n\nRemember that the default size of a Widget is size_hint=(1, 1). If you don't\nwant your popup to be fullscreen, either use size hints with values less than 1\n(for instance size_hint=(.8, .8)) or deactivate the size_hint and use\nfixed size attributes.\n\n\n.. versionchanged:: 1.4.0\n    The :class:`Popup` class now inherits from\n    :class:`~kivy.uix.modalview.ModalView`. The :class:`Popup` offers a default\n    layout with a title and a separation bar.\n\nExamples\n--------\n\nExample of a simple 400x400 Hello world popup::\n\n    popup = Popup(title='Test popup',\n        content=Label(text='Hello world'),\n        size_hint=(None, None), size=(400, 400))\n\nBy default, any click outside the popup will dismiss/close it. If you don't\nwant that, you can set\n:attr:`~kivy.uix.modalview.ModalView.auto_dismiss` to False::\n\n    popup = Popup(title='Test popup', content=Label(text='Hello world'),\n                  auto_dismiss=False)\n    popup.open()\n\nTo manually dismiss/close the popup, use\n:attr:`~kivy.uix.modalview.ModalView.dismiss`::\n\n    popup.dismiss()\n\nBoth :meth:`~kivy.uix.modalview.ModalView.open` and\n:meth:`~kivy.uix.modalview.ModalView.dismiss` are bindable. That means you\ncan directly bind the function to an action, e.g. to a button's on_press::\n\n    # create content and add to the popup\n    content = Button(text='Close me!')\n    popup = Popup(content=content, auto_dismiss=False)\n\n    # bind the on_press event of the button to the dismiss function\n    content.bind(on_press=popup.dismiss)\n\n    # open the popup\n    popup.open()\n\n\nPopup Events\n------------\n\nThere are two events available: `on_open` which is raised when the popup is\nopening, and `on_dismiss` which is raised when the popup is closed.\nFor `on_dismiss`, you can prevent the\npopup from closing by explictly returning True from your callback::\n\n    def my_callback(instance):\n        print('Popup', instance, 'is being dismissed but is prevented!')\n        return True\n    popup = Popup(content=Label(text='Hello world'))\n    popup.bind(on_dismiss=my_callback)\n    popup.open()\n\n'''\n\n__all__ = ('Popup', 'PopupException')\n\nfrom kivy.uix.modalview import ModalView\nfrom kivy.properties import (StringProperty, ObjectProperty, OptionProperty,\n                             NumericProperty, ListProperty)\n\n\nclass PopupException(Exception):\n    '''Popup exception, fired when multiple content widgets are added to the\n    popup.\n\n    .. versionadded:: 1.4.0\n    '''\n\n\nclass Popup(ModalView):\n    '''Popup class. See module documentation for more information.\n\n    :Events:\n        `on_open`:\n            Fired when the Popup is opened.\n        `on_dismiss`:\n            Fired when the Popup is closed. If the callback returns True, the\n            dismiss will be canceled.\n    '''\n\n    title = StringProperty('No title')\n    '''String that represents the title of the popup.\n\n    :attr:`title` is a :class:`~kivy.properties.StringProperty` and defaults to\n    'No title'.\n    '''\n\n    title_size = NumericProperty('14sp')\n    '''Represents the font size of the popup title.\n\n    .. versionadded:: 1.6.0\n\n    :attr:`title_size` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to '14sp'.\n    '''\n\n    title_align = OptionProperty('left',\n                                 options=['left', 'center', 'right', 'justify'])\n    '''Horizontal alignment of the title.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`title_align` is a :class:`~kivy.properties.OptionProperty` and\n    defaults to 'left'. Available options are left, middle, right and justify.\n    '''\n\n    title_font = StringProperty('DroidSans')\n    '''Font used to render the title text.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`title_font` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'DroidSans'.\n    '''\n\n    content = ObjectProperty(None)\n    '''Content of the popup that is displayed just under the title.\n\n    :attr:`content` is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    title_color = ListProperty([1, 1, 1, 1])\n    '''Color used by the Title.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`title_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [1, 1, 1, 1].\n    '''\n\n    separator_color = ListProperty([47 / 255., 167 / 255., 212 / 255., 1.])\n    '''Color used by the separator between title and content.\n\n    .. versionadded:: 1.1.0\n\n    :attr:`separator_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [47 / 255., 167 / 255., 212 / 255., 1.]\n    '''\n\n    separator_height = NumericProperty('2dp')\n    '''Height of the separator.\n\n    .. versionadded:: 1.1.0\n\n    :attr:`separator_height` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 2dp.\n    '''\n\n    # Internal properties used for graphical representation.\n\n    _container = ObjectProperty(None)\n\n    def add_widget(self, widget):\n        if self._container:\n            if self.content:\n                raise PopupException(\n                    'Popup can have only one widget as content')\n            self.content = widget\n        else:\n            super(Popup, self).add_widget(widget)\n\n    def on_content(self, instance, value):\n        if self._container:\n            self._container.clear_widgets()\n            self._container.add_widget(value)\n\n    def on__container(self, instance, value):\n        if value is None or self.content is None:\n            return\n        self._container.clear_widgets()\n        self._container.add_widget(self.content)\n\n    def on_touch_down(self, touch):\n        if self.disabled and self.collide_point(*touch.pos):\n            return True\n        return super(Popup, self).on_touch_down(touch)\n\n\nif __name__ == '__main__':\n    from kivy.base import runTouchApp\n    from kivy.uix.button import Button\n    from kivy.uix.label import Label\n    from kivy.uix.gridlayout import GridLayout\n    from kivy.core.window import Window\n\n    # add popup\n    content = GridLayout(cols=1)\n    content_cancel = Button(text='Cancel', size_hint_y=None, height=40)\n    content.add_widget(Label(text='This is a hello world'))\n    content.add_widget(content_cancel)\n    popup = Popup(title='Test popup',\n                  size_hint=(None, None), size=(256, 256),\n                  content=content, disabled=True)\n    content_cancel.bind(on_release=popup.dismiss)\n\n    layout = GridLayout(cols=3)\n    for x in range(9):\n        btn = Button(text=str(x))\n        btn.bind(on_release=popup.open)\n        layout.add_widget(btn)\n\n    Window.add_widget(layout)\n\n    popup.open()\n\n    runTouchApp()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/progressbar.py",
    "content": "'''\nProgress Bar\n============\n\n.. versionadded:: 1.0.8\n\n.. image:: images/progressbar.jpg\n    :align: right\n\nThe :class:`ProgressBar` widget is used to visualize the progress of some task.\nOnly the horizontal mode is currently supported: the vertical mode is not\nyet available.\n\nThe progress bar has no interactive elements and is a display-only widget.\n\nTo use it, simply assign a value to indicate the current progress::\n\n    from kivy.uix.progressbar import ProgressBar\n    pb = ProgressBar(max=1000)\n\n    # this will update the graphics automatically (75% done)\n    pb.value = 750\n\n'''\n\n__all__ = ('ProgressBar', )\n\nfrom kivy.uix.widget import Widget\nfrom kivy.properties import NumericProperty, AliasProperty\n\n\nclass ProgressBar(Widget):\n    '''Class for creating a progress bar widget.\n\n    See module documentation for more details.\n    '''\n\n    def __init__(self, **kwargs):\n        self._value = 0.\n        super(ProgressBar, self).__init__(**kwargs)\n\n    def _get_value(self):\n        return self._value\n\n    def _set_value(self, value):\n        value = max(0, min(self.max, value))\n        if value != self._value:\n            self._value = value\n            return True\n\n    value = AliasProperty(_get_value, _set_value)\n    '''Current value used for the slider.\n\n    :attr:`value` is an :class:`~kivy.properties.AliasProperty` that\n    returns the value of the progress bar. If the value is < 0 or >\n    :attr:`max`, it will be normalized to those boundaries.\n\n    .. versionchanged:: 1.6.0\n        The value is now limited to between 0 and :attr:`max`.\n    '''\n\n    def get_norm_value(self):\n        d = self.max\n        if d == 0:\n            return 0\n        return self.value / float(d)\n\n    def set_norm_value(self, value):\n        self.value = value * self.max\n\n    value_normalized = AliasProperty(get_norm_value, set_norm_value,\n                                     bind=('value', 'max'))\n    '''Normalized value inside the range 0-1::\n\n        >>> pb = ProgressBar(value=50, max=100)\n        >>> pb.value\n        50\n        >>> slider.value_normalized\n        0.5\n\n    :attr:`value_normalized` is an :class:`~kivy.properties.AliasProperty`.\n    '''\n\n    max = NumericProperty(100.)\n    '''Maximum value allowed for :attr:`value`.\n\n    :attr:`max` is a :class:`~kivy.properties.NumericProperty` and defaults to\n    100.\n    '''\n\n\nif __name__ == '__main__':\n\n    from kivy.base import runTouchApp\n    runTouchApp(ProgressBar(value=50))\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/relativelayout.py",
    "content": "'''\nRelative Layout\n===============\n\n.. versionadded:: 1.4.0\n\n\nThis layout allows you to set relative coordinates for children. If you want\nabsolute positioning, use the :class:`~kivy.uix.floatlayout.FloatLayout`.\n\nThe :class:`RelativeLayout` class behaves just like the regular\n:class:`FloatLayout` except that its child widgets are positioned relative to\nthe layout.\n\nWhen a widget with position = (0,0) is added to a RelativeLayout,\nthe child widget will also move when the position of the RelativeLayout\nis changed. The child widgets coordinates remain (0,0) as they are\nalways relative to the parent layout.\n\nCoordinate Systems\n------------------\n\nWindow coordinates\n~~~~~~~~~~~~~~~~~~\n\nBy default, there's only one coordinate system that defines the position of\nwidgets and touch events dispatched to them: the window coordinate system,\nwhich places (0, 0) at the bottom left corner of the window.\nAlthough there are other coordinate systems defined, e.g. local\nand parent coordinates, these coordinate systems are identical to the window\ncoordinate system as long as a relative layout type widget is not in the\nwidget's parent stack. When widget.pos is read or a touch is received,\nthe coordinate values are in parent coordinates, but as mentioned, these are\nidentical to window coordinates, even in complex widget stacks.\n\nFor example::\n\n    BoxLayout:\n        Label:\n            text: 'Left'\n        Button:\n            text: 'Middle'\n            on_touch_down: print('Middle: {}'.format(args[1].pos))\n        BoxLayout:\n            on_touch_down: print('Box: {}'.format(args[1].pos))\n            Button:\n                text: 'Right'\n                on_touch_down: print('Right: {}'.format(args[1].pos))\n\nWhen the middle button is clicked and the touch propagates through the\ndifferent parent coordinate systems, it prints the following::\n\n    >>> Box: (430.0, 282.0)\n    >>> Right: (430.0, 282.0)\n    >>> Middle: (430.0, 282.0)\n\nAs claimed, the touch has identical coordinates to the window coordinates\nin every coordinate system. :meth:`~kivy.uix.widget.Widget.collide_point`\nfor example, takes the point in window coordinates.\n\nParent coordinates\n~~~~~~~~~~~~~~~~~~\n\nOther :class:`RelativeLayout` type widgets are\n:class:`~kivy.uix.scatter.Scatter`,\n:class:`~kivy.uix.scatterlayout.ScatterLayout`,\nand :class:`~kivy.uix.scrollview.ScrollView`. If such a special widget is in\nthe parent stack, only then does the parent and local coordinate system\ndiverge from the window coordinate system. For each such widget in the stack,\na coordinate system with (0, 0) of that coordinate system being at the bottom\nleft corner of that widget is created. **Position and touch coordinates\nreceived and read by a widget are in the coordinate system of the most\nrecent special widget in its parent stack (not including itself) or in window\ncoordinates if there are none** (as in the first example). We call these\ncoordinates parent coordinates.\n\n\nFor example::\n\n    BoxLayout:\n        Label:\n            text: 'Left'\n        Button:\n            text: 'Middle'\n            on_touch_down: print('Middle: {}'.format(args[1].pos))\n        RelativeLayout:\n            on_touch_down: print('Relative: {}'.format(args[1].pos))\n            Button:\n                text: 'Right'\n                on_touch_down: print('Right: {}'.format(args[1].pos))\n\nClicking on the middle button prints::\n\n    >>> Relative: (396.0, 298.0)\n    >>> Right: (-137.33, 298.0)\n    >>> Middle: (396.0, 298.0)\n\nAs the touch propagates through the widgets, for each widget, the\ntouch is received in parent coordinates. Because both the relative and middle\nwidgets don't have these special widgets in their parent stack, the touch is\nthe same as window coordinates. Only the right widget, which has a\nRelativeLayout in its parent stack, receives the touch in coordinates relative\nto that RelativeLayout which is different than window coordinates.\n\nLocal and Widget coordinates\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nWhen expressed in parent coordinates, the position is expressed in the\ncoordinates of the most recent special widget in its parent stack, not\nincluding itself. When expressed in local or widget coordinates, the widgets\nthemselves are also included.\n\nChanging the above example to transform the parent coordinates into local\ncoordinates::\n\n    BoxLayout:\n        Label:\n            text: 'Left'\n        Button:\n            text: 'Middle'\n            on_touch_down: print('Middle: {}'.format(\\\nself.to_local(*args[1].pos)))\n        RelativeLayout:\n            on_touch_down: print('Relative: {}'.format(\\\nself.to_local(*args[1].pos)))\n            Button:\n                text: 'Right'\n                on_touch_down: print('Right: {}'.format(\\\nself.to_local(*args[1].pos)))\n\nNow, clicking on the middle button prints::\n\n    >>> Relative: (-135.33, 301.0)\n    >>> Right: (-135.33, 301.0)\n    >>> Middle: (398.0, 301.0)\n\nThis is because now the relative widget also expresses the coordinates\nrelative to itself.\n\nCoordinate transformations\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n:class:`~kivy.uix.widget.Widget` provides 4 functions to transform coordinates\nbetween the various coordinate systems. For now, we assume that the `relative`\nkeyword of these functions is `False`.\n:meth:`~kivy.uix.widget.Widget.to_widget` takes the coordinates expressed in\nwindow coordinates and returns them in local (widget) coordinates.\n:meth:`~kivy.uix.widget.Widget.to_window` takes the coordinates expressed in\nlocal coordinates and returns them in window coordinates.\n:meth:`~kivy.uix.widget.Widget.to_parent` takes the coordinates expressed in\nlocal coordinates and returns them in parent coordinates.\n:meth:`~kivy.uix.widget.Widget.to_local` takes the coordinates expressed in\nparent coordinates and returns them in local coordinates.\n\nEach of the 4 transformation functions take a `relative` parameter. When the\nrelative parameter is True, the coordinates are returned or originate in\ntrue relative coordinates - relative to a coordinate system with its (0, 0) at\nthe bottom left corner of the widget in question.\n\n.. _kivy-uix-relativelayout-common-pitfalls:\n\nCommon Pitfalls\n---------------\n\nAs all positions within a :class:`RelativeLayout` are relative to the position\nof the layout itself, the position of the layout should never be used in\ndetermining the position of sub-widgets or the layout's :attr:`canvas`.\n\nTake the following kv code for example:\n\n.. container:: align-right\n\n    .. figure:: images/relativelayout-fixedposition.png\n        :scale: 50%\n\n        expected result\n\n    .. figure:: images/relativelayout-doubleposition.png\n        :scale: 50%\n\n        actual result\n\n.. code::\n\n    FloatLayout:\n        Widget:\n            size_hint: None, None\n            size: 200, 200\n            pos: 200, 200\n\n            canvas:\n                Color:\n                    rgba: 1, 1, 1, 1\n                Rectangle:\n                    pos: self.pos\n                    size: self.size\n\n        RelativeLayout:\n            size_hint: None, None\n            size: 200, 200\n            pos: 200, 200\n\n            canvas:\n                Color:\n                    rgba: 1, 0, 0, 0.5\n                Rectangle:\n                    pos: self.pos  # incorrect\n                    size: self.size\n\nYou might expect this to render a single pink rectangle; however, the content\nof the :class:`RelativeLayout` is already transformed, so the use of\n`pos: self.pos` will double that transformation. In this case, using\n`pos: 0, 0` or omitting `pos` completely will provide the expected result.\n\nThis also applies to the position of sub-widgets. Instead of positioning a\n:class:`~kivy.uix.widget.Widget` based on the layout's own position::\n\n    RelativeLayout:\n        Widget:\n            pos: self.parent.pos\n        Widget:\n            center: self.parent.center\n\n...use the :attr:`pos_hint` property::\n\n    RelativeLayout:\n        Widget:\n            pos_hint: {'x': 0, 'y': 0}\n        Widget:\n            pos_hint: {'center_x': 0.5, 'center_y': 0.5}\n\n.. versionchanged:: 1.7.0\n    Prior to version 1.7.0, the :class:`RelativeLayout` was implemented as a\n    :class:`~kivy.uix.floatlayout.FloatLayout` inside a\n    :class:`~kivy.uix.scatter.Scatter`. This behaviour/widget has\n    been renamed to `ScatterLayout`. The :class:`RelativeLayout` now only\n    supports relative positions (and can't be rotated, scaled or translated on\n    a multitouch system using two or more fingers). This was done so that the\n    implementation could be optimized and avoid the heavier calculations of\n    :class:`Scatter` (e.g. inverse matrix, recaculating multiple properties\n    etc.)\n\n'''\n\n__all__ = ('RelativeLayout', )\n\nfrom kivy.uix.floatlayout import FloatLayout\n\n\nclass RelativeLayout(FloatLayout):\n    '''RelativeLayout class, see module documentation for more information.\n    '''\n\n    def __init__(self, **kw):\n        super(RelativeLayout, self).__init__(**kw)\n        self.unbind(pos=self._trigger_layout,\n                    pos_hint=self._trigger_layout)\n\n    def do_layout(self, *args):\n        super(RelativeLayout, self).do_layout(pos=(0, 0))\n\n    def to_parent(self, x, y, **k):\n        return (x + self.x, y + self.y)\n\n    def to_local(self, x, y, **k):\n        return (x - self.x, y - self.y)\n\n    def _apply_transform(self, m):\n        m.translate(self.x, self.y, 0)\n        return super(RelativeLayout, self)._apply_transform(m)\n\n    def on_touch_down(self, touch):\n        x, y = touch.x, touch.y\n        touch.push()\n        touch.apply_transform_2d(self.to_local)\n        ret = super(RelativeLayout, self).on_touch_down(touch)\n        touch.pop()\n        return ret\n\n    def on_touch_move(self, touch):\n        x, y = touch.x, touch.y\n        touch.push()\n        touch.apply_transform_2d(self.to_local)\n        ret = super(RelativeLayout, self).on_touch_move(touch)\n        touch.pop()\n        return ret\n\n    def on_touch_up(self, touch):\n        x, y = touch.x, touch.y\n        touch.push()\n        touch.apply_transform_2d(self.to_local)\n        ret = super(RelativeLayout, self).on_touch_up(touch)\n        touch.pop()\n        return ret\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/rst.py",
    "content": "'''\nreStructuredText renderer\n=========================\n\n.. versionadded:: 1.1.0\n\n`reStructuredText <http://docutils.sourceforge.net/rst.html>`_ is an\neasy-to-read, what-you-see-is-what-you-get plaintext markup syntax and parser\nsystem.\n\n.. warning::\n\n    This widget is highly experimental. The whole styling and\n    implementation are not stable until this warning has been removed.\n\nUsage with Text\n---------------\n\n::\n\n    text = \"\"\"\n    .. _top:\n\n    Hello world\n    ===========\n\n    This is an **emphased text**, some ``interpreted text``.\n    And this is a reference to top_::\n\n        $ print(\"Hello world\")\n\n    \"\"\"\n    document = RstDocument(text=text)\n\nThe rendering will output:\n\n.. image:: images/rstdocument.png\n\nUsage with Source\n-----------------\n\nYou can also render a rst file using the :attr:`RstDocument.source` property::\n\n    document = RstDocument(source='index.rst')\n\nYou can reference other documents with the role ``:doc:``. For example, in the\ndocument ``index.rst`` you can write::\n\n    Go to my next document: :doc:`moreinfo.rst`\n\nIt will generate a link that, when clicked, opens the ``moreinfo.rst``\ndocument.\n\n'''\n\n__all__ = ('RstDocument', )\n\nimport os\nfrom os.path import dirname, join, exists, abspath\nfrom kivy.clock import Clock\nfrom kivy.compat import PY2\nfrom kivy.properties import ObjectProperty, NumericProperty, \\\n    DictProperty, ListProperty, StringProperty, \\\n    BooleanProperty, OptionProperty, AliasProperty\nfrom kivy.lang import Builder\nfrom kivy.utils import get_hex_from_color, get_color_from_hex\nfrom kivy.uix.widget import Widget\nfrom kivy.uix.scrollview import ScrollView\nfrom kivy.uix.gridlayout import GridLayout\nfrom kivy.uix.label import Label\nfrom kivy.uix.image import AsyncImage, Image\nfrom kivy.uix.videoplayer import VideoPlayer\nfrom kivy.uix.anchorlayout import AnchorLayout\nfrom kivy.animation import Animation\nfrom kivy.logger import Logger\nfrom docutils.parsers import rst\nfrom docutils.parsers.rst import roles\nfrom docutils import nodes, frontend, utils\nfrom docutils.parsers.rst import Directive, directives\nfrom docutils.parsers.rst.roles import set_classes\nfrom kivy.parser import parse_color\n\n\n#\n# Handle some additional roles\n#\nif 'KIVY_DOC' not in os.environ:\n\n    class role_doc(nodes.Inline, nodes.TextElement):\n        pass\n\n    class role_video(nodes.General, nodes.TextElement):\n        pass\n\n    class VideoDirective(Directive):\n        has_content = False\n        required_arguments = 1\n        optional_arguments = 0\n        final_argument_whitespace = True\n        option_spec = {'width': directives.nonnegative_int,\n                       'height': directives.nonnegative_int}\n\n        def run(self):\n            set_classes(self.options)\n            node = role_video(source=self.arguments[0], **self.options)\n            return [node]\n\n    generic_docroles = {\n        'doc': role_doc}\n\n    for rolename, nodeclass in generic_docroles.items():\n        generic = roles.GenericRole(rolename, nodeclass)\n        role = roles.CustomRole(rolename, generic, {'classes': [rolename]})\n        roles.register_local_role(rolename, role)\n\n    directives.register_directive('video', VideoDirective)\n\nBuilder.load_string('''\n#:import parse_color kivy.parser.parse_color\n\n\n\n<RstDocument>:\n    content: content\n    scatter: scatter\n    do_scroll_x: False\n    canvas.before:\n        Color:\n            rgba: parse_color(root.colors['background'])\n        Rectangle:\n            pos: self.pos\n            size: self.size\n\n    Scatter:\n        id: scatter\n        size_hint_y: None\n        height: content.minimum_height\n        width: root.width\n        scale: 1\n        do_translation: False, False\n        do_scale: False\n        do_rotation: False\n\n        GridLayout:\n            id: content\n            cols: 1\n            height: self.minimum_height\n            width: root.width\n            padding: 10\n\n<RstTitle>:\n    markup: True\n    valign: 'top'\n    font_size:\n        sp(self.document.base_font_size - self.section * (\n        self.document.base_font_size / 31.0 * 2))\n    size_hint_y: None\n    height: self.texture_size[1] + dp(20)\n    text_size: self.width, None\n    bold: True\n\n    canvas:\n        Color:\n            rgba: parse_color(self.document.underline_color)\n        Rectangle:\n            pos: self.x, self.y + 5\n            size: self.width, 1\n\n\n<RstParagraph>:\n    markup: True\n    valign: 'top'\n    size_hint_y: None\n    height: self.texture_size[1] + self.my\n    text_size: self.width - self.mx, None\n    font_size: sp(self.document.base_font_size / 2.0)\n\n<RstTerm>:\n    size_hint: None, None\n    height: label.height\n    anchor_x: 'left'\n    Label:\n        id: label\n        text: root.text\n        markup: True\n        valign: 'top'\n        size_hint: None, None\n        size: self.texture_size[0] + dp(10), self.texture_size[1] + dp(10)\n        font_size: sp(root.document.base_font_size / 2.0)\n\n<RstBlockQuote>:\n    cols: 2\n    content: content\n    size_hint_y: None\n    height: content.height\n    Widget:\n        size_hint_x: None\n        width: 20\n    GridLayout:\n        id: content\n        cols: 1\n        size_hint_y: None\n        height: self.minimum_height\n\n<RstLiteralBlock>:\n    cols: 1\n    content: content\n    size_hint_y: None\n    height: content.texture_size[1] + dp(20)\n    canvas:\n        Color:\n            rgb: parse_color('#cccccc')\n        Rectangle:\n            pos: self.x - 1, self.y - 1\n            size: self.width + 2, self.height + 2\n        Color:\n            rgb: parse_color('#eeeeee')\n        Rectangle:\n            pos: self.pos\n            size: self.size\n    Label:\n        id: content\n        markup: True\n        valign: 'top'\n        text_size: self.width - 20, None\n        font_name: 'data/fonts/DroidSansMono.ttf'\n        color: (0, 0, 0, 1)\n\n<RstList>:\n    cols: 2\n    size_hint_y: None\n    height: self.minimum_height\n\n<RstListItem>:\n    cols: 1\n    size_hint_y: None\n    height: self.minimum_height\n\n<RstSystemMessage>:\n    cols: 1\n    size_hint_y: None\n    height: self.minimum_height\n    canvas:\n        Color:\n            rgba: 1, 0, 0, .3\n        Rectangle:\n            pos: self.pos\n            size: self.size\n\n<RstWarning>:\n    content: content\n    cols: 1\n    padding: 20\n    size_hint_y: None\n    height: self.minimum_height\n    canvas:\n        Color:\n            rgba: 1, 0, 0, .5\n        Rectangle:\n            pos: self.x + 10, self.y + 10\n            size: self.width - 20, self.height - 20\n    GridLayout:\n        cols: 1\n        id: content\n        size_hint_y: None\n        height: self.minimum_height\n\n<RstNote>:\n    content: content\n    cols: 1\n    padding: 20\n    size_hint_y: None\n    height: self.minimum_height\n    canvas:\n        Color:\n            rgba: 0, 1, 0, .5\n        Rectangle:\n            pos: self.x + 10, self.y + 10\n            size: self.width - 20, self.height - 20\n    GridLayout:\n        cols: 1\n        id: content\n        size_hint_y: None\n        height: self.minimum_height\n\n<RstImage>:\n    size_hint: None, None\n    size: self.texture_size[0], self.texture_size[1] + dp(10)\n\n<RstAsyncImage>:\n    size_hint: None, None\n    size: self.texture_size[0], self.texture_size[1] + dp(10)\n\n<RstDefinitionList>:\n    cols: 1\n    size_hint_y: None\n    height: self.minimum_height\n    font_size: sp(self.document.base_font_size / 2.0)\n\n<RstDefinition>:\n    cols: 2\n    size_hint_y: None\n    height: self.minimum_height\n    font_size: sp(self.document.base_font_size / 2.0)\n\n<RstFieldList>:\n    cols: 2\n    size_hint_y: None\n    height: self.minimum_height\n\n<RstFieldName>:\n    markup: True\n    valign: 'top'\n    size_hint: 0.2, 1\n    color: (0, 0, 0, 1)\n    bold: True\n    text_size: self.width-10, self.height - 10\n    valign: 'top'\n    font_size: sp(self.document.base_font_size / 2.0)\n\n<RstFieldBody>:\n    cols: 1\n    size_hint_y: None\n    height: self.minimum_height\n\n<RstTable>:\n    size_hint_y: None\n    height: self.minimum_height\n\n<RstEntry>:\n    cols: 1\n    size_hint_y: None\n    height: self.minimum_height\n\n    canvas:\n        Color:\n            rgb: .2, .2, .2\n        Line:\n            points: [\\\n            self.x,\\\n            self.y,\\\n            self.right,\\\n            self.y,\\\n            self.right,\\\n            self.top,\\\n            self.x,\\\n            self.top,\\\n            self.x,\\\n            self.y]\n\n<RstTransition>:\n    size_hint_y: None\n    height: 20\n    canvas:\n        Color:\n            rgb: .2, .2, .2\n        Line:\n            points: [self.x, self.center_y, self.right, self.center_y]\n\n<RstListBullet>:\n    markup: True\n    valign: 'top'\n    size_hint_x: None\n    width: self.texture_size[0] + dp(10)\n    text_size: None, self.height - dp(10)\n    font_size: sp(self.document.base_font_size / 2.0)\n\n<RstEmptySpace>:\n    size_hint: 0.01, 0.01\n\n<RstDefinitionSpace>:\n    size_hint: None, 0.1\n    width: 50\n    font_size: sp(self.document.base_font_size / 2.0)\n\n<RstVideoPlayer>:\n    options: {'allow_stretch': True}\n    canvas.before:\n        Color:\n            rgba: (1, 1, 1, 1)\n        BorderImage:\n            source: 'atlas://data/images/defaulttheme/player-background'\n            pos: self.x - 25, self.y - 25\n            size: self.width + 50, self.height + 50\n            border: (25, 25, 25, 25)\n''')\n\n\nclass RstVideoPlayer(VideoPlayer):\n    pass\n\n\nclass RstDocument(ScrollView):\n    '''Base widget used to store an Rst document. See module documentation for\n    more information.\n    '''\n    source = StringProperty(None)\n    '''Filename of the RST document.\n\n    :attr:`source` is a :class:`~kivy.properties.StringProperty` and\n    defaults to None.\n    '''\n\n    source_encoding = StringProperty('utf-8')\n    '''Encoding to be used for the :attr:`source` file.\n\n    :attr:`source_encoding` is a :class:`~kivy.properties.StringProperty` and\n    defaults to `utf-8`.\n\n    .. Note::\n        It is your responsibility to ensure that the value provided is a\n        valid codec supported by python.\n    '''\n\n    source_error = OptionProperty('strict',\n                                  options=('strict', 'ignore', 'replace',\n                                           'xmlcharrefreplace',\n                                           'backslashreplac'))\n    '''Error handling to be used while encoding the :attr:`source` file.\n\n    :attr:`source_error` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to `strict`. Can be one of 'strict', 'ignore', 'replace',\n    'xmlcharrefreplace' or 'backslashreplac'.\n    '''\n\n    text = StringProperty(None)\n    '''RST markup text of the document.\n\n    :attr:`text` is a :class:`~kivy.properties.StringProperty` and defaults to\n    None.\n    '''\n\n    document_root = StringProperty(None)\n    '''Root path where :doc: will search for rst documents. If no path is\n    given, it will use the directory of the first loaded source file.\n\n    :attr:`document_root` is a :class:`~kivy.properties.StringProperty` and\n    defaults to None.\n    '''\n\n    base_font_size = NumericProperty(31)\n    '''Font size for the biggest title, 31 by default. All other font sizes are\n    derived from this.\n\n    .. versionadded:: 1.8.0\n    '''\n\n    show_errors = BooleanProperty(False)\n    '''Indicate whether RST parsers errors should be shown on the screen\n    or not.\n\n    :attr:`show_errors` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    def _get_bgc(self):\n        return get_color_from_hex(self.colors.background)\n\n    def _set_bgc(self, value):\n        self.colors.background = get_hex_from_color(value)[1:]\n\n    background_color = AliasProperty(_get_bgc, _set_bgc, bind=('colors',))\n    '''Specifies the background_color to be used for the RstDocument.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`background_color` is an :class:`~kivy.properties.AliasProperty`\n    for colors['background'].\n    '''\n\n    colors = DictProperty({\n        'background': 'e5e6e9ff',\n        'link': 'ce5c00ff',\n        'paragraph': '202020ff',\n        'title': '204a87ff',\n        'bullet': '000000ff'})\n    '''Dictionary of all the colors used in the RST rendering.\n\n    .. warning::\n\n        This dictionary is needs special handling. You also need to call\n        :meth:`RstDocument.render` if you change them after loading.\n\n    :attr:`colors` is a :class:`~kivy.properties.DictProperty`.\n    '''\n\n    title = StringProperty('')\n    '''Title of the current document.\n\n    :attr:`title` is a :class:`~kivy.properties.StringProperty` and defaults to\n    ''. It is read-only.\n    '''\n\n    toctrees = DictProperty({})\n    '''Toctree of all loaded or preloaded documents. This dictionary is filled\n    when a rst document is explicitly loaded or where :meth:`preload` has been\n    called.\n\n    If the document has no filename, e.g. when the document is loaded from a\n    text file, the key will be ''.\n\n    :attr:`toctrees` is a :class:`~kivy.properties.DictProperty` and defaults\n    to {}.\n    '''\n\n    underline_color = StringProperty('204a9699')\n    '''underline color of the titles, expressed in html color notation\n\n    :attr:`underline_color` is a\n    :class:`~kivy.properties.StringProperty` and defaults to '204a9699'.\n\n    .. versionadded: 1.9.0\n    '''\n\n    # internals.\n    content = ObjectProperty(None)\n    scatter = ObjectProperty(None)\n    anchors_widgets = ListProperty([])\n    refs_assoc = DictProperty({})\n\n    def __init__(self, **kwargs):\n        self._trigger_load = Clock.create_trigger(self._load_from_text, -1)\n        self._parser = rst.Parser()\n        self._settings = frontend.OptionParser(\n            components=(rst.Parser, )).get_default_values()\n        super(RstDocument, self).__init__(**kwargs)\n\n    def on_source(self, instance, value):\n        if not value:\n            return\n        if self.document_root is None:\n            # set the documentation root to the directory name of the\n            # first tile\n            self.document_root = abspath(dirname(value))\n        self._load_from_source()\n\n    def on_text(self, instance, value):\n        self._trigger_load()\n\n    def render(self):\n        '''Force document rendering.\n        '''\n        self._load_from_text()\n\n    def resolve_path(self, filename):\n        '''Get the path for this filename. If the filename doesn't exist,\n        it returns the document_root + filename.\n        '''\n        if exists(filename):\n            return filename\n        return join(self.document_root, filename)\n\n    def preload(self, filename, encoding='utf-8', errors='strict'):\n        '''Preload a rst file to get its toctree and its title.\n\n        The result will be stored in :attr:`toctrees` with the ``filename`` as\n        key.\n        '''\n\n        with open(filename, 'rb') as fd:\n            text = fd.read().decode(encoding, errors)\n        # parse the source\n        document = utils.new_document('Document', self._settings)\n        self._parser.parse(text, document)\n        # fill the current document node\n        visitor = _ToctreeVisitor(document)\n        document.walkabout(visitor)\n        self.toctrees[filename] = visitor.toctree\n        return text\n\n    def _load_from_source(self):\n        filename = self.resolve_path(self.source)\n        self.text = self.preload(filename,\n                                 self.source_encoding,\n                                 self.source_error)\n\n    def _load_from_text(self, *largs):\n        try:\n            # clear the current widgets\n            self.content.clear_widgets()\n            self.anchors_widgets = []\n            self.refs_assoc = {}\n\n            # parse the source\n            document = utils.new_document('Document', self._settings)\n            text = self.text\n            if PY2 and type(text) is str:\n                text = text.decode('utf-8')\n            self._parser.parse(text, document)\n\n            # fill the current document node\n            visitor = _Visitor(self, document)\n            document.walkabout(visitor)\n\n            self.title = visitor.title or 'No title'\n        except:\n            Logger.exception('Rst: error while loading text')\n\n    def on_ref_press(self, node, ref):\n        self.goto(ref)\n\n    def goto(self, ref, *largs):\n        '''Scroll to the reference. If it's not found, nothing will be done.\n\n        For this text::\n\n            .. _myref:\n\n            This is something I always wanted.\n\n        You can do::\n\n            from kivy.clock import Clock\n            from functools import partial\n\n            doc = RstDocument(...)\n            Clock.schedule_once(partial(doc.goto, 'myref'), 0.1)\n\n        .. note::\n\n            It is preferable to delay the call of the goto if you just loaded\n            the document because the layout might not be finished or the\n            size of the RstDocument has not yet been determined. In\n            either case, the calculation of the scrolling would be\n            wrong.\n\n            You can, however, do a direct call if the document is already\n            loaded.\n\n        .. versionadded:: 1.3.0\n        '''\n        # check if it's a file ?\n        if ref.endswith('.rst'):\n            # whether it's a valid or invalid file, let source deal with it\n            self.source = ref\n            return\n\n        # get the association\n        ref = self.refs_assoc.get(ref, ref)\n\n        # search into all the nodes containing anchors\n        ax = ay = None\n        for node in self.anchors_widgets:\n            if ref in node.anchors:\n                ax, ay = node.anchors[ref]\n                break\n\n        # not found, stop here\n        if ax is None:\n            return\n\n        # found, calculate the real coordinate\n\n        # get the anchor coordinate inside widget space\n        ax += node.x\n        ay = node.top - ay\n        #ay += node.y\n\n        # what's the current coordinate for us?\n        sx, sy = self.scatter.x, self.scatter.top\n        #ax, ay = self.scatter.to_parent(ax, ay)\n\n        ay -= self.height\n\n        dx, dy = self.convert_distance_to_scroll(0, ay)\n        dy = max(0, min(1, dy))\n        Animation(scroll_y=dy, d=.25, t='in_out_expo').start(self)\n\n    def add_anchors(self, node):\n        self.anchors_widgets.append(node)\n\n\nclass RstTitle(Label):\n\n    section = NumericProperty(0)\n\n    document = ObjectProperty(None)\n\n\nclass RstParagraph(Label):\n\n    mx = NumericProperty(10)\n\n    my = NumericProperty(10)\n\n    document = ObjectProperty(None)\n\n\nclass RstTerm(AnchorLayout):\n\n    text = StringProperty('')\n\n    document = ObjectProperty(None)\n\n\nclass RstBlockQuote(GridLayout):\n    content = ObjectProperty(None)\n\n\nclass RstLiteralBlock(GridLayout):\n    content = ObjectProperty(None)\n\n\nclass RstList(GridLayout):\n    pass\n\n\nclass RstListItem(GridLayout):\n    content = ObjectProperty(None)\n\n\nclass RstListBullet(Label):\n\n    document = ObjectProperty(None)\n\n\nclass RstSystemMessage(GridLayout):\n    pass\n\n\nclass RstWarning(GridLayout):\n    content = ObjectProperty(None)\n\n\nclass RstNote(GridLayout):\n    content = ObjectProperty(None)\n\n\nclass RstImage(Image):\n    pass\n\n\nclass RstAsyncImage(AsyncImage):\n    pass\n\n\nclass RstDefinitionList(GridLayout):\n\n    document = ObjectProperty(None)\n\n\nclass RstDefinition(GridLayout):\n\n    document = ObjectProperty(None)\n\n\nclass RstFieldList(GridLayout):\n    pass\n\n\nclass RstFieldName(Label):\n\n    document = ObjectProperty(None)\n\n\nclass RstFieldBody(GridLayout):\n    pass\n\n\nclass RstGridLayout(GridLayout):\n    pass\n\n\nclass RstTable(GridLayout):\n    pass\n\n\nclass RstEntry(GridLayout):\n    pass\n\n\nclass RstTransition(Widget):\n    pass\n\n\nclass RstEmptySpace(Widget):\n    pass\n\n\nclass RstDefinitionSpace(Widget):\n\n    document = ObjectProperty(None)\n\n\nclass _ToctreeVisitor(nodes.NodeVisitor):\n\n    def __init__(self, *largs):\n        self.toctree = self.current = []\n        self.queue = []\n        self.text = ''\n        nodes.NodeVisitor.__init__(self, *largs)\n\n    def push(self, tree):\n        self.queue.append(tree)\n        self.current = tree\n\n    def pop(self):\n        self.current = self.queue.pop()\n\n    def dispatch_visit(self, node):\n        cls = node.__class__\n        if cls is nodes.section:\n            section = {\n                'ids': node['ids'],\n                'names': node['names'],\n                'title': '',\n                'children': []}\n            if isinstance(self.current, dict):\n                self.current['children'].append(section)\n            else:\n                self.current.append(section)\n            self.push(section)\n        elif cls is nodes.title:\n            self.text = ''\n        elif cls is nodes.Text:\n            self.text += node\n\n    def dispatch_departure(self, node):\n        cls = node.__class__\n        if cls is nodes.section:\n            self.pop()\n        elif cls is nodes.title:\n            self.current['title'] = self.text\n\n\nclass _Visitor(nodes.NodeVisitor):\n\n    def __init__(self, root, *largs):\n        self.root = root\n        self.title = None\n        self.current_list = []\n        self.current = None\n        self.idx_list = None\n        self.text = ''\n        self.text_have_anchor = False\n        self.section = 0\n        self.do_strip_text = False\n        nodes.NodeVisitor.__init__(self, *largs)\n\n    def push(self, widget):\n        self.current_list.append(self.current)\n        self.current = widget\n\n    def pop(self):\n        self.current = self.current_list.pop()\n\n    def dispatch_visit(self, node):\n        cls = node.__class__\n        if cls is nodes.document:\n            self.push(self.root.content)\n\n        elif cls is nodes.section:\n            self.section += 1\n\n        elif cls is nodes.title:\n            label = RstTitle(section=self.section, document=self.root)\n            self.current.add_widget(label)\n            self.push(label)\n            #assert(self.text == '')\n\n        elif cls is nodes.Text:\n            if self.do_strip_text:\n                node = node.replace('\\n', ' ')\n                node = node.replace('  ', ' ')\n                node = node.replace('\\t', ' ')\n                node = node.replace('  ', ' ')\n                if node.startswith(' '):\n                    node = ' ' + node.lstrip(' ')\n                if node.endswith(' '):\n                    node = node.rstrip(' ') + ' '\n                if self.text.endswith(' ') and node.startswith(' '):\n                    node = node[1:]\n            self.text += node\n\n        elif cls is nodes.paragraph:\n            self.do_strip_text = True\n            label = RstParagraph(document=self.root)\n            if isinstance(self.current, RstEntry):\n                label.mx = 10\n            self.current.add_widget(label)\n            self.push(label)\n\n        elif cls is nodes.literal_block:\n            box = RstLiteralBlock()\n            self.current.add_widget(box)\n            self.push(box)\n\n        elif cls is nodes.emphasis:\n            self.text += '[i]'\n\n        elif cls is nodes.strong:\n            self.text += '[b]'\n\n        elif cls is nodes.literal:\n            self.text += '[font=fonts/DroidSansMono.ttf]'\n\n        elif cls is nodes.block_quote:\n            box = RstBlockQuote()\n            self.current.add_widget(box)\n            self.push(box.content)\n            assert(self.text == '')\n\n        elif cls is nodes.enumerated_list:\n            box = RstList()\n            self.current.add_widget(box)\n            self.push(box)\n            self.idx_list = 0\n\n        elif cls is nodes.bullet_list:\n            box = RstList()\n            self.current.add_widget(box)\n            self.push(box)\n            self.idx_list = None\n\n        elif cls is nodes.list_item:\n            bullet = '-'\n            if self.idx_list is not None:\n                self.idx_list += 1\n                bullet = '%d.' % self.idx_list\n            bullet = self.colorize(bullet, 'bullet')\n            item = RstListItem()\n            self.current.add_widget(RstListBullet(\n                text=bullet, document=self.root))\n            self.current.add_widget(item)\n            self.push(item)\n\n        elif cls is nodes.system_message:\n            label = RstSystemMessage()\n            if self.root.show_errors:\n                self.current.add_widget(label)\n            self.push(label)\n\n        elif cls is nodes.warning:\n            label = RstWarning()\n            self.current.add_widget(label)\n            self.push(label.content)\n            assert(self.text == '')\n\n        elif cls is nodes.note:\n            label = RstNote()\n            self.current.add_widget(label)\n            self.push(label.content)\n            assert(self.text == '')\n\n        elif cls is nodes.image:\n            uri = node['uri']\n            if uri.startswith('/') and self.root.document_root:\n                uri = join(self.root.document_root, uri[1:])\n            if uri.startswith('http://') or uri.startswith('https://'):\n                image = RstAsyncImage(source=uri)\n            else:\n                image = RstImage(source=uri)\n\n            align = node.get('align', 'center')\n            root = AnchorLayout(size_hint_y=None, anchor_x=align, height=1)\n            image.bind(height=root.setter('height'))\n            root.add_widget(image)\n            self.current.add_widget(root)\n\n        elif cls is nodes.definition_list:\n            lst = RstDefinitionList(document=self.root)\n            self.current.add_widget(lst)\n            self.push(lst)\n\n        elif cls is nodes.term:\n            assert(isinstance(self.current, RstDefinitionList))\n            term = RstTerm(document=self.root)\n            self.current.add_widget(term)\n            self.push(term)\n\n        elif cls is nodes.definition:\n            assert(isinstance(self.current, RstDefinitionList))\n            definition = RstDefinition(document=self.root)\n            definition.add_widget(RstDefinitionSpace(document=self.root))\n            self.current.add_widget(definition)\n            self.push(definition)\n\n        elif cls is nodes.field_list:\n            fieldlist = RstFieldList()\n            self.current.add_widget(fieldlist)\n            self.push(fieldlist)\n\n        elif cls is nodes.field_name:\n            name = RstFieldName(document=self.root)\n            self.current.add_widget(name)\n            self.push(name)\n\n        elif cls is nodes.field_body:\n            body = RstFieldBody()\n            self.current.add_widget(body)\n            self.push(body)\n\n        elif cls is nodes.table:\n            table = RstTable(cols=0)\n            self.current.add_widget(table)\n            self.push(table)\n\n        elif cls is nodes.colspec:\n            self.current.cols += 1\n\n        elif cls is nodes.entry:\n            entry = RstEntry()\n            self.current.add_widget(entry)\n            self.push(entry)\n\n        elif cls is nodes.transition:\n            self.current.add_widget(RstTransition())\n\n        elif cls is nodes.reference:\n            name = node.get('name', node.get('refuri'))\n            self.text += '[ref=%s][color=%s]' % (\n                name, self.root.colors.get(\n                    'link', self.root.colors.get('paragraph')))\n            if 'refname' in node and 'name' in node:\n                self.root.refs_assoc[node['name']] = node['refname']\n\n        elif cls is nodes.target:\n            name = None\n            if 'ids' in node:\n                name = node['ids'][0]\n            elif 'names' in node:\n                name = node['names'][0]\n            self.text += '[anchor=%s]' % name\n            self.text_have_anchor = True\n\n        elif cls is role_doc:\n            self.doc_index = len(self.text)\n\n        elif cls is role_video:\n            pass\n\n    def dispatch_departure(self, node):\n        cls = node.__class__\n        if cls is nodes.document:\n            self.pop()\n\n        elif cls is nodes.section:\n            self.section -= 1\n\n        elif cls is nodes.title:\n            assert(isinstance(self.current, RstTitle))\n            if not self.title:\n                self.title = self.text\n            self.set_text(self.current, 'title')\n            self.pop()\n\n        elif cls is nodes.Text:\n            pass\n\n        elif cls is nodes.paragraph:\n            self.do_strip_text = False\n            assert(isinstance(self.current, RstParagraph))\n            self.set_text(self.current, 'paragraph')\n            self.pop()\n\n        elif cls is nodes.literal_block:\n            assert(isinstance(self.current, RstLiteralBlock))\n            self.set_text(self.current.content, 'literal_block')\n            self.pop()\n\n        elif cls is nodes.emphasis:\n            self.text += '[/i]'\n\n        elif cls is nodes.strong:\n            self.text += '[/b]'\n\n        elif cls is nodes.literal:\n            self.text += '[/font]'\n\n        elif cls is nodes.block_quote:\n            self.pop()\n\n        elif cls is nodes.enumerated_list:\n            self.idx_list = None\n            self.pop()\n\n        elif cls is nodes.bullet_list:\n            self.pop()\n\n        elif cls is nodes.list_item:\n            self.pop()\n\n        elif cls is nodes.system_message:\n            self.pop()\n\n        elif cls is nodes.warning:\n            self.pop()\n\n        elif cls is nodes.note:\n            self.pop()\n\n        elif cls is nodes.definition_list:\n            self.pop()\n\n        elif cls is nodes.term:\n            assert(isinstance(self.current, RstTerm))\n            self.set_text(self.current, 'term')\n            self.pop()\n\n        elif cls is nodes.definition:\n            self.pop()\n\n        elif cls is nodes.field_list:\n            self.pop()\n\n        elif cls is nodes.field_name:\n            assert(isinstance(self.current, RstFieldName))\n            self.set_text(self.current, 'field_name')\n            self.pop()\n\n        elif cls is nodes.field_body:\n            self.pop()\n\n        elif cls is nodes.table:\n            self.pop()\n\n        elif cls is nodes.colspec:\n            pass\n\n        elif cls is nodes.entry:\n            self.pop()\n\n        elif cls is nodes.reference:\n            self.text += '[/color][/ref]'\n\n        elif cls is role_doc:\n            docname = self.text[self.doc_index:]\n            rst_docname = docname\n            if rst_docname.endswith('.rst'):\n                docname = docname[:-4]\n            else:\n                rst_docname += '.rst'\n\n            # try to preload it\n            filename = self.root.resolve_path(rst_docname)\n            self.root.preload(filename)\n\n            # if exist, use the title of the first section found in the\n            # document\n            title = docname\n            if filename in self.root.toctrees:\n                toctree = self.root.toctrees[filename]\n                if len(toctree):\n                    title = toctree[0]['title']\n\n            # replace the text with a good reference\n            text = '[ref=%s]%s[/ref]' % (\n                rst_docname,\n                self.colorize(title, 'link'))\n            self.text = self.text[:self.doc_index] + text\n\n        elif cls is role_video:\n            width = node['width'] if 'width' in node.attlist() else 400\n            height = node['height'] if 'height' in node.attlist() else 300\n            uri = node['source']\n            if uri.startswith('/') and self.root.document_root:\n                uri = join(self.root.document_root, uri[1:])\n            video = RstVideoPlayer(\n                source=uri,\n                size_hint=(None, None),\n                size=(width, height))\n            anchor = AnchorLayout(size_hint_y=None, height=height + 20)\n            anchor.add_widget(video)\n            self.current.add_widget(anchor)\n\n    def set_text(self, node, parent):\n        text = self.text\n        if parent == 'term' or parent == 'field_name':\n            text = '[b]%s[/b]' % text\n        # search anchors\n        node.text = self.colorize(text, parent)\n        node.bind(on_ref_press=self.root.on_ref_press)\n        if self.text_have_anchor:\n            self.root.add_anchors(node)\n        self.text = ''\n        self.text_have_anchor = False\n\n    def colorize(self, text, name):\n        return '[color=%s]%s[/color]' % (\n            self.root.colors.get(name, self.root.colors['paragraph']),\n            text)\n\nif __name__ == '__main__':\n    from kivy.base import runTouchApp\n    import sys\n    runTouchApp(RstDocument(source=sys.argv[1]))\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/sandbox.py",
    "content": "'''\nSandbox\n=======\n\n.. versionadded:: 1.8.0\n\n.. warning::\n\n    This is experimental and subject to change as long as this warning notice\n    is present.\n\nThis is a widget that runs itself and all of its children in a Sandbox. That\nmeans if a child raises an Exception, it will be caught. The Sandbox\nitself runs its own Clock, Cache, etc.\n\nThe SandBox widget is still experimental and required for the Kivy designer.\nWhen the user designs their own widget, if they do something wrong (wrong size\nvalue, invalid python code), it will be caught correctly without breaking\nthe whole application. Because it has been designed that way, we are still\nenhancing this widget and the :mod:`kivy.context` module.\nDon't use it unless you know what you are doing.\n\n'''\n\n__all__ = ('Sandbox', )\n\nfrom kivy.context import Context\nfrom kivy.base import ExceptionManagerBase\nfrom kivy.clock import Clock\nfrom kivy.uix.widget import Widget\nfrom kivy.uix.floatlayout import FloatLayout\nfrom kivy.uix.relativelayout import RelativeLayout\nfrom kivy.lang import Builder\n\n\ndef sandbox(f):\n    def _f2(self, *args, **kwargs):\n        ret = None\n        with self:\n            ret = f(self, *args, **kwargs)\n        return ret\n    return _f2\n\n\nclass SandboxExceptionManager(ExceptionManagerBase):\n\n    def __init__(self, sandbox):\n        ExceptionManagerBase.__init__(self)\n        self.sandbox = sandbox\n\n    def handle_exception(self, e):\n        if not self.sandbox.on_exception(e):\n            return ExceptionManagerBase.RAISE\n        return ExceptionManagerBase.PASS\n\n\nclass SandboxContent(RelativeLayout):\n    pass\n\n\nclass Sandbox(FloatLayout):\n    '''Sandbox widget, used to trap all the exceptions raised by child\n    widgets.\n    '''\n\n    def __init__(self, **kwargs):\n        self._context = Context(init=True)\n        self._context['ExceptionManager'] = SandboxExceptionManager(self)\n        self._context.sandbox = self\n        self._context.push()\n        self.on_context_created()\n        self._container = None\n        super(Sandbox, self).__init__(**kwargs)\n        self._container = SandboxContent(size=self.size, pos=self.pos)\n        super(Sandbox, self).add_widget(self._container)\n        self._context.pop()\n\n        # force SandboxClock's scheduling\n        Clock.schedule_interval(self._clock_sandbox, 0)\n        Clock.schedule_once(self._clock_sandbox_draw, -1)\n        self.main_clock = object.__getattribute__(Clock, '_obj')\n\n    def __enter__(self):\n        self._context.push()\n\n    def __exit__(self, _type, value, traceback):\n        self._context.pop()\n        if _type is not None:\n            return self.on_exception(value, _traceback=traceback)\n\n    def on_context_created(self):\n        '''Override this method in order to load your kv file or do anything\n        else with the newly created context.\n        '''\n        pass\n\n    def on_exception(self, exception, _traceback=None):\n        '''Override this method in order to catch all the exceptions from\n        children.\n\n        If you return True, it will not reraise the exception.\n        If you return False, the exception will be raised to the parent.\n        '''\n        import traceback\n        traceback.print_tb(_traceback)\n        return True\n\n    on_touch_down = sandbox(Widget.on_touch_down)\n    on_touch_move = sandbox(Widget.on_touch_move)\n    on_touch_up = sandbox(Widget.on_touch_up)\n\n    @sandbox\n    def add_widget(self, *args, **kwargs):\n        self._container.add_widget(*args, **kwargs)\n\n    @sandbox\n    def remove_widget(self, *args, **kwargs):\n        self._container.remove_widget(*args, **kwargs)\n\n    @sandbox\n    def clear_widgets(self, *args, **kwargs):\n        self._container.clear_widgets()\n\n    @sandbox\n    def on_size(self, *args):\n        if self._container:\n            self._container.size = self.size\n\n    @sandbox\n    def on_pos(self, *args):\n        if self._container:\n            self._container.pos = self.pos\n\n    @sandbox\n    def _clock_sandbox(self, dt):\n        #import pdb; pdb.set_trace()\n        Clock.tick()\n        Builder.sync()\n\n    @sandbox\n    def _clock_sandbox_draw(self, dt):\n        Clock.tick_draw()\n        Builder.sync()\n        self.main_clock.schedule_once(self._call_draw, 0)\n\n    def _call_draw(self, dt):\n        self.main_clock.schedule_once(self._clock_sandbox_draw, -1)\n\nif __name__ == '__main__':\n    from kivy.base import runTouchApp\n    from kivy.uix.button import Button\n\n    class TestButton(Button):\n\n        def on_touch_up(self, touch):\n            #raise Exception('fdfdfdfdfdfdfd')\n            return super(TestButton, self).on_touch_up(touch)\n\n        def on_touch_down(self, touch):\n            #raise Exception('')\n            return super(TestButton, self).on_touch_down(touch)\n\n    s = Sandbox()\n    with s:\n        Builder.load_string('''\n<TestButton>:\n    canvas:\n        Color:\n            rgb: (.3, .2, 0) if self.state == 'normal' else (.7, .7, 0)\n        Rectangle:\n            pos: self.pos\n            size: self.size\n        Color:\n            rgb: 1, 1, 1\n        Rectangle:\n            size: self.texture_size\n            pos: self.center_x - self.texture_size[0] / 2.,\\\n                 self.center_y - self.texture_size[1] / 2.\n            texture: self.texture\n\n    # invalid... for testing.\n    #on_touch_up: root.d()\n    #on_touch_down: root.f()\n    on_release: root.args()\n    #on_press: root.args()\n''')\n        b = TestButton(text='Hello World')\n        s.add_widget(b)\n\n        # this exception is within the \"with\" block, but will be ignored by\n        # default because the sandbox on_exception will return True\n        raise Exception('hello')\n\n    runTouchApp(s)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/scatter.py",
    "content": "'''\nScatter\n=======\n\n:class:`Scatter` is used to build interactive widgets that can be translated,\nrotated and scaled with two or more fingers on a multitouch system.\n\nScatter has its own matrix transformation: the modelview matrix is changed\nbefore the children are drawn and the previous matrix is restored when the\ndrawing is finished. That makes it possible to perform rotation, scaling and\ntranslation over the entire children tree without changing any widget\nproperties. That specific behavior makes the scatter unique, but there are some\nadvantages / constraints that you should consider:\n\n#. The children are positioned relative to the scatter similar to a\n   RelativeLayout (see :mod:`~kivy.uix.relativelayout`). So when dragging the\n   scatter, the position of the children don't change, only the position of\n   the scatter does.\n#. The scatter size has no impact on the size of it's children.\n#. If you want to resize the scatter, use scale, not size (read #2). Scale\n   transforms both the scatter and its children, but does not change size.\n#. The scatter is not a layout. You must manage the size of the children\n   yourself.\n\nFor touch events, the scatter converts from the parent matrix to the scatter\nmatrix automatically in on_touch_down/move/up events. If you are doing things\nmanually, you will need to use :meth:`~kivy.uix.widget.Widget.to_parent` and\n:meth:`~kivy.uix.widget.Widget.to_local`.\n\nUsage\n-----\n\nBy default, the Scatter does not have a graphical representation: it is a\ncontainer only. The idea is to combine the Scatter with another widget, for\nexample an :class:`~kivy.uix.image.Image`::\n\n    scatter = Scatter()\n    image = Image(source='sun.jpg')\n    scatter.add_widget(image)\n\nControl Interactions\n--------------------\n\nBy default, all interactions are enabled. You can selectively disable\nthem using the do_rotation, do_translation and do_scale properties.\n\nDisable rotation::\n\n    scatter = Scatter(do_rotation=False)\n\nAllow only translation::\n\n    scatter = Scatter(do_rotation=False, do_scale=False)\n\nAllow only translation on x axis::\n\n    scatter = Scatter(do_rotation=False, do_scale=False,\n                      do_translation_y=False)\n\n\nAutomatic Bring to Front\n------------------------\n\nIf the :attr:`Scatter.auto_bring_to_front` property is True, the scatter\nwidget will be removed and re-added to the parent when it is touched\n(brought to front, above all other widgets in the parent). This is useful\nwhen you are manipulating several scatter widgets and don't want the active\none to be partially hidden.\n\nScale Limitation\n----------------\n\nWe are using a 32-bit matrix in double representation. That means we have\na limit for scaling. You cannot do infinite scaling down/up with our\nimplementation. Generally, you don't hit the minimum scale (because you don't\nsee it on the screen), but the maximum scale is 9.99506983235e+19 (2^66).\n\nYou can also limit the minimum and maximum scale allowed::\n\n    scatter = Scatter(scale_min=.5, scale_max=3.)\n\nBehavior\n--------\n\n.. versionchanged:: 1.1.0\n    If no control interactions are enabled, then the touch handler will never\n    return True.\n\n'''\n\n__all__ = ('Scatter', 'ScatterPlane')\n\nfrom math import radians\nfrom kivy.properties import BooleanProperty, AliasProperty, \\\n    NumericProperty, ObjectProperty, BoundedNumericProperty\nfrom kivy.vector import Vector\nfrom kivy.uix.widget import Widget\nfrom kivy.graphics.transformation import Matrix\n\n\nclass Scatter(Widget):\n    '''Scatter class. See module documentation for more information.\n\n    :Events:\n        `on_transform_with_touch`:\n            Fired when the scatter has been transformed by user touch\n            or multitouch, such as panning or zooming.\n        `on_bring_to_front`:\n            Fired when the scatter is brought to the front.\n\n    .. versionchanged:: 1.9.0\n        Event `on_bring_to_front` added.\n\n    .. versionchanged:: 1.8.0\n        Event `on_transform_with_touch` added.\n    '''\n\n    __events__ = ('on_transform_with_touch', 'on_bring_to_front')\n\n    auto_bring_to_front = BooleanProperty(True)\n    '''If True, the widget will be automatically pushed on the top of parent\n    widget list for drawing.\n\n    :attr:`auto_bring_to_front` is a :class:`~kivy.properties.BooleanProperty`\n    and defaults to True.\n    '''\n\n    do_translation_x = BooleanProperty(True)\n    '''Allow translation on the X axis.\n\n    :attr:`do_translation_x` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n\n    do_translation_y = BooleanProperty(True)\n    '''Allow translation on Y axis.\n\n    :attr:`do_translation_y` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n\n    def _get_do_translation(self):\n        return (self.do_translation_x, self.do_translation_y)\n\n    def _set_do_translation(self, value):\n        if type(value) in (list, tuple):\n            self.do_translation_x, self.do_translation_y = value\n        else:\n            self.do_translation_x = self.do_translation_y = bool(value)\n    do_translation = AliasProperty(\n        _get_do_translation, _set_do_translation,\n        bind=('do_translation_x', 'do_translation_y'))\n    '''Allow translation on the X or Y axis.\n\n    :attr:`do_translation` is an :class:`~kivy.properties.AliasProperty` of\n    (:attr:`do_translation_x` + :attr:`do_translation_y`)\n    '''\n\n    translation_touches = BoundedNumericProperty(1, min=1)\n    '''Determine whether translation was triggered by a single or multiple\n    touches. This only has effect when :attr:`do_translation` = True.\n\n    :attr:`translation_touches` is a :class:`~kivy.properties.NumericProperty`\n    and defaults to 1.\n\n    .. versionadded:: 1.7.0\n    '''\n\n    do_rotation = BooleanProperty(True)\n    '''Allow rotation.\n\n    :attr:`do_rotation` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n\n    do_scale = BooleanProperty(True)\n    '''Allow scaling.\n\n    :attr:`do_scale` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n\n    do_collide_after_children = BooleanProperty(False)\n    '''If True, the collision detection for limiting the touch inside the\n    scatter will be done after dispaching the touch to the children.\n    You can put children outside the bounding box of the scatter and still be\n    able to touch them.\n\n    .. versionadded:: 1.3.0\n    '''\n\n    scale_min = NumericProperty(0.01)\n    '''Minimum scaling factor allowed.\n\n    :attr:`scale_min` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.01.\n    '''\n\n    scale_max = NumericProperty(1e20)\n    '''Maximum scaling factor allowed.\n\n    :attr:`scale_max` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 1e20.\n    '''\n\n    transform = ObjectProperty(Matrix())\n    '''Transformation matrix.\n\n    :attr:`transform` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to the identity matrix.\n\n    .. note::\n\n        This matrix reflects the current state of the transformation matrix\n        but setting it directly will erase previously applied\n        transformations. To apply a transformation considering context,\n        please use the :attr:`~Scatter.apply_transform` method.\n\n    '''\n\n    transform_inv = ObjectProperty(Matrix())\n    '''Inverse of the transformation matrix.\n\n    :attr:`transform_inv` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to the identity matrix.\n    '''\n\n    def _get_bbox(self):\n        xmin, ymin = xmax, ymax = self.to_parent(0, 0)\n        for point in [(self.width, 0), (0, self.height), self.size]:\n            x, y = self.to_parent(*point)\n            if x < xmin:\n                xmin = x\n            if y < ymin:\n                ymin = y\n            if x > xmax:\n                xmax = x\n            if y > ymax:\n                ymax = y\n        return (xmin, ymin), (xmax - xmin, ymax - ymin)\n    bbox = AliasProperty(_get_bbox, None, bind=(\n        'transform', 'width', 'height'))\n    '''Bounding box of the widget in parent space::\n\n        ((x, y), (w, h))\n        # x, y = lower left corner\n\n    :attr:`bbox` is an :class:`~kivy.properties.AliasProperty`.\n    '''\n\n    def _get_rotation(self):\n        v1 = Vector(0, 10)\n        tp = self.to_parent\n        v2 = Vector(*tp(*self.pos)) - tp(self.x, self.y + 10)\n        return -1.0 * (v1.angle(v2) + 180) % 360\n\n    def _set_rotation(self, rotation):\n        angle_change = self.rotation - rotation\n        r = Matrix().rotate(-radians(angle_change), 0, 0, 1)\n        self.apply_transform(r, post_multiply=True,\n                             anchor=self.to_local(*self.center))\n    rotation = AliasProperty(_get_rotation, _set_rotation, bind=(\n        'x', 'y', 'transform'))\n    '''Rotation value of the scatter.\n\n    :attr:`rotation` is an :class:`~kivy.properties.AliasProperty` and defaults\n    to 0.0.\n    '''\n\n    def _get_scale(self):\n        p1 = Vector(*self.to_parent(0, 0))\n        p2 = Vector(*self.to_parent(1, 0))\n        scale = p1.distance(p2)\n\n        # XXX float calculation are not accurate, and then, scale can be\n        # throwed again even with only the position change. So to\n        # prevent anything wrong with scale, just avoid to dispatch it\n        # if the scale \"visually\" didn't change. #947\n        # Remove this ugly hack when we'll be Python 3 only.\n        if hasattr(self, '_scale_p'):\n            if str(scale) == str(self._scale_p):\n                return self._scale_p\n\n        self._scale_p = scale\n        return scale\n\n    def _set_scale(self, scale):\n        rescale = scale * 1.0 / self.scale\n        self.apply_transform(Matrix().scale(rescale, rescale, rescale),\n                             post_multiply=True,\n                             anchor=self.to_local(*self.center))\n    scale = AliasProperty(_get_scale, _set_scale, bind=('x', 'y', 'transform'))\n    '''Scale value of the scatter.\n\n    :attr:`scale` is an :class:`~kivy.properties.AliasProperty` and defaults to\n    1.0.\n    '''\n\n    def _get_center(self):\n        return (self.bbox[0][0] + self.bbox[1][0] / 2.0,\n                self.bbox[0][1] + self.bbox[1][1] / 2.0)\n\n    def _set_center(self, center):\n        if center == self.center:\n            return False\n        t = Vector(*center) - self.center\n        trans = Matrix().translate(t.x, t.y, 0)\n        self.apply_transform(trans)\n    center = AliasProperty(_get_center, _set_center, bind=('bbox', ))\n\n    def _get_pos(self):\n        return self.bbox[0]\n\n    def _set_pos(self, pos):\n        _pos = self.bbox[0]\n        if pos == _pos:\n            return\n        t = Vector(*pos) - _pos\n        trans = Matrix().translate(t.x, t.y, 0)\n        self.apply_transform(trans)\n    pos = AliasProperty(_get_pos, _set_pos, bind=('bbox', ))\n\n    def _get_x(self):\n        return self.bbox[0][0]\n\n    def _set_x(self, x):\n        if x == self.bbox[0][0]:\n            return False\n        self.pos = (x, self.y)\n        return True\n    x = AliasProperty(_get_x, _set_x, bind=('bbox', ))\n\n    def _get_y(self):\n        return self.bbox[0][1]\n\n    def _set_y(self, y):\n        if y == self.bbox[0][1]:\n            return False\n        self.pos = (self.x, y)\n        return True\n    y = AliasProperty(_get_y, _set_y, bind=('bbox', ))\n\n    def get_right(self):\n        return self.x + self.bbox[1][0]\n\n    def set_right(self, value):\n        self.x = value - self.bbox[1][0]\n\n    right = AliasProperty(get_right, set_right, bind=('x', 'width'))\n\n    def get_top(self):\n        return self.y + self.bbox[1][1]\n\n    def set_top(self, value):\n        self.y = value - self.bbox[1][1]\n\n    top = AliasProperty(get_top, set_top, bind=('y', 'height'))\n\n    def get_center_x(self):\n        return self.x + self.bbox[1][0] / 2.\n\n    def set_center_x(self, value):\n        self.x = value - self.bbox[1][0] / 2.\n    center_x = AliasProperty(get_center_x, set_center_x, bind=('x', 'width'))\n\n    def get_center_y(self):\n        return self.y + self.bbox[1][1] / 2.\n\n    def set_center_y(self, value):\n        self.y = value - self.bbox[1][1] / 2.\n    center_y = AliasProperty(get_center_y, set_center_y, bind=('y', 'height'))\n\n    def __init__(self, **kwargs):\n        self._touches = []\n        self._last_touch_pos = {}\n        super(Scatter, self).__init__(**kwargs)\n\n    def on_transform(self, instance, value):\n        self.transform_inv = value.inverse()\n\n    def collide_point(self, x, y):\n        x, y = self.to_local(x, y)\n        return 0 <= x <= self.width and 0 <= y <= self.height\n\n    def to_parent(self, x, y, **k):\n        p = self.transform.transform_point(x, y, 0)\n        return (p[0], p[1])\n\n    def to_local(self, x, y, **k):\n        p = self.transform_inv.transform_point(x, y, 0)\n        return (p[0], p[1])\n\n    def _apply_transform(self, m):\n        m = self.transform.multiply(m)\n        return super(Scatter, self)._apply_transform(m)\n\n    def apply_transform(self, trans, post_multiply=False, anchor=(0, 0)):\n        '''\n        Transforms the scatter by applying the \"trans\" transformation\n        matrix (on top of its current transformation state). The resultant\n        matrix can be found in the :attr:`~Scatter.transform` property.\n\n        :Parameters:\n            `trans`: :class:`~kivy.graphics.transformation.Matrix`.\n                Transformation matix to be applied to the scatter widget.\n            `anchor`: tuple, defaults to (0, 0).\n                The point to use as the origin of the transformation\n                (uses local widget space).\n            `post_multiply`: bool, defaults to False.\n                If True, the transform matrix is post multiplied\n                (as if applied before the current transform).\n\n        Usage example::\n\n            from kivy.graphics.transformation import Matrix\n            mat = Matrix().scale(3, 3, 3)\n            scatter_instance.apply_transform(mat)\n\n        '''\n        t = Matrix().translate(anchor[0], anchor[1], 0)\n        t = t.multiply(trans)\n        t = t.multiply(Matrix().translate(-anchor[0], -anchor[1], 0))\n\n        if post_multiply:\n            self.transform = self.transform.multiply(t)\n        else:\n            self.transform = t.multiply(self.transform)\n\n    def transform_with_touch(self, touch):\n        # just do a simple one finger drag\n        changed = False\n        if len(self._touches) == self.translation_touches:\n            # _last_touch_pos has last pos in correct parent space,\n            # just like incoming touch\n            dx = (touch.x - self._last_touch_pos[touch][0]) \\\n                * self.do_translation_x\n            dy = (touch.y - self._last_touch_pos[touch][1]) \\\n                * self.do_translation_y\n            dx = dx / self.translation_touches\n            dy = dy / self.translation_touches\n            self.apply_transform(Matrix().translate(dx, dy, 0))\n            changed = True\n\n        if len(self._touches) == 1:\n            return changed\n\n        # we have more than one touch... list of last known pos\n        points = [Vector(self._last_touch_pos[t]) for t in self._touches\n                  if t is not touch]\n        # add current touch last\n        points.append(Vector(touch.pos))\n\n        # we only want to transform if the touch is part of the two touches\n        # farthest apart! So first we find anchor, the point to transform\n        # around as another touch farthest away from current touch's pos\n        anchor = max(points[:-1], key=lambda p: p.distance(touch.pos))\n\n        # now we find the touch farthest away from anchor, if its not the\n        # same as touch. Touch is not one of the two touches used to transform\n        farthest = max(points, key=anchor.distance)\n        if farthest is not points[-1]:\n            return changed\n\n        # ok, so we have touch, and anchor, so we can actually compute the\n        # transformation\n        old_line = Vector(*touch.ppos) - anchor\n        new_line = Vector(*touch.pos) - anchor\n        if not old_line.length():   # div by zero\n            return changed\n\n        angle = radians(new_line.angle(old_line)) * self.do_rotation\n        self.apply_transform(Matrix().rotate(angle, 0, 0, 1), anchor=anchor)\n\n        if self.do_scale:\n            scale = new_line.length() / old_line.length()\n            new_scale = scale * self.scale\n            if new_scale < self.scale_min:\n                scale = self.scale_min / self.scale\n            elif new_scale > self.scale_max:\n                scale = self.scale_max / self.scale\n            self.apply_transform(Matrix().scale(scale, scale, scale),\n                                 anchor=anchor)\n            changed = True\n        return changed\n\n    def _bring_to_front(self, touch):\n        # auto bring to front\n        if self.auto_bring_to_front and self.parent:\n            parent = self.parent\n            if parent.children[0] is self:\n                return\n            parent.remove_widget(self)\n            parent.add_widget(self)\n            self.dispatch('on_bring_to_front', touch)\n\n    def on_touch_down(self, touch):\n        x, y = touch.x, touch.y\n\n        # if the touch isnt on the widget we do nothing\n        if not self.do_collide_after_children:\n            if not self.collide_point(x, y):\n                return False\n\n        # let the child widgets handle the event if they want\n        touch.push()\n        touch.apply_transform_2d(self.to_local)\n        if super(Scatter, self).on_touch_down(touch):\n            # ensure children don't have to do it themselves\n            if 'multitouch_sim' in touch.profile:\n                touch.multitouch_sim = True\n            touch.pop()\n            self._bring_to_front(touch)\n            return True\n        touch.pop()\n\n        # if our child didn't do anything, and if we don't have any active\n        # interaction control, then don't accept the touch.\n        if not self.do_translation_x and \\\n                not self.do_translation_y and \\\n                not self.do_rotation and \\\n                not self.do_scale:\n            return False\n\n        if self.do_collide_after_children:\n            if not self.collide_point(x, y):\n                return False\n\n        if 'multitouch_sim' in touch.profile:\n            touch.multitouch_sim = True\n        # grab the touch so we get all it later move events for sure\n        self._bring_to_front(touch)\n        touch.grab(self)\n        self._touches.append(touch)\n        self._last_touch_pos[touch] = touch.pos\n\n        return True\n\n    def on_touch_move(self, touch):\n        x, y = touch.x, touch.y\n        # let the child widgets handle the event if they want\n        if self.collide_point(x, y) and not touch.grab_current == self:\n            touch.push()\n            touch.apply_transform_2d(self.to_local)\n            if super(Scatter, self).on_touch_move(touch):\n                touch.pop()\n                return True\n            touch.pop()\n\n        # rotate/scale/translate\n        if touch in self._touches and touch.grab_current == self:\n            if self.transform_with_touch(touch):\n                self.dispatch('on_transform_with_touch', touch)\n            self._last_touch_pos[touch] = touch.pos\n\n        # stop propagating if its within our bounds\n        if self.collide_point(x, y):\n            return True\n\n    def on_transform_with_touch(self, touch):\n        '''\n        Called when a touch event has transformed the scatter widget.\n        By default this does nothing, but can be overriden by derived\n        classes that need to react to transformations caused by user\n        input.\n\n        :Parameters:\n            `touch`: the touch object which triggered the transformation.\n\n        .. versionadded:: 1.8.0\n        '''\n        pass\n\n    def on_bring_to_front(self, touch):\n        '''\n        Called when a touch event causes the scatter to be brought to the\n        front of the parent (only if :attr:`auto_bring_to_front` is True)\n\n        :Parameters:\n            `touch`: the touch object which brought the scatter to front.\n\n        .. versionadded:: 1.9.0\n        '''\n        pass\n\n    def on_touch_up(self, touch):\n        x, y = touch.x, touch.y\n        # if the touch isnt on the widget we do nothing, just try children\n        if not touch.grab_current == self:\n            touch.push()\n            touch.apply_transform_2d(self.to_local)\n            if super(Scatter, self).on_touch_up(touch):\n                touch.pop()\n                return True\n            touch.pop()\n\n        # remove it from our saved touches\n        if touch in self._touches and touch.grab_state:\n            touch.ungrab(self)\n            del self._last_touch_pos[touch]\n            self._touches.remove(touch)\n\n        # stop propagating if its within our bounds\n        if self.collide_point(x, y):\n            return True\n\n\nclass ScatterPlane(Scatter):\n    '''This is essentially an unbounded Scatter widget. It's a convenience\n       class to make it easier to handle infinite planes.\n    '''\n\n    def __init__(self, **kwargs):\n        kwargs.setdefault('auto_bring_to_front', False)\n        super(ScatterPlane, self).__init__(**kwargs)\n\n    def collide_point(self, x, y):\n        return True\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/scatterlayout.py",
    "content": "'''\nScatter Layout\n===============\n\n.. versionadded:: 1.6.0\n\nThis layout behaves just like a\n:class:`~kivy.uix.relativelayout.RelativeLayout`.\nWhen a widget is added with position = (0,0) to a :class:`ScatterLayout`,\nthe child widget will also move when you change the position of the\n:class:`ScatterLayout`. The child widget's coordinates remain\n(0,0) as they are relative to the parent layout.\n\nHowever, since :class:`ScatterLayout` is implemented using a\n:class:`~kivy.uix.scatter.Scatter`\nwidget, you can also translate, rotate and scale the layout using touches\nor clicks, just like in the case of a normal Scatter widget, and the child\nwidgets will behave as expected.\n\nIn contrast to a Scatter, the Layout favours 'hint' properties, such as\nsize_hint, size_hint_x, size_hint_y and pos_hint.\n\n.. note::\n\n    The :class:`ScatterLayout` is implemented as a\n    :class:`~kivy.uix.floatlayout.FloatLayout`\n    inside a :class:`~kivy.uix.scatter.Scatter`.\n\n.. warning::\n\n    Since the actual :class:`ScatterLayout` is a\n    :class:`~kivy.uix.scatter.Scatter`, its\n    add_widget and remove_widget functions are overridden to add children\n    to the embedded :class:`~kivy.uix.floatlayout.FloatLayout` (accessible as\n    the `content` property of :class:`~kivy.uix.scatter.Scatter`)\n    automatically. So if you want to access the added child elements,\n    you need self.content.children instead of self.children.\n\n.. warning::\n\n    The :class:`ScatterLayout` was introduced in 1.7.0 and was called\n    :class:`~kivy.uix.relativelayout.RelativeLayout` in prior versions.\n    The :class:`~kivy.uix.relativelayout.RelativeLayout` is now an optimized\n    implementation that uses only a positional transform to avoid some of the\n    heavier calculation involved for :class:`~kivy.uix.scatter.Scatter`.\n\n'''\n\n__all__ = ('ScatterLayout', 'ScatterPlaneLayout')\n\nfrom kivy.uix.floatlayout import FloatLayout\nfrom kivy.uix.scatter import Scatter, ScatterPlane\nfrom kivy.properties import ObjectProperty\n\n\nclass ScatterLayout(Scatter):\n    '''ScatterLayout class, see module documentation for more information.\n    '''\n\n    content = ObjectProperty()\n\n    def __init__(self, **kw):\n        self.content = FloatLayout()\n        super(ScatterLayout, self).__init__(**kw)\n        if self.content.size != self.size:\n            self.content.size = self.size\n        super(ScatterLayout, self).add_widget(self.content)\n        self.bind(size=self.update_size)\n\n    def update_size(self, instance, size):\n        self.content.size = size\n\n    def add_widget(self, *l):\n        self.content.add_widget(*l)\n\n    def remove_widget(self, *l):\n        self.content.remove_widget(*l)\n\n    def clear_widgets(self):\n        self.content.clear_widgets()\n\n\nclass ScatterPlaneLayout(ScatterPlane):\n    '''ScatterPlaneLayout class, see module documentation for more information.\n\n    Similar to ScatterLayout, but based on ScatterPlane - so the input is not\n    bounded.\n\n    .. versionadded:: 1.9.0\n    '''\n\n    def __init__(self, **kwargs):\n        kwargs.setdefault('auto_bring_to_front', False)\n        super(ScatterPlaneLayout, self).__init__(**kwargs)\n\n    def collide_point(self, x, y):\n        return True\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/screenmanager.py",
    "content": "'''Screen Manager\n==============\n\n.. versionadded:: 1.4.0\n\nThe screen manager is a widget dedicated to managing multiple screens for your\napplication. The default :class:`ScreenManager` displays only one\n:class:`Screen` at a time and uses a :class:`TransitionBase` to switch from one\nScreen to another.\n\nMultiple transitions are supported based on changing the screen coordinates /\nscale or even performing fancy animation using custom shaders.\n\nBasic Usage\n-----------\n\nLet's construct a Screen Manager with 4 named screens. When you are creating\na screen, **you absolutely need to give a name to it**::\n\n    from kivy.uix.screenmanager import ScreenManager, Screen\n\n    # Create the manager\n    sm = ScreenManager()\n\n    # Add few screens\n    for i in range(4):\n        screen = Screen(name='Title %d' % i)\n        sm.add_widget(screen)\n\n    # By default, the first screen added into the ScreenManager will be\n    # displayed. You can then change to another screen.\n\n    # Let's display the screen named 'Title 2'\n    # A transition will automatically be used.\n    sm.current = 'Title 2'\n\nThe default :attr:`ScreenManager.transition` is a :class:`SlideTransition` with\noptions :attr:`~SlideTransition.direction` and\n:attr:`~TransitionBase.duration`.\n\nPlease note that by default, a :class:`Screen` displays nothing: it's just a\n:class:`~kivy.uix.relativelayout.RelativeLayout`. You need to use that class as\na root widget for your own screen, the best way being to subclass.\n\n.. warning::\n    As :class:`Screen` is a :class:`~kivy.uix.relativelayout.RelativeLayout`,\n    it is important to understand the\n    :ref:`kivy-uix-relativelayout-common-pitfalls`.\n\nHere is an example with a 'Menu Screen' and a 'Settings Screen'::\n\n    from kivy.app import App\n    from kivy.lang import Builder\n    from kivy.uix.screenmanager import ScreenManager, Screen\n\n    # Create both screens. Please note the root.manager.current: this is how\n    # you can control the ScreenManager from kv. Each screen has by default a\n    # property manager that gives you the instance of the ScreenManager used.\n    Builder.load_string(\"\"\"\n    <MenuScreen>:\n        BoxLayout:\n            Button:\n                text: 'Goto settings'\n                on_press: root.manager.current = 'settings'\n            Button:\n                text: 'Quit'\n\n    <SettingsScreen>:\n        BoxLayout:\n            Button:\n                text: 'My settings button'\n            Button:\n                text: 'Back to menu'\n                on_press: root.manager.current = 'menu'\n    \"\"\")\n\n    # Declare both screens\n    class MenuScreen(Screen):\n        pass\n\n    class SettingsScreen(Screen):\n        pass\n\n    # Create the screen manager\n    sm = ScreenManager()\n    sm.add_widget(MenuScreen(name='menu'))\n    sm.add_widget(SettingsScreen(name='settings'))\n\n    class TestApp(App):\n\n        def build(self):\n            return sm\n\n    if __name__ == '__main__':\n        TestApp().run()\n\n\nChanging Direction\n------------------\n\nA common use case for :class:`ScreenManager` involves using a\n:class:`SlideTransition` which slides right to the next screen\nand slides left to the previous screen. Building on the previous\nexample, this can be accomplished like so::\n\n    Builder.load_string(\"\"\"\n    <MenuScreen>:\n        BoxLayout:\n            Button:\n                text: 'Goto settings'\n                on_press:\n                    root.manager.transition.direction = 'left'\n                    root.manager.current = 'settings'\n            Button:\n                text: 'Quit'\n\n    <SettingScreen>:\n        BoxLayout:\n            Button:\n                text: 'My settings button'\n            Button:\n                text: 'Back to menu'\n                on_press:\n                    root.manager.transition.direction = 'right'\n                    root.manager.current = 'menu'\n    \"\"\")\n\n\nAdvanced Usage\n--------------\n\nFrom 1.8.0, you can now switch dynamically to a new screen, change the\ntransition options and remove the previous one by using\n:meth:`~ScreenManager.switch_to`::\n\n    sm = ScreenManager()\n    screens = [Screen(name='Title {}'.format(i)) for i in range(4)]\n\n    sm.switch_to(screens[0])\n    # later\n    sm.switch_to(screens[1], direction='right')\n\nNote that this method adds the screen to the :class:`ScreenManager` instance\nand should not be used if your screens have already been added to this\ninstance. To switch to a screen which is already added, you should use the\n:attr:`~ScreenManager.current` property.\n\n\nChanging transitions\n--------------------\n\nYou have multiple transitions available by default, such as:\n\n- :class:`NoTransition` - switches screens instantly with no animation\n- :class:`SlideTransition` - slide the screen in/out, from any direction\n- :class:`SwapTransition` - implementation of the iOS swap transition\n- :class:`FadeTransition` - shader to fade the screen in/out\n- :class:`WipeTransition` - shader to wipe the screens from right to left\n- :class:`FallOutTransition` - shader where the old screen 'falls' and\n  becomes transparent, revealing the new one behind it.\n- :class:`RiseInTransition` - shader where the new screen rises from the\n  screen centre while fading from transparent to opaque.\n\nYou can easily switch transitions by changing the\n:attr:`ScreenManager.transition` property::\n\n    sm = ScreenManager(transition=FadeTransition())\n\n.. note::\n\n    Currently, none of Shader based Transitions use\n    anti-aliasing. This is because they use the FBO which doesn't have\n    any logic to handle supersampling. This is a known issue and we\n    are working on a transparent implementation that will give the\n    same results as if it had been rendered on screen.\n\n    To be more concrete, if you see sharp edged text during the animation, it's\n    normal.\n\n'''\n\n__all__ = ('Screen', 'ScreenManager', 'ScreenManagerException',\n           'TransitionBase', 'ShaderTransition', 'SlideTransition',\n           'SwapTransition', 'FadeTransition', 'WipeTransition',\n           'FallOutTransition', 'RiseInTransition', 'NoTransition')\n\nfrom kivy.compat import iteritems\nfrom kivy.logger import Logger\nfrom kivy.event import EventDispatcher\nfrom kivy.clock import Clock\nfrom kivy.uix.floatlayout import FloatLayout\nfrom kivy.properties import (StringProperty, ObjectProperty, AliasProperty,\n                             NumericProperty, ListProperty, OptionProperty,\n                             BooleanProperty)\nfrom kivy.animation import Animation, AnimationTransition\nfrom kivy.uix.relativelayout import RelativeLayout\nfrom kivy.lang import Builder\nfrom kivy.graphics import (RenderContext, Rectangle, Fbo,\n                           ClearColor, ClearBuffers, BindTexture, PushMatrix,\n                           PopMatrix, Translate, Callback)\n\n\nclass ScreenManagerException(Exception):\n    '''Exception for the :class:`ScreenManager`.\n    '''\n    pass\n\n\nclass Screen(RelativeLayout):\n    '''Screen is an element intended to be used with a :class:`ScreenManager`.\n    Check module documentation for more information.\n\n    :Events:\n        `on_pre_enter`: ()\n            Event fired when the screen is about to be used: the entering\n            animation is started.\n        `on_enter`: ()\n            Event fired when the screen is displayed: the entering animation is\n            complete.\n        `on_pre_leave`: ()\n            Event fired when the screen is about to be removed: the leaving\n            animation is started.\n        `on_leave`: ()\n            Event fired when the screen is removed: the leaving animation is\n            finished.\n\n    .. versionchanged:: 1.6.0\n        Events `on_pre_enter`, `on_enter`, `on_pre_leave` and `on_leave` were\n        added.\n    '''\n\n    name = StringProperty('')\n    '''\n    Name of the screen which must be unique within a :class:`ScreenManager`.\n    This is the name used for :attr:`ScreenManager.current`.\n\n    :attr:`name` is a :class:`~kivy.properties.StringProperty` and defaults to\n    ''.\n    '''\n\n    manager = ObjectProperty(None, allownone=True)\n    ''':class:`ScreenManager` object, set when the screen is added to a\n    manager.\n\n    :attr:`manager` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None, read-only.\n\n    '''\n\n    transition_progress = NumericProperty(0.)\n    '''Value that represents the completion of the current transition, if any\n    is occuring.\n\n    If a transition is in progress, whatever the mode, the value will change\n    from 0 to 1. If you want to know if it's an entering or leaving animation,\n    check the :attr:`transition_state`.\n\n    :attr:`transition_progress` is a :class:`~kivy.properties.NumericProperty`\n    and defaults to 0.\n    '''\n\n    transition_state = OptionProperty('out', options=('in', 'out'))\n    '''Value that represents the state of the transition:\n\n    - 'in' if the transition is going to show your screen\n    - 'out' if the transition is going to hide your screen\n\n    After the transition is complete, the state will retain it's last value (in\n    or out).\n\n    :attr:`transition_state` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to 'out'.\n    '''\n\n    __events__ = ('on_pre_enter', 'on_enter', 'on_pre_leave', 'on_leave')\n\n    def on_pre_enter(self, *args):\n        pass\n\n    def on_enter(self, *args):\n        pass\n\n    def on_pre_leave(self, *args):\n        pass\n\n    def on_leave(self, *args):\n        pass\n\n    def __repr__(self):\n        return '<Screen name=%r>' % self.name\n\n\nclass TransitionBase(EventDispatcher):\n    '''TransitionBase is used to animate 2 screens within the\n    :class:`ScreenManager`. This class acts as a base for other\n    implementations like the :class:`SlideTransition` and\n    :class:`SwapTransition`.\n\n    :Events:\n        `on_progress`: Transition object, progression float\n            Fired during the animation of the transition.\n        `on_complete`: Transition object\n            Fired when the transition is fininshed.\n    '''\n\n    screen_out = ObjectProperty()\n    '''Property that contains the screen to hide.\n    Automatically set by the :class:`ScreenManager`.\n\n    :class:`screen_out` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    screen_in = ObjectProperty()\n    '''Property that contains the screen to show.\n    Automatically set by the :class:`ScreenManager`.\n\n    :class:`screen_in` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    duration = NumericProperty(.4)\n    '''Duration in seconds of the transition.\n\n    :class:`duration` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to .4 (= 400ms).\n\n    .. versionchanged:: 1.8.0\n\n        Default duration has been changed from 700ms to 400ms.\n    '''\n\n    manager = ObjectProperty()\n    ''':class:`ScreenManager` object, set when the screen is added to a\n    manager.\n\n    :attr:`manager` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None, read-only.\n\n    '''\n\n    is_active = BooleanProperty(False)\n    '''Indicate whether the transition is currently active or not.\n\n    :attr:`is_active` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False, read-only.\n    '''\n\n    # privates\n\n    _anim = ObjectProperty(allownone=True)\n\n    __events__ = ('on_progress', 'on_complete')\n\n    def start(self, manager):\n        '''(internal) Starts the transition. This is automatically\n        called by the :class:`ScreenManager`.\n        '''\n        if self.is_active:\n            raise ScreenManagerException('start() is called twice!')\n        self.manager = manager\n        self._anim = Animation(d=self.duration, s=0)\n        self._anim.bind(on_progress=self._on_progress,\n                        on_complete=self._on_complete)\n\n        self.add_screen(self.screen_in)\n        self.screen_in.transition_progress = 0.\n        self.screen_in.transition_state = 'in'\n        self.screen_out.transition_progress = 0.\n        self.screen_out.transition_state = 'out'\n        self.screen_in.dispatch('on_pre_enter')\n        self.screen_out.dispatch('on_pre_leave')\n\n        self.is_active = True\n        self._anim.start(self)\n        self.dispatch('on_progress', 0)\n\n    def stop(self):\n        '''(internal) Stops the transition. This is automatically called by the\n        :class:`ScreenManager`.\n        '''\n        if self._anim:\n            self._anim.cancel(self)\n            self.dispatch('on_complete')\n            self._anim = None\n        self.is_active = False\n\n    def add_screen(self, screen):\n        '''(internal) Used to add a screen to the :class:`ScreenManager`.\n        '''\n        self.manager.real_add_widget(screen)\n\n    def remove_screen(self, screen):\n        '''(internal) Used to remove a screen from the :class:`ScreenManager`.\n        '''\n        self.manager.real_remove_widget(screen)\n\n    def on_complete(self):\n        self.remove_screen(self.screen_out)\n\n    def on_progress(self, progression):\n        pass\n\n    def _on_progress(self, *l):\n        progress = l[-1]\n        self.screen_in.transition_progress = progress\n        self.screen_out.transition_progress = 1. - progress\n        self.dispatch('on_progress', progress)\n\n    def _on_complete(self, *l):\n        self.is_active = False\n        self.dispatch('on_complete')\n        self.screen_in.dispatch('on_enter')\n        self.screen_out.dispatch('on_leave')\n        self._anim = None\n\n\nclass ShaderTransition(TransitionBase):\n    '''Transition class that uses a Shader for animating the transition between\n    2 screens. By default, this class doesn't assign any fragment/vertex\n    shader. If you want to create your own fragment shader for the transition,\n    you need to declare the header yourself and include the \"t\", \"tex_in\" and\n    \"tex_out\" uniform::\n\n        # Create your own transition. This shader implements a \"fading\"\n        # transition.\n        fs = \"\"\"$HEADER\n            uniform float t;\n            uniform sampler2D tex_in;\n            uniform sampler2D tex_out;\n\n            void main(void) {\n                vec4 cin = texture2D(tex_in, tex_coord0);\n                vec4 cout = texture2D(tex_out, tex_coord0);\n                gl_FragColor = mix(cout, cin, t);\n            }\n        \"\"\"\n\n        # And create your transition\n        tr = ShaderTransition(fs=fs)\n        sm = ScreenManager(transition=tr)\n\n    '''\n\n    fs = StringProperty(None)\n    '''Fragment shader to use.\n\n    :attr:`fs` is a :class:`~kivy.properties.StringProperty` and defaults to\n    None.'''\n\n    vs = StringProperty(None)\n    '''Vertex shader to use.\n\n    :attr:`vs` is a :class:`~kivy.properties.StringProperty` and defaults to\n    None.'''\n\n    clearcolor = ListProperty([0, 0, 0, 1])\n    '''Sets the color of Fbo ClearColor.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`clearcolor` is a :class:`~kivy.properties.ListProperty`\n    and defaults to [0, 0, 0, 1].'''\n\n    def make_screen_fbo(self, screen):\n        fbo = Fbo(size=screen.size)\n        with fbo:\n            ClearColor(*self.clearcolor)\n            ClearBuffers()\n        fbo.add(screen.canvas)\n        with fbo.before:\n            PushMatrix()\n            Translate(-screen.x, -screen.y, 0)\n        with fbo.after:\n            PopMatrix()\n        return fbo\n\n    def on_progress(self, progress):\n        self.render_ctx['t'] = progress\n\n    def on_complete(self):\n        self.render_ctx['t'] = 1.\n        super(ShaderTransition, self).on_complete()\n\n    def _remove_out_canvas(self, *args):\n        if (self.screen_out\n                and self.screen_out.canvas in self.manager.canvas.children\n                and self.screen_out not in self.manager.children):\n            self.manager.canvas.remove(self.screen_out.canvas)\n\n    def add_screen(self, screen):\n        self.screen_in.pos = self.screen_out.pos\n        self.screen_in.size = self.screen_out.size\n        self.manager.real_remove_widget(self.screen_out)\n        self.manager.canvas.add(self.screen_out.canvas)\n\n        def remove_screen_out(instr):\n            Clock.schedule_once(self._remove_out_canvas, -1)\n            self.render_ctx.remove(instr)\n\n        self.fbo_in = self.make_screen_fbo(self.screen_in)\n        self.fbo_out = self.make_screen_fbo(self.screen_out)\n        self.manager.canvas.add(self.fbo_in)\n        self.manager.canvas.add(self.fbo_out)\n\n        self.render_ctx = RenderContext(fs=self.fs, vs=self.vs,\n                                        use_parent_modelview=True,\n                                        use_parent_projection=True)\n        with self.render_ctx:\n            BindTexture(texture=self.fbo_out.texture, index=1)\n            BindTexture(texture=self.fbo_in.texture, index=2)\n            x, y = self.screen_in.pos\n            w, h = self.fbo_in.texture.size\n            Rectangle(size=(w, h), pos=(x, y),\n                      tex_coords=self.fbo_in.texture.tex_coords)\n            Callback(remove_screen_out)\n        self.render_ctx['tex_out'] = 1\n        self.render_ctx['tex_in'] = 2\n        self.manager.canvas.add(self.render_ctx)\n\n    def remove_screen(self, screen):\n        self.manager.canvas.remove(self.fbo_in)\n        self.manager.canvas.remove(self.fbo_out)\n        self.manager.canvas.remove(self.render_ctx)\n        self._remove_out_canvas()\n        self.manager.real_add_widget(self.screen_in)\n\n    def stop(self):\n        self._remove_out_canvas()\n        super(ShaderTransition, self).stop()\n\n\nclass NoTransition(TransitionBase):\n    '''No transition, instantly switches to the next screen with no delay or\n    animation.\n\n    .. versionadded:: 1.8.0\n    '''\n\n    duration = NumericProperty(0.0)\n\n    def on_complete(self):\n        self.screen_in.pos = self.manager.pos\n        self.screen_out.pos = self.manager.pos\n        super(NoTransition, self).on_complete()\n\n\nclass SlideTransition(TransitionBase):\n    '''Slide Transition, can be used to show a new screen from any direction:\n    left, right, up or down.\n    '''\n\n    direction = OptionProperty('left', options=('left', 'right', 'up', 'down'))\n    '''Direction of the transition.\n\n    :attr:`direction` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to 'left'. Can be one of 'left', 'right', 'up' or 'down'.\n    '''\n\n    def on_progress(self, progression):\n        a = self.screen_in\n        b = self.screen_out\n        manager = self.manager\n        x, y = manager.pos\n        width, height = manager.size\n        direction = self.direction\n        al = AnimationTransition.out_quad\n        progression = al(progression)\n        if direction == 'left':\n            a.y = b.y = y\n            a.x = x + width * (1 - progression)\n            b.x = x - width * progression\n        elif direction == 'right':\n            a.y = b.y = y\n            b.x = x + width * progression\n            a.x = x - width * (1 - progression)\n        elif direction == 'down':\n            a.x = b.x = x\n            a.y = y + height * (1 - progression)\n            b.y = y - height * progression\n        elif direction == 'up':\n            a.x = b.x = manager.x\n            b.y = y + height * progression\n            a.y = y - height * (1 - progression)\n\n    def on_complete(self):\n        self.screen_in.pos = self.manager.pos\n        self.screen_out.pos = self.manager.pos\n        super(SlideTransition, self).on_complete()\n\n\nclass SwapTransition(TransitionBase):\n    '''Swap transition that looks like iOS transition when a new window\n    appears on the screen.\n    '''\n\n    def add_screen(self, screen):\n        self.manager.real_add_widget(screen, 1)\n\n    def on_complete(self):\n        self.screen_in.scale = 1.\n        self.screen_out.scale = 1.\n        self.screen_in.pos = self.manager.pos\n        self.screen_out.pos = self.manager.pos\n        super(SwapTransition, self).on_complete()\n\n    def on_progress(self, progression):\n        a = self.screen_in\n        b = self.screen_out\n        manager = self.manager\n\n        b.scale = 1. - progression * 0.7\n        a.scale = 0.5 + progression * 0.5\n        a.center_y = b.center_y = manager.center_y\n\n        al = AnimationTransition.in_out_sine\n\n        if progression < 0.5:\n            p2 = al(progression * 2)\n            width = manager.width * 0.7\n            widthb = manager.width * 0.2\n            a.x = manager.center_x + p2 * width / 2.\n            b.center_x = manager.center_x - p2 * widthb / 2.\n        else:\n            if self.screen_in is self.manager.children[-1]:\n                self.manager.real_remove_widget(self.screen_in)\n                self.manager.real_add_widget(self.screen_in)\n            p2 = al((progression - 0.5) * 2)\n            width = manager.width * 0.85\n            widthb = manager.width * 0.2\n            a.x = manager.x + width * (1 - p2)\n            b.center_x = manager.center_x - (1 - p2) * widthb / 2.\n\n\nclass WipeTransition(ShaderTransition):\n    '''Wipe transition, based on a fragment Shader.\n    '''\n\n    WIPE_TRANSITION_FS = '''$HEADER$\n    uniform float t;\n    uniform sampler2D tex_in;\n    uniform sampler2D tex_out;\n\n    void main(void) {\n        vec4 cin = texture2D(tex_in, tex_coord0);\n        vec4 cout = texture2D(tex_out, tex_coord0);\n        gl_FragColor = mix(cout, cin, clamp((-1.5 + 1.5*tex_coord0.x + 2.5*t),\n            0.0, 1.0));\n    }\n    '''\n    fs = StringProperty(WIPE_TRANSITION_FS)\n\n\nclass FadeTransition(ShaderTransition):\n    '''Fade transition, based on a fragment Shader.\n    '''\n\n    FADE_TRANSITION_FS = '''$HEADER$\n    uniform float t;\n    uniform sampler2D tex_in;\n    uniform sampler2D tex_out;\n\n    void main(void) {\n        vec4 cin = vec4(texture2D(tex_in, tex_coord0.st));\n        vec4 cout = vec4(texture2D(tex_out, tex_coord0.st));\n        vec4 frag_col = vec4(t * cin) + vec4((1.0 - t) * cout);\n        gl_FragColor = frag_col;\n    }\n    '''\n    fs = StringProperty(FADE_TRANSITION_FS)\n\n\nclass FallOutTransition(ShaderTransition):\n    '''Transition where the new screen 'falls' from the screen centre,\n    becoming smaller and more transparent until it disappears, and\n    revealing the new screen behind it. Mimics the popular/standard\n    Android transition.\n\n    .. versionadded:: 1.8.0\n\n    '''\n\n    duration = NumericProperty(0.15)\n    '''Duration in seconds of the transition, replacing the default of\n    :class:`TransitionBase`.\n\n    :class:`duration` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to .15 (= 150ms).\n    '''\n\n    FALLOUT_TRANSITION_FS = '''$HEADER$\n    uniform float t;\n    uniform sampler2D tex_in;\n    uniform sampler2D tex_out;\n\n    void main(void) {\n        /* quantities for position and opacity calculation */\n        float tr = 0.5*sin(t);  /* 'real' time */\n        vec2 diff = (tex_coord0.st - 0.5) * (1.0/(1.0-tr));\n        vec2 dist = diff + 0.5;\n        float max_dist = 1.0 - tr;\n\n        /* in and out colors */\n        vec4 cin = vec4(texture2D(tex_in, tex_coord0.st));\n        vec4 cout = vec4(texture2D(tex_out, dist));\n\n        /* opacities for in and out textures */\n        float oin = clamp(1.0-cos(t), 0.0, 1.0);\n        float oout = clamp(cos(t), 0.0, 1.0);\n\n        bvec2 outside_bounds = bvec2(abs(tex_coord0.s - 0.5) > 0.5*max_dist,\n                                     abs(tex_coord0.t - 0.5) > 0.5*max_dist);\n\n        vec4 frag_col;\n        if (any(outside_bounds) ){\n            frag_col = vec4(cin.x, cin.y, cin.z, 1.0);\n            }\n        else {\n            frag_col = vec4(oout*cout.x + oin*cin.x, oout*cout.y + oin*cin.y,\n                            oout*cout.z + oin*cin.z, 1.0);\n            }\n\n        gl_FragColor = frag_col;\n    }\n    '''\n\n    fs = StringProperty(FALLOUT_TRANSITION_FS)\n\n\nclass RiseInTransition(ShaderTransition):\n    '''Transition where the new screen rises from the screen centre,\n    becoming larger and changing from transparent to opaque until it\n    fills the screen. Mimics the popular/standard Android transition.\n\n    .. versionadded:: 1.8.0\n    '''\n\n    duration = NumericProperty(0.2)\n    '''Duration in seconds of the transition, replacing the default of\n    :class:`TransitionBase`.\n\n    :class:`duration` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to .2 (= 200ms).\n    '''\n\n    RISEIN_TRANSITION_FS = '''$HEADER$\n    uniform float t;\n    uniform sampler2D tex_in;\n    uniform sampler2D tex_out;\n\n    void main(void) {\n        /* quantities for position and opacity calculation */\n        float tr = 0.5 - 0.5*sqrt(sin(t));  /* 'real' time */\n        vec2 diff = (tex_coord0.st - 0.5) * (1.0/(1.0-tr));\n        vec2 dist = diff + 0.5;\n        float max_dist = 1.0 - tr;\n\n        /* in and out colors */\n        vec4 cin = vec4(texture2D(tex_in, dist));\n        vec4 cout = vec4(texture2D(tex_out, tex_coord0.st));\n\n        /* opacities for in and out textures */\n        float oin = clamp(sin(2.0*t), 0.0, 1.0);\n        float oout = clamp(1.0 - sin(2.0*t), 0.0, 1.0);\n\n        bvec2 outside_bounds = bvec2(abs(tex_coord0.s - 0.5) > 0.5*max_dist,\n                                     abs(tex_coord0.t - 0.5) > 0.5*max_dist);\n\n        vec4 frag_col;\n        if (any(outside_bounds) ){\n            frag_col = vec4(cout.x, cout.y, cout.z, 1.0);\n            }\n        else {\n            frag_col = vec4(oout*cout.x + oin*cin.x, oout*cout.y + oin*cin.y,\n                            oout*cout.z + oin*cin.z, 1.0);\n            }\n\n        gl_FragColor = frag_col;\n    }\n    '''\n\n    fs = StringProperty(RISEIN_TRANSITION_FS)\n\n\nclass ScreenManager(FloatLayout):\n    '''Screen manager. This is the main class that will control your\n    :class:`Screen` stack and memory.\n\n    By default, the manager will show only one screen at a time.\n    '''\n\n    current = StringProperty(None)\n    '''Name of the screen currently shown, or the screen to show.\n\n  ::\n\n        from kivy.uix.screenmanager import ScreenManager, Screen\n\n        sm = ScreenManager()\n        sm.add_widget(Screen(name='first'))\n        sm.add_widget(Screen(name='second'))\n\n        # By default, the first added screen will be shown. If you want to\n        # show another one, just set the 'current' property.\n        sm.current = 'second'\n    '''\n\n    transition = ObjectProperty(SlideTransition(), baseclass=TransitionBase)\n    '''Transition object to use for animating the screen that will be hidden\n    and the screen that will be shown. By default, an instance of\n    :class:`SlideTransition` will be given.\n\n    For example, if you want to change to a :class:`WipeTransition`::\n\n        from kivy.uix.screenmanager import ScreenManager, Screen,\n        WipeTransition\n\n        sm = ScreenManager(transition=WipeTransition())\n        sm.add_widget(Screen(name='first'))\n        sm.add_widget(Screen(name='second'))\n\n        # by default, the first added screen will be shown. If you want to\n        # show another one, just set the 'current' property.\n        sm.current = 'second'\n\n    .. versionchanged:: 1.8.0\n\n        Default transition has been changed from :class:`SwapTransition` to\n        :class:`SlideTransition`.\n    '''\n\n    screens = ListProperty()\n    '''List of all the :class:`Screen` widgets added. You must not change the\n    list manually. Use :meth:`Screen.add_widget` instead.\n\n    :attr:`screens` is a :class:`~kivy.properties.ListProperty` and defaults to\n    [], read-only.\n    '''\n\n    current_screen = ObjectProperty(None)\n    '''Contains the currently displayed screen. You must not change this\n    property manually, use :attr:`current` instead.\n\n    :attr:`current_screen` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None, read-only.\n    '''\n\n    def _get_screen_names(self):\n        return [s.name for s in self.screens]\n\n    screen_names = AliasProperty(_get_screen_names,\n                                 None, bind=('screens', ))\n    '''List of the names of all the :class:`Screen` widgets added. The list\n    is read only.\n\n    :attr:`screens_names` is an :class:`~kivy.properties.AliasProperty` and\n    is read-only. It is updated if the screen list changes or the name\n    of a screen changes.\n    '''\n\n    def __init__(self, **kwargs):\n        super(ScreenManager, self).__init__(**kwargs)\n        self.bind(pos=self._update_pos)\n\n    def _screen_name_changed(self, screen, name):\n        self.property('screen_names').dispatch(self)\n        if screen == self.current_screen:\n            self.current = name\n\n    def add_widget(self, screen):\n        if not isinstance(screen, Screen):\n            raise ScreenManagerException(\n                'ScreenManager accepts only Screen widget.')\n        if screen.manager:\n            if screen.manager is self:\n                raise ScreenManagerException(\n                    'Screen already managed by this ScreenManager (are you '\n                    'calling `switch_to` when you should be setting '\n                    '`current`?)')\n            raise ScreenManagerException(\n                'Screen already managed by another ScreenManager.')\n        screen.manager = self\n        screen.bind(name=self._screen_name_changed)\n        self.screens.append(screen)\n        if self.current is None:\n            self.current = screen.name\n\n    def remove_widget(self, *l):\n        screen = l[0]\n        if not isinstance(screen, Screen):\n            raise ScreenManagerException(\n                'ScreenManager uses remove_widget only to remove' +\n                'screens added via add_widget! use real_remove_widget.')\n\n        if not screen in self.screens:\n            return\n        if self.current_screen == screen:\n            other = next(self)\n            if other:\n                self.current = other\n        screen.manager = None\n        screen.unbind(name=self._screen_name_changed)\n        self.screens.remove(screen)\n\n    def real_add_widget(self, *l):\n        # ensure screen is removed from it's previous parent before adding'\n        if l[0].parent:\n            l[0].parent.remove_widget(l[0])\n        super(ScreenManager, self).add_widget(*l)\n\n    def real_remove_widget(self, *l):\n        super(ScreenManager, self).remove_widget(*l)\n\n    def on_current(self, instance, value):\n        screen = self.get_screen(value)\n        if not screen:\n            return\n        if screen == self.current_screen:\n            return\n\n        self.transition.stop()\n\n        previous_screen = self.current_screen\n        self.current_screen = screen\n        if previous_screen:\n            self.transition.screen_in = screen\n            self.transition.screen_out = previous_screen\n            self.transition.start(self)\n        else:\n            self.real_add_widget(screen)\n            screen.pos = self.pos\n            self.do_layout()\n            screen.dispatch('on_pre_enter')\n            screen.dispatch('on_enter')\n\n    def get_screen(self, name):\n        '''Return the screen widget associated with the name or raise a\n        :class:`ScreenManagerException` if not found.\n        '''\n        matches = [s for s in self.screens if s.name == name]\n        num_matches = len(matches)\n        if num_matches == 0:\n            raise ScreenManagerException('No Screen with name \"%s\".' % name)\n        if num_matches > 1:\n            Logger.warn('Multiple screens named \"%s\": %s' % (name, matches))\n        return matches[0]\n\n    def has_screen(self, name):\n        '''Return True if a screen with the `name` has been found.\n\n        .. versionadded:: 1.6.0\n        '''\n        return bool([s for s in self.screens if s.name == name])\n\n    def __next__(self):\n        '''Py2K backwards compatability without six or other lib.\n        '''\n        screens = self.screens\n        if not screens:\n            return\n        try:\n            index = screens.index(self.current_screen)\n            index = (index + 1) % len(screens)\n            return screens[index].name\n        except ValueError:\n            return\n\n    def next(self):\n        '''Return the name of the next screen from the screen list.'''\n        return self.__next__()\n\n    def previous(self):\n        '''Return the name of the previous screen from the screen list.\n        '''\n        screens = self.screens\n        if not screens:\n            return\n        try:\n            index = screens.index(self.current_screen)\n            index = (index - 1) % len(screens)\n            return screens[index].name\n        except ValueError:\n            return\n\n    def switch_to(self, screen, **options):\n        '''Add a new screen to the ScreenManager and switch to it. The previous\n        screen will be removed from the children. `options` are the\n        :attr:`transition` options that will be changed before the animation\n        happens.\n\n        If no previous screens are available, the screen will be used as the\n        main one::\n\n            sm = ScreenManager()\n            sm.switch_to(screen1)\n            # later\n            sm.switch_to(screen2, direction='left')\n            # later\n            sm.switch_to(screen3, direction='right', duration=1.)\n\n        If any animation is in progress, it will be stopped and replaced by\n        this one: you should avoid this because the animation will just look\n        weird. Use either :meth:`switch_to` or :attr:`current` but not both.\n\n        The `screen` name will be changed if there is any conflict with the\n        current screen.\n\n        .. versionadded: 1.8.0\n        '''\n        assert(screen is not None)\n\n        if not isinstance(screen, Screen):\n            raise ScreenManagerException(\n                'ScreenManager accepts only Screen widget.')\n\n        # stop any transition that might be happening already\n        self.transition.stop()\n\n        # ensure the screen name will be unique\n        if screen not in self.children:\n            if self.has_screen(screen.name):\n                screen.name = self._generate_screen_name()\n\n        # change the transition if given explicitly\n        old_transition = self.transition\n        specified_transition = options.pop(\"transition\", None)\n        if specified_transition:\n            self.transition = specified_transition\n\n        # change the transition options\n        for key, value in iteritems(options):\n            setattr(self.transition, key, value)\n\n        # add and leave if we are set as the current screen\n        self.add_widget(screen)\n        if self.current_screen is screen:\n            return\n\n        old_current = self.current_screen\n\n        def remove_old_screen(transition):\n            if old_current in self.children:\n                self.remove_widget(old_current)\n                self.transition = old_transition\n            transition.unbind(on_complete=remove_old_screen)\n        self.transition.bind(on_complete=remove_old_screen)\n\n        self.current = screen.name\n\n    def _generate_screen_name(self):\n        i = 0\n        while True:\n            name = '_screen{}'.format(i)\n            if not self.has_screen(name):\n                return name\n            i += 1\n\n    def _update_pos(self, instance, value):\n        for child in self.children:\n            if self.transition.is_active and \\\n                (child == self.transition.screen_in or\n                 child == self.transition.screen_out):\n                    continue\n            child.pos = value\n\n    def on_touch_down(self, touch):\n        if self.transition.is_active:\n            return False\n        return super(ScreenManager, self).on_touch_down(touch)\n\n    def on_touch_move(self, touch):\n        if self.transition.is_active:\n            return False\n        return super(ScreenManager, self).on_touch_move(touch)\n\n    def on_touch_up(self, touch):\n        if self.transition.is_active:\n            return False\n        return super(ScreenManager, self).on_touch_up(touch)\n\nif __name__ == '__main__':\n    from kivy.app import App\n    from kivy.uix.button import Button\n    Builder.load_string('''\n<Screen>:\n    canvas:\n        Color:\n            rgb: .2, .2, .2\n        Rectangle:\n            size: self.size\n\n    GridLayout:\n        cols: 2\n        Button:\n            text: 'Hello world'\n        Button:\n            text: 'Hello world'\n        Button:\n            text: 'Hello world'\n        Button:\n            text: 'Hello world'\n''')\n\n    class TestApp(App):\n\n        def change_view(self, *l):\n            #d = ('left', 'up', 'down', 'right')\n            #di = d.index(self.sm.transition.direction)\n            #self.sm.transition.direction = d[(di + 1) % len(d)]\n            self.sm.current = next(self.sm)\n\n        def remove_screen(self, *l):\n            self.sm.remove_widget(self.sm.get_screen('test1'))\n\n        def build(self):\n            root = FloatLayout()\n            self.sm = sm = ScreenManager(transition=SwapTransition())\n\n            sm.add_widget(Screen(name='test1'))\n            sm.add_widget(Screen(name='test2'))\n\n            btn = Button(size_hint=(None, None))\n            btn.bind(on_release=self.change_view)\n\n            btn2 = Button(size_hint=(None, None), x=100)\n            btn2.bind(on_release=self.remove_screen)\n\n            root.add_widget(sm)\n            root.add_widget(btn)\n            root.add_widget(btn2)\n            return root\n\n    TestApp().run()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/scrollview.py",
    "content": "'''Scroll View\n===========\n\n.. versionadded:: 1.0.4\n\nThe :class:`ScrollView` widget provides a scrollable/pannable viewport that is\nclipped at the scrollview's bounding box.\n\n\nScrolling Behavior\n------------------\n\nThe ScrollView accepts only one child and applies a viewport/window to\nit according to the :attr:`ScrollView.scroll_x` and\n:attr:`ScrollView.scroll_y` properties. Touches are analyzed to\ndetermine if the user wants to scroll or control the child in some\nother manner - you cannot do both at the same time. To determine if\ninteraction is a scrolling gesture, these properties are used:\n\n    - :attr:`ScrollView.scroll_distance`: the minimum distance to travel,\n         defaults to 20 pixels.\n    - :attr:`ScrollView.scroll_timeout`: the maximum time period, defaults\n         to 250 milliseconds.\n\nIf a touch travels :attr:`~ScrollView.scroll_distance` pixels within the\n:attr:`~ScrollView.scroll_timeout` period, it is recognized as a scrolling\ngesture and translation (scroll/pan) will begin. If the timeout occurs, the\ntouch down event is dispatched to the child instead (no translation).\n\nThe default value for those settings can be changed in the configuration file::\n\n    [widgets]\n    scroll_timeout = 250\n    scroll_distance = 20\n\n.. versionadded:: 1.1.1\n\n    ScrollView now animates scrolling in Y when a mousewheel is used.\n\n\nLimiting to the X or Y Axis\n---------------------------\n\nBy default, the ScrollView allows scrolling in both the X and Y axes. You can\nexplicitly disable scrolling on an axis by setting\n:attr:`ScrollView.do_scroll_x` or :attr:`ScrollView.do_scroll_y` to False.\n\n\nManaging the Content Size and Position\n--------------------------------------\n\nScrollView manages the position of its children similarly to a\nRelativeLayout (see :mod:`~kivy.uix.relativelayout`) but not the size. You must\ncarefully specify the `size_hint` of your content to get the desired\nscroll/pan effect.\n\nBy default, size_hint is (1, 1), so the content size will fit your ScrollView\nexactly (you will have nothing to scroll). You must deactivate at least one of\nthe size_hint instructions (x or y) of the child to enable scrolling.\n\nTo scroll a :class:`GridLayout` on Y-axis/vertically, set the child's width\nidentical to that of the ScrollView (size_hint_x=1, default), and set the\nsize_hint_y property to None::\n\n    layout = GridLayout(cols=1, spacing=10, size_hint_y=None)\n    # Make sure the height is such that there is something to scroll.\n    layout.bind(minimum_height=layout.setter('height'))\n    for i in range(30):\n        btn = Button(text=str(i), size_hint_y=None, height=40)\n        layout.add_widget(btn)\n    root = ScrollView(size_hint=(None, None), size=(400, 400))\n    root.add_widget(layout)\n\n\nOverscroll Effects\n------------------\n\n.. versionadded:: 1.7.0\n\nWhen scrolling would exceed the bounds of the :class:`ScrollView`, it\nuses a :class:`~kivy.effects.scroll.ScrollEffect` to handle the\noverscroll. These effects can perform actions like bouncing back,\nchanging opacity, or simply preventing scrolling beyond the normal\nboundaries. Note that complex effects may perform many computations,\nwhich can be slow on weaker hardware.\n\nYou can change what effect is being used by setting\n:attr:`ScrollView.effect_cls` to any effect class. Current options\ninclude:\n\n    - :class:`~kivy.effects.scroll.ScrollEffect`: Does not allow\n      scrolling beyond the :class:`ScrollView` boundaries.\n    - :class:`~kivy.effects.dampedscroll.DampedScrollEffect`: The\n      current default. Allows the user to scroll beyond the normal\n      boundaries, but has the content spring back once the\n      touch/click is released.\n    - :class:`~kivy.effects.opacityscroll.OpacityScrollEffect`: Similar\n      to the :class:`~kivy.effect.dampedscroll.DampedScrollEffect`, but\n      also reduces opacity during overscroll.\n\nYou can also create your own scroll effect by subclassing one of these,\nthen pass it as the :attr:`~ScrollView.effect_cls` in the same way.\n\nAlternatively, you can set :attr:`ScrollView.effect_x` and/or\n:attr:`ScrollView.effect_y` to an *instance* of the effect you want to\nuse. This will override the default effect set in\n:attr:`ScrollView.effect_cls`.\n\nAll the effects are located in the :mod:`kivy.effects`.\n\n'''\n\n__all__ = ('ScrollView', )\n\nfrom functools import partial\nfrom kivy.animation import Animation\nfrom kivy.compat import string_types\nfrom kivy.config import Config\nfrom kivy.clock import Clock\nfrom kivy.factory import Factory\nfrom kivy.uix.stencilview import StencilView\nfrom kivy.metrics import sp\nfrom kivy.effects.dampedscroll import DampedScrollEffect\nfrom kivy.properties import NumericProperty, BooleanProperty, AliasProperty, \\\n    ObjectProperty, ListProperty, ReferenceListProperty, OptionProperty\n\n\n# When we are generating documentation, Config doesn't exist\n_scroll_timeout = _scroll_distance = 0\nif Config:\n    _scroll_timeout = Config.getint('widgets', 'scroll_timeout')\n    _scroll_distance = sp(Config.getint('widgets', 'scroll_distance'))\n\n\nclass ScrollView(StencilView):\n    '''ScrollView class. See module documentation for more information.\n\n    :Events:\n        `on_scroll_start`\n            Generic event fired when scrolling starts from touch.\n        `on_scroll_move`\n            Generic event fired when scrolling move from touch.\n        `on_scroll_stop`\n            Generic event fired when scrolling stops from touch.\n\n    .. versionchanged:: 1.9.0\n        `on_scroll_start`, `on_scroll_move` and `on_scroll_stop` events are\n        now dispatched when scrolling to handle nested ScrollViews.\n\n    .. versionchanged:: 1.7.0\n        `auto_scroll`, `scroll_friction`, `scroll_moves`, `scroll_stoptime' has\n        been deprecated, use :attr:`effect_cls` instead.\n    '''\n\n    scroll_distance = NumericProperty(_scroll_distance)\n    '''Distance to move before scrolling the :class:`ScrollView`, in pixels. As\n    soon as the distance has been traveled, the :class:`ScrollView` will start\n    to scroll, and no touch event will go to children.\n    It is advisable that you base this value on the dpi of your target device's\n    screen.\n\n    :attr:`scroll_distance` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 20 (pixels), according to the default value in user\n    configuration.\n    '''\n\n    scroll_wheel_distance = NumericProperty(20)\n    '''Distance to move when scrolling with a mouse wheel.\n    It is advisable that you base this value on the dpi of your target device's\n    screen.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`scroll_wheel_distance` is a\n    :class:`~kivy.properties.NumericProperty` , defaults to 20 pixels.\n    '''\n\n    scroll_timeout = NumericProperty(_scroll_timeout)\n    '''Timeout allowed to trigger the :attr:`scroll_distance`, in milliseconds.\n    If the user has not moved :attr:`scroll_distance` within the timeout,\n    the scrolling will be disabled, and the touch event will go to the\n    children.\n\n    :attr:`scroll_timeout` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 55 (milliseconds) according to the default value in user\n    configuration.\n\n    .. versionchanged:: 1.5.0\n        Default value changed from 250 to 55.\n    '''\n\n    scroll_x = NumericProperty(0.)\n    '''X scrolling value, between 0 and 1. If 0, the content's left side will\n    touch the left side of the ScrollView. If 1, the content's right side will\n    touch the right side.\n\n    This property is controled by :class:`ScrollView` only if\n    :attr:`do_scroll_x` is True.\n\n    :attr:`scroll_x` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    scroll_y = NumericProperty(1.)\n    '''Y scrolling value, between 0 and 1. If 0, the content's bottom side will\n    touch the bottom side of the ScrollView. If 1, the content's top side will\n    touch the top side.\n\n    This property is controled by :class:`ScrollView` only if\n    :attr:`do_scroll_y` is True.\n\n    :attr:`scroll_y` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 1.\n    '''\n\n    do_scroll_x = BooleanProperty(True)\n    '''Allow scroll on X axis.\n\n    :attr:`do_scroll_x` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n\n    do_scroll_y = BooleanProperty(True)\n    '''Allow scroll on Y axis.\n\n    :attr:`do_scroll_y` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n\n    def _get_do_scroll(self):\n        return (self.do_scroll_x, self.do_scroll_y)\n\n    def _set_do_scroll(self, value):\n        if type(value) in (list, tuple):\n            self.do_scroll_x, self.do_scroll_y = value\n        else:\n            self.do_scroll_x = self.do_scroll_y = bool(value)\n    do_scroll = AliasProperty(_get_do_scroll, _set_do_scroll,\n                              bind=('do_scroll_x', 'do_scroll_y'))\n    '''Allow scroll on X or Y axis.\n\n    :attr:`do_scroll` is a :class:`~kivy.properties.AliasProperty` of\n    (:attr:`do_scroll_x` + :attr:`do_scroll_y`)\n    '''\n\n    def _get_vbar(self):\n        # must return (y, height) in %\n        # calculate the viewport size / scrollview size %\n        if self._viewport is None:\n            return 0, 1.\n        vh = self._viewport.height\n        h = self.height\n        if vh < h or vh == 0:\n            return 0, 1.\n        ph = max(0.01, h / float(vh))\n        sy = min(1.0, max(0.0, self.scroll_y))\n        py = (1. - ph) * sy\n        return (py, ph)\n\n    vbar = AliasProperty(_get_vbar, None, bind=(\n        'scroll_y', '_viewport', 'viewport_size'))\n    '''Return a tuple of (position, size) of the vertical scrolling bar.\n\n    .. versionadded:: 1.2.0\n\n    The position and size are normalized between 0-1, and represent a\n    percentage of the current scrollview height. This property is used\n    internally for drawing the little vertical bar when you're scrolling.\n\n    :attr:`vbar` is a :class:`~kivy.properties.AliasProperty`, readonly.\n    '''\n\n    def _get_hbar(self):\n        # must return (x, width) in %\n        # calculate the viewport size / scrollview size %\n        if self._viewport is None:\n            return 0, 1.\n        vw = self._viewport.width\n        w = self.width\n        if vw < w or vw == 0:\n            return 0, 1.\n        pw = max(0.01, w / float(vw))\n        sx = min(1.0, max(0.0, self.scroll_x))\n        px = (1. - pw) * sx\n        return (px, pw)\n\n    hbar = AliasProperty(_get_hbar, None, bind=(\n        'scroll_x', '_viewport', 'viewport_size'))\n    '''Return a tuple of (position, size) of the horizontal scrolling bar.\n\n    .. versionadded:: 1.2.0\n\n    The position and size are normalized between 0-1, and represent a\n    percentage of the current scrollview height. This property is used\n    internally for drawing the little horizontal bar when you're scrolling.\n\n    :attr:`vbar` is a :class:`~kivy.properties.AliasProperty`, readonly.\n    '''\n\n    bar_color = ListProperty([.7, .7, .7, .9])\n    '''Color of horizontal / vertical scroll bar, in RGBA format.\n\n    .. versionadded:: 1.2.0\n\n    :attr:`bar_color` is a :class:`~kivy.properties.ListProperty` and defaults\n    to [.7, .7, .7, .9].\n    '''\n\n    bar_inactive_color = ListProperty([.7, .7, .7, .2])\n    '''Color of horizontal / vertical scroll bar (in RGBA format), when no\n    scroll is happening.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`bar_inactive_color` is a\n    :class:`~kivy.properties.ListProperty` and defaults to [.7, .7, .7, .2].\n    '''\n\n    bar_width = NumericProperty('2dp')\n    '''Width of the horizontal / vertical scroll bar. The width is interpreted\n    as a height for the horizontal bar.\n\n    .. versionadded:: 1.2.0\n\n    :attr:`bar_width` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 2.\n    '''\n\n    bar_pos_x = OptionProperty('bottom', options=('top', 'bottom'))\n    '''Which side of the ScrollView the horizontal scroll bar should go\n    on. Possible values are 'top' and 'bottom'.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`bar_pos_x` is an :class:`~kivy.properties.OptionProperty`,\n    defaults to 'bottom'.\n\n    '''\n\n    bar_pos_y = OptionProperty('right', options=('left', 'right'))\n    '''Which side of the ScrollView the vertical scroll bar should go\n    on. Possible values are 'left' and 'right'.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`bar_pos_y` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to 'right'.\n\n    '''\n\n    bar_pos = ReferenceListProperty(bar_pos_x, bar_pos_y)\n    '''Which side of the scroll view to place each of the bars on.\n\n    :attr:`bar_pos` is a :class:`~kivy.properties.ReferenceListProperty` of\n    (:attr:`bar_pos_x`, :attr:`bar_pos_y`)\n    '''\n\n    bar_margin = NumericProperty(0)\n    '''Margin between the bottom / right side of the scrollview when drawing\n    the horizontal / vertical scroll bar.\n\n    .. versionadded:: 1.2.0\n\n    :attr:`bar_margin` is a :class:`~kivy.properties.NumericProperty`, default\n    to 0\n    '''\n\n    effect_cls = ObjectProperty(DampedScrollEffect, allownone=True)\n    '''Class effect to instanciate for X and Y axis.\n\n    .. versionadded:: 1.7.0\n\n    :attr:`effect_cls` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to :class:`DampedScrollEffect`.\n\n    .. versionchanged:: 1.8.0\n        If you set a string, the :class:`~kivy.factory.Factory` will be used to\n        resolve the class.\n\n    '''\n\n    effect_x = ObjectProperty(None, allownone=True)\n    '''Effect to apply for the X axis. If None is set, an instance of\n    :attr:`effect_cls` will be created.\n\n    .. versionadded:: 1.7.0\n\n    :attr:`effect_x` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    effect_y = ObjectProperty(None, allownone=True)\n    '''Effect to apply for the Y axis. If None is set, an instance of\n    :attr:`effect_cls` will be created.\n\n    .. versionadded:: 1.7.0\n\n    :attr:`effect_y` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None, read-only.\n    '''\n\n    viewport_size = ListProperty([0, 0])\n    '''(internal) Size of the internal viewport. This is the size of your only\n    child in the scrollview.\n    '''\n\n    scroll_type = OptionProperty(['content'], options=(['content'], ['bars'],\n                                 ['bars', 'content'], ['content', 'bars']))\n    '''Sets the type of scrolling to use for the content of the scrollview.\n    Available options are: ['content'], ['bars'], ['bars', 'content'].\n\n    .. versionadded:: 1.8.0\n\n    :attr:`scroll_type` is a :class:`~kivy.properties.OptionProperty`, defaults\n    to ['content'].\n    '''\n\n    # private, for internal use only\n\n    _viewport = ObjectProperty(None, allownone=True)\n    _bar_color = ListProperty([0, 0, 0, 0])\n\n    def _set_viewport_size(self, instance, value):\n        self.viewport_size = value\n\n    def on__viewport(self, instance, value):\n        if value:\n            value.bind(size=self._set_viewport_size)\n            self.viewport_size = value.size\n\n    __events__ = ('on_scroll_start', 'on_scroll_move', 'on_scroll_stop')\n\n    def __init__(self, **kwargs):\n        self._touch = None\n        self._trigger_update_from_scroll = Clock.create_trigger(\n            self.update_from_scroll, -1)\n        # create a specific canvas for the viewport\n        from kivy.graphics import PushMatrix, Translate, PopMatrix, Canvas\n        self.canvas_viewport = Canvas()\n        self.canvas = Canvas()\n        with self.canvas_viewport.before:\n            PushMatrix()\n            self.g_translate = Translate(0, 0)\n        with self.canvas_viewport.after:\n            PopMatrix()\n\n        super(ScrollView, self).__init__(**kwargs)\n\n        self.register_event_type('on_scroll_start')\n        self.register_event_type('on_scroll_move')\n        self.register_event_type('on_scroll_stop')\n\n        # now add the viewport canvas to our canvas\n        self.canvas.add(self.canvas_viewport)\n\n        effect_cls = self.effect_cls\n        if isinstance(effect_cls, string_types):\n            effect_cls = Factory.get(effect_cls)\n        if self.effect_x is None and effect_cls is not None:\n            self.effect_x = effect_cls(target_widget=self._viewport)\n        if self.effect_y is None and effect_cls is not None:\n            self.effect_y = effect_cls(target_widget=self._viewport)\n        self.bind(\n            width=self._update_effect_x_bounds,\n            height=self._update_effect_y_bounds,\n            viewport_size=self._update_effect_bounds,\n            _viewport=self._update_effect_widget,\n            scroll_x=self._trigger_update_from_scroll,\n            scroll_y=self._trigger_update_from_scroll,\n            pos=self._trigger_update_from_scroll,\n            size=self._trigger_update_from_scroll)\n\n        self._update_effect_widget()\n        self._update_effect_x_bounds()\n        self._update_effect_y_bounds()\n\n    def on_effect_x(self, instance, value):\n        if value:\n            value.bind(scroll=self._update_effect_x)\n            value.target_widget = self._viewport\n\n    def on_effect_y(self, instance, value):\n        if value:\n            value.bind(scroll=self._update_effect_y)\n            value.target_widget = self._viewport\n\n    def on_effect_cls(self, instance, cls):\n        if isinstance(cls, string_types):\n            cls = Factory.get(cls)\n        self.effect_x = cls(target_widget=self._viewport)\n        self.effect_x.bind(scroll=self._update_effect_x)\n        self.effect_y = cls(target_widget=self._viewport)\n        self.effect_y.bind(scroll=self._update_effect_y)\n\n    def _update_effect_widget(self, *args):\n        if self.effect_x:\n            self.effect_x.target_widget = self._viewport\n        if self.effect_y:\n            self.effect_y.target_widget = self._viewport\n\n    def _update_effect_x_bounds(self, *args):\n        if not self._viewport or not self.effect_x:\n            return\n        self.effect_x.min = -(self.viewport_size[0] - self.width)\n        self.effect_x.max = 0\n        self.effect_x.value = self.effect_x.min * self.scroll_x\n\n    def _update_effect_y_bounds(self, *args):\n        if not self._viewport or not self.effect_y:\n            return\n        self.effect_y.min = -(self.viewport_size[1] - self.height)\n        self.effect_y.max = 0\n        self.effect_y.value = self.effect_y.min * self.scroll_y\n\n    def _update_effect_bounds(self, *args):\n        if not self._viewport:\n            return\n        if self.effect_x:\n            self._update_effect_x_bounds()\n        if self.effect_y:\n            self._update_effect_y_bounds()\n\n    def _update_effect_x(self, *args):\n        vp = self._viewport\n        if not vp or not self.effect_x:\n            return\n        sw = vp.width - self.width\n        if sw < 1:\n            return\n        sx = self.effect_x.scroll / float(sw)\n        self.scroll_x = -sx\n        self._trigger_update_from_scroll()\n\n    def _update_effect_y(self, *args):\n        vp = self._viewport\n        if not vp or not self.effect_y:\n            return\n        sh = vp.height - self.height\n        if sh < 1:\n            return\n        sy = self.effect_y.scroll / float(sh)\n        self.scroll_y = -sy\n        self._trigger_update_from_scroll()\n\n    def to_local(self, x, y, **k):\n        tx, ty = self.g_translate.xy\n        return x - tx, y - ty\n\n    def to_parent(self, x, y, **k):\n        tx, ty = self.g_translate.xy\n        return x + tx, y + ty\n\n    def _apply_transform(self, m):\n        tx, ty = self.g_translate.xy\n        m.translate(tx, ty, 0)\n        return super(ScrollView, self)._apply_transform(m)\n\n    def simulate_touch_down(self, touch):\n        # at this point the touch is in parent coords\n        touch.push()\n        touch.apply_transform_2d(self.to_local)\n        ret = super(ScrollView, self).on_touch_down(touch)\n        touch.pop()\n        return ret\n\n    def on_touch_down(self, touch):\n        if self.dispatch('on_scroll_start', touch):\n            self._touch = touch\n            touch.grab(self)\n            return True\n\n    def on_scroll_start(self, touch, check_children=True):\n        if check_children:\n            touch.push()\n            touch.apply_transform_2d(self.to_local)\n            if self.dispatch_children('on_scroll_start', touch):\n                return True\n            touch.pop()\n\n        if not self.collide_point(*touch.pos):\n            touch.ud[self._get_uid('svavoid')] = True\n            return\n        if self.disabled:\n            return True\n        if self._touch or (not (self.do_scroll_x or self.do_scroll_y)):\n            return self.simulate_touch_down(touch)\n\n        # handle mouse scrolling, only if the viewport size is bigger than the\n        # scrollview size, and if the user allowed to do it\n        vp = self._viewport\n        if not vp:\n            return True\n        scroll_type = self.scroll_type\n        ud = touch.ud\n        scroll_bar = 'bars' in scroll_type\n\n        # check if touch is in bar_x(horizontal) or bay_y(bertical)\n        ud['in_bar_x'] = ud['in_bar_y'] = False\n        width_scrollable = vp.width > self.width\n        height_scrollable = vp.height > self.height\n        bar_pos_x = self.bar_pos_x[0]\n        bar_pos_y = self.bar_pos_y[0]\n\n        d = {'b': True if touch.y < self.y + self.bar_width else False,\n             't': True if touch.y > self.top - self.bar_width else False,\n             'l': True if touch.x < self.x + self.bar_width else False,\n             'r': True if touch.x > self.right - self.bar_width else False}\n        if scroll_bar:\n            if (width_scrollable and d[bar_pos_x]):\n                ud['in_bar_x'] = True\n            if (height_scrollable and d[bar_pos_y]):\n                ud['in_bar_y'] = True\n\n        if vp and 'button' in touch.profile and \\\n                touch.button.startswith('scroll'):\n            btn = touch.button\n            m = sp(self.scroll_wheel_distance)\n            e = None\n\n            if ((btn == 'scrolldown' and self.scroll_y >= 1) or\n                (btn == 'scrollup' and self.scroll_y <= 0) or\n                (btn == 'scrollleft' and self.scroll_x >= 1) or\n                (btn == 'scrollright' and self.scroll_x <= 0)):\n                return False\n\n            if (self.effect_x and self.do_scroll_y and height_scrollable\n                    and btn in ('scrolldown', 'scrollup')):\n                e = self.effect_x if ud['in_bar_x'] else self.effect_y\n\n            elif (self.effect_y and self.do_scroll_x and width_scrollable\n                    and btn in ('scrollleft', 'scrollright')):\n                e = self.effect_y if ud['in_bar_y'] else self.effect_x\n\n            if e:\n                if btn in ('scrolldown', 'scrollleft'):\n                    e.value = max(e.value - m, e.min)\n                    e.velocity = 0\n                elif btn in ('scrollup', 'scrollright'):\n                    e.value = min(e.value + m, e.max)\n                    e.velocity = 0\n                touch.ud[self._get_uid('svavoid')] = True\n                e.trigger_velocity_update()\n            return True\n\n        # no mouse scrolling, so the user is going to drag the scrollview with\n        # this touch.\n        self._touch = touch\n        uid = self._get_uid()\n\n        ud[uid] = {\n            'mode': 'unknown',\n            'dx': 0,\n            'dy': 0,\n            'user_stopped': False,\n            'frames': Clock.frames,\n            'time': touch.time_start}\n\n        if self.do_scroll_x and self.effect_x and not ud['in_bar_x']:\n            self.effect_x.start(touch.x)\n            self._scroll_x_mouse = self.scroll_x\n        if self.do_scroll_y and self.effect_y and not ud['in_bar_y']:\n            self.effect_y.start(touch.y)\n            self._scroll_y_mouse = self.scroll_y\n\n        if (ud.get('in_bar_x', False) or ud.get('in_bar_y', False)):\n            return True\n\n        Clock.schedule_once(self._change_touch_mode,\n                                self.scroll_timeout / 1000.)\n        if scroll_type == ['bars']:\n            return False\n        else:\n            return True\n\n    def on_touch_move(self, touch):\n        if self._touch is not touch:\n            # touch is in parent\n            touch.push()\n            touch.apply_transform_2d(self.to_local)\n            super(ScrollView, self).on_touch_move(touch)\n            touch.pop()\n            return self._get_uid() in touch.ud\n        if touch.grab_current is not self:\n            return True\n\n        if not (self.do_scroll_y or self.do_scroll_x):\n            return super(ScrollView, self).on_touch_move(touch)\n\n        touch.ud['sv.handled'] = {'x': False, 'y': False}\n        if self.dispatch('on_scroll_move', touch):\n            return True\n\n    def on_scroll_move(self, touch):\n        if self._get_uid('svavoid') in touch.ud:\n            return False\n\n        touch.push()\n        touch.apply_transform_2d(self.to_local)\n        if self.dispatch_children('on_scroll_move', touch):\n            return True\n        touch.pop()\n\n        rv = True\n\n        uid = self._get_uid()\n        if not uid in touch.ud:\n            self._touch = False\n            return self.on_scroll_start(touch, False)\n        ud = touch.ud[uid]\n        mode = ud['mode']\n\n        # check if the minimum distance has been travelled\n        if mode == 'unknown' or mode == 'scroll':\n            if not touch.ud['sv.handled']['x'] and self.do_scroll_x \\\n                    and self.effect_x:\n                width = self.width\n                if touch.ud.get('in_bar_x', False):\n                    dx = touch.dx / float(width - width * self.hbar[1])\n                    self.scroll_x = min(max(self.scroll_x + dx, 0.), 1.)\n                    self._trigger_update_from_scroll()\n                else:\n                    if self.scroll_type != ['bars']:\n                        self.effect_x.update(touch.x)\n                if self.scroll_x < 0 or self.scroll_x > 1:\n                    rv = False\n                else:\n                    touch.ud['sv.handled']['x'] = True\n            if not touch.ud['sv.handled']['y'] and self.do_scroll_y \\\n                    and self.effect_y:\n                height = self.height\n                if touch.ud.get('in_bar_y', False):\n                    dy = touch.dy / float(height - height * self.vbar[1])\n                    self.scroll_y = min(max(self.scroll_y + dy, 0.), 1.)\n                    self._trigger_update_from_scroll()\n                else:\n                    if self.scroll_type != ['bars']:\n                        self.effect_y.update(touch.y)\n                if self.scroll_y < 0 or self.scroll_y > 1:\n                    rv = False\n                else:\n                    touch.ud['sv.handled']['y'] = True\n\n        if mode == 'unknown':\n            ud['dx'] += abs(touch.dx)\n            ud['dy'] += abs(touch.dy)\n            if ud['dx'] > self.scroll_distance:\n                if not self.do_scroll_x:\n                    # touch is in parent, but _change expects window coords\n                    touch.push()\n                    touch.apply_transform_2d(self.to_local)\n                    touch.apply_transform_2d(self.to_window)\n                    self._change_touch_mode()\n                    touch.pop()\n                    return\n                mode = 'scroll'\n\n            if ud['dy'] > self.scroll_distance:\n                if not self.do_scroll_y:\n                    # touch is in parent, but _change expects window coords\n                    touch.push()\n                    touch.apply_transform_2d(self.to_local)\n                    touch.apply_transform_2d(self.to_window)\n                    self._change_touch_mode()\n                    touch.pop()\n                    return\n                mode = 'scroll'\n            ud['mode'] = mode\n\n        if mode == 'scroll':\n            ud['dt'] = touch.time_update - ud['time']\n            ud['time'] = touch.time_update\n            ud['user_stopped'] = True\n\n        return rv\n\n    def on_touch_up(self, touch):\n        if self._touch is not touch and self.uid not in touch.ud:\n            # touch is in parents\n            touch.push()\n            touch.apply_transform_2d(self.to_local)\n            if super(ScrollView, self).on_touch_up(touch):\n                return True\n            touch.pop()\n            return False\n\n        if self.dispatch('on_scroll_stop', touch):\n            touch.ungrab(self)\n            return True\n\n    def on_scroll_stop(self, touch, check_children=True):\n        self._touch = None\n\n        if check_children:\n            touch.push()\n            touch.apply_transform_2d(self.to_local)\n            if self.dispatch_children('on_scroll_stop', touch):\n                return True\n            touch.pop()\n\n        if self._get_uid('svavoid') in touch.ud:\n            return\n        if self._get_uid() not in touch.ud:\n            return False\n\n        self._touch = None\n        uid = self._get_uid()\n        ud = touch.ud[uid]\n        if self.do_scroll_x and self.effect_x:\n            if not touch.ud.get('in_bar_x', False) and\\\n                    self.scroll_type != ['bars']:\n                self.effect_x.stop(touch.x)\n        if self.do_scroll_y and self.effect_y and\\\n                self.scroll_type != ['bars']:\n            if not touch.ud.get('in_bar_y', False):\n                self.effect_y.stop(touch.y)\n        if ud['mode'] == 'unknown':\n            # we must do the click at least..\n            # only send the click if it was not a click to stop\n            # autoscrolling\n            if not ud['user_stopped']:\n                self.simulate_touch_down(touch)\n            Clock.schedule_once(partial(self._do_touch_up, touch), .2)\n        Clock.unschedule(self._update_effect_bounds)\n        Clock.schedule_once(self._update_effect_bounds)\n\n        # if we do mouse scrolling, always accept it\n        if 'button' in touch.profile and touch.button.startswith('scroll'):\n            return True\n\n        return self._get_uid() in touch.ud\n\n    def convert_distance_to_scroll(self, dx, dy):\n        '''Convert a distance in pixels to a scroll distance, depending on the\n        content size and the scrollview size.\n\n        The result will be a tuple of scroll distance that can be added to\n        :data:`scroll_x` and :data:`scroll_y`\n        '''\n        if not self._viewport:\n            return 0, 0\n        vp = self._viewport\n        if vp.width > self.width:\n            sw = vp.width - self.width\n            sx = dx / float(sw)\n        else:\n            sx = 0\n        if vp.height > self.height:\n            sh = vp.height - self.height\n            sy = dy / float(sh)\n        else:\n            sy = 1\n        return sx, sy\n\n    def update_from_scroll(self, *largs):\n        '''Force the reposition of the content, according to current value of\n        :attr:`scroll_x` and :attr:`scroll_y`.\n\n        This method is automatically called when one of the :attr:`scroll_x`,\n        :attr:`scroll_y`, :attr:`pos` or :attr:`size` properties change, or\n        if the size of the content changes.\n        '''\n        if not self._viewport:\n            return\n        vp = self._viewport\n\n        # update from size_hint\n        if vp.size_hint_x is not None:\n            vp.width = vp.size_hint_x * self.width\n        if vp.size_hint_y is not None:\n            vp.height = vp.size_hint_y * self.height\n\n        if vp.width > self.width:\n            sw = vp.width - self.width\n            x = self.x - self.scroll_x * sw\n        else:\n            x = self.x\n        if vp.height > self.height:\n            sh = vp.height - self.height\n            y = self.y - self.scroll_y * sh\n        else:\n            y = self.top - vp.height\n\n        # from 1.8.0, we now use a matrix by default, instead of moving the\n        # widget position behind. We set it here, but it will be a no-op most of\n        # the time.\n        vp.pos = 0, 0\n        self.g_translate.xy = x, y\n\n        # New in 1.2.0, show bar when scrolling happens and (changed in 1.9.0)\n        # fade to bar_inactive_color when no scroll is happening.\n        Clock.unschedule(self._bind_inactive_bar_color)\n        self.unbind(bar_inactive_color=self._change_bar_color)\n        Animation.stop_all(self, '_bar_color')\n        self.bind(bar_color=self._change_bar_color)\n        self._bar_color = self.bar_color\n        Clock.schedule_once(self._bind_inactive_bar_color, .5)\n\n    def _bind_inactive_bar_color(self, *l):\n        self.unbind(bar_color=self._change_bar_color)\n        self.bind(bar_inactive_color=self._change_bar_color)\n        Animation(\n            _bar_color=self.bar_inactive_color, d=.5, t='out_quart').start(self)\n\n    def _change_bar_color(self, inst, value):\n        self._bar_color = value\n\n    #\n    # Private\n    #\n    def add_widget(self, widget, index=0):\n        if self._viewport:\n            raise Exception('ScrollView accept only one widget')\n        canvas = self.canvas\n        self.canvas = self.canvas_viewport\n        super(ScrollView, self).add_widget(widget, index)\n        self.canvas = canvas\n        self._viewport = widget\n        widget.bind(size=self._trigger_update_from_scroll)\n        self._trigger_update_from_scroll()\n\n    def remove_widget(self, widget):\n        canvas = self.canvas\n        self.canvas = self.canvas_viewport\n        super(ScrollView, self).remove_widget(widget)\n        self.canvas = canvas\n        if widget is self._viewport:\n            self._viewport = None\n\n    def _get_uid(self, prefix='sv'):\n        return '{0}.{1}'.format(prefix, self.uid)\n\n    def _change_touch_mode(self, *largs):\n        if not self._touch:\n            return\n        uid = self._get_uid()\n        touch = self._touch\n        if uid not in touch.ud:\n            self._touch = False\n            return\n        ud = touch.ud[uid]\n        if ud['mode'] != 'unknown' or ud['user_stopped']:\n            return\n        diff_frames = Clock.frames - ud['frames']\n\n        # in order to be able to scroll on very slow devices, let at least 3\n        # frames displayed to accumulate some velocity. And then, change the\n        # touch mode. Otherwise, we might never be able to compute velocity, and\n        # no way to scroll it. See #1464 and #1499\n        if diff_frames < 3:\n            Clock.schedule_once(self._change_touch_mode, 0)\n            return\n\n        if self.do_scroll_x and self.effect_x:\n            self.effect_x.cancel()\n        if self.do_scroll_y and self.effect_y:\n            self.effect_y.cancel()\n        # XXX the next line was in the condition. But this stop\n        # the possibily to \"drag\" an object out of the scrollview in the\n        # non-used direction: if you have an horizontal scrollview, a\n        # vertical gesture will not \"stop\" the scroll view to look for an\n        # horizontal gesture, until the timeout is done.\n        # and touch.dx + touch.dy == 0:\n        touch.ungrab(self)\n        self._touch = None\n        # touch is in window coords\n        touch.push()\n        touch.apply_transform_2d(self.to_widget)\n        touch.apply_transform_2d(self.to_parent)\n        self.simulate_touch_down(touch)\n        touch.pop()\n        return\n\n    def _do_touch_up(self, touch, *largs):\n        # touch is in window coords\n        touch.push()\n        touch.apply_transform_2d(self.to_widget)\n        super(ScrollView, self).on_touch_up(touch)\n        touch.pop()\n        # don't forget about grab event!\n        for x in touch.grab_list[:]:\n            touch.grab_list.remove(x)\n            x = x()\n            if not x:\n                continue\n            touch.grab_current = x\n            # touch is in window coords\n            touch.push()\n            touch.apply_transform_2d(self.to_widget)\n            super(ScrollView, self).on_touch_up(touch)\n            touch.pop()\n        touch.grab_current = None\n\n\nif __name__ == '__main__':\n    from kivy.app import App\n\n    from kivy.uix.gridlayout import GridLayout\n    from kivy.uix.button import Button\n\n    class ScrollViewApp(App):\n\n        def build(self):\n            layout1 = GridLayout(cols=4, spacing=10, size_hint=(None, None))\n            layout1.bind(minimum_height=layout1.setter('height'),\n                         minimum_width=layout1.setter('width'))\n            for i in range(40):\n                btn = Button(text=str(i), size_hint=(None, None),\n                             size=(200, 100))\n                layout1.add_widget(btn)\n            scrollview1 = ScrollView(bar_width='2dp')\n            scrollview1.add_widget(layout1)\n\n            layout2 = GridLayout(cols=4, spacing=10, size_hint=(None, None))\n            layout2.bind(minimum_height=layout2.setter('height'),\n                         minimum_width=layout2.setter('width'))\n            for i in range(40):\n                btn = Button(text=str(i), size_hint=(None, None),\n                             size=(200, 100))\n                layout2.add_widget(btn)\n            scrollview2 = ScrollView(scroll_type=['bars'],\n                                     bar_width='9dp',\n                                     scroll_wheel_distance=100)\n            scrollview2.add_widget(layout2)\n\n            root = GridLayout(cols=2)\n            root.add_widget(scrollview1)\n            root.add_widget(scrollview2)\n            return root\n\n    ScrollViewApp().run()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/selectableview.py",
    "content": "from kivy.properties import NumericProperty, BooleanProperty\n\n\nclass SelectableView(object):\n    '''The :class:`SelectableView` mixin is used with list items and other\n    classes that are to be instantiated in a list view or other classes\n    which use a selection-enabled adapter such as ListAdapter. select() and\n    deselect() can be overridden with display code to mark items as\n    selected or not, if desired.\n    '''\n\n    index = NumericProperty(-1)\n    '''The index into the underlying data list or the data item this view\n    represents.\n    '''\n\n    is_selected = BooleanProperty(False)\n    '''A SelectableView instance carries this property which should be kept\n    in sync with the equivalent property the data item represents.\n    '''\n\n    def __init__(self, **kwargs):\n        super(SelectableView, self).__init__(**kwargs)\n\n    def select(self, *args):\n        '''The list item is responsible for updating the display when\n        being selected, if desired.\n        '''\n        self.is_selected = True\n\n    def deselect(self, *args):\n        '''The list item is responsible for updating the display when\n        being unselected, if desired.\n        '''\n        self.is_selected = False\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/settings.py",
    "content": "'''\nSettings\n========\n\n.. versionadded:: 1.0.7\n\nThis module is a complete and extensible framework for adding a\nSettings interface to your application. By default, the interface uses\na :class:`SettingsWithSpinner`, which consists of a\n:class:`~kivy.uix.spinner.Spinner` (top) to switch between individual\nsettings panels (bottom). See :ref:`differentlayouts` for some\nalternatives.\n\n.. image:: images/settingswithspinner_kivy.jpg\n    :align: center\n\nA :class:`SettingsPanel` represents a group of configurable options. The\n:attr:`SettingsPanel.title` property is used by :class:`Settings` when a panel\nis added - it determines the name of the sidebar button. SettingsPanel controls\na :class:`~kivy.config.ConfigParser` instance.\n\nThe panel can be automatically constructed from a JSON definition file: you\ndescribe the settings you want and corresponding sections/keys in the\nConfigParser instance... and you're done!\n\nSettings are also integrated with the :class:`~kivy.app.App` class. Use\n:meth:`Settings.add_kivy_panel` to configure the Kivy core settings in a panel.\n\n\n.. _settings_json:\n\nCreate a panel from JSON\n------------------------\n\nTo create a panel from a JSON-file, you need two things:\n\n    * a :class:`~kivy.config.ConfigParser` instance with default values\n    * a JSON file\n\n.. warning::\n\n    The :class:`kivy.config.ConfigParser` is required. You cannot use the\n    default ConfigParser from Python libraries.\n\nYou must create and handle the :class:`~kivy.config.ConfigParser`\nobject. SettingsPanel will read the values from the associated\nConfigParser instance. Make sure you have default values for all sections/keys\nin your JSON file!\n\nThe JSON file contains structured information to describe the available\nsettings. Here is an example::\n\n    [\n        {\n            \"type\": \"title\",\n            \"title\": \"Windows\"\n        },\n        {\n            \"type\": \"bool\",\n            \"title\": \"Fullscreen\",\n            \"desc\": \"Set the window in windowed or fullscreen\",\n            \"section\": \"graphics\",\n            \"key\": \"fullscreen\",\n            \"true\": \"auto\"\n        }\n    ]\n\nEach element in the root list represents a setting that the user can configure.\nOnly the \"type\" key is mandatory: an instance of the associated class will be\ncreated and used for the setting - other keys are assigned to corresponding\nproperties of that class.\n\n    ============== =================================================\n     Type           Associated class\n    -------------- -------------------------------------------------\n    title          :class:`SettingTitle`\n    bool           :class:`SettingBoolean`\n    numeric        :class:`SettingNumeric`\n    options        :class:`SettingOptions`\n    string         :class:`SettingString`\n    path           :class:`SettingPath` (new from 1.1.0)\n    ============== =================================================\n\nIn the JSON example above, the first element is of type \"title\". It will create\na new instance of :class:`SettingTitle` and apply the rest of the key/value\npairs to the properties of that class, i.e. \"title\": \"Windows\" sets the\n:attr:`SettingTitle.title` property to \"Windows\".\n\nTo load the JSON example to a :class:`Settings` instance, use the\n:meth:`Settings.add_json_panel` method. It will automatically instantiate a\n:class:`SettingsPanel` and add it to :class:`Settings`::\n\n    from kivy.config import ConfigParser\n\n    config = ConfigParser()\n    config.read('myconfig.ini')\n\n    s = Settings()\n    s.add_json_panel('My custom panel', config, 'settings_custom.json')\n    s.add_json_panel('Another panel', config, 'settings_test2.json')\n\n    # then use the s as a widget...\n\n\n.. _differentlayouts:\n\nDifferent panel layouts\n-----------------------\n\nA kivy :class:`~kivy.app.App` can automatically create and display a\n:class:`Settings` instance. See the :attr:`~kivy.app.App.settings_cls`\ndocumentation for details on how to choose which settings class to\ndisplay.\n\nSeveral pre-built settings widgets are available. All except\n:class:`SettingsWithNoMenu` include close buttons triggering the\non_close event.\n\n- :class:`Settings`: Displays settings with a sidebar at the left to\n  switch between json panels.\n\n- :class:`SettingsWithSidebar`: A trivial subclass of\n  :class:`Settings`.\n\n- :class:`SettingsWithSpinner`: Displays settings with a spinner at\n  the top, which can be used to switch between json panels. Uses\n  :class:`InterfaceWithSpinner` as the\n  :attr:`~Settings.interface_cls`. This is the default behavior from\n  Kivy 1.8.0.\n\n- :class:`SettingsWithTabbedPanel`: Displays json panels as individual\n  tabs in a :class:`~kivy.uix.tabbedpanel.TabbedPanel`. Uses\n  :class:`InterfaceWithTabbedPanel` as the :attr:`~Settings.interface_cls`.\n\n- :class:`SettingsWithNoMenu`: Displays a single json panel, with no\n  way to switch to other panels and no close button. This makes it\n  impossible for the user to exit unless\n  :meth:`~kivy.app.App.close_settings` is overridden with a different\n  close trigger! Uses :class:`InterfaceWithNoMenu` as the\n  :attr:`~Settings.interface_cls`.\n\nYou can construct your own settings panels with any layout you choose\nby setting :attr:`Settings.interface_cls`. This should be a widget\nthat displays a json settings panel with some way to switch between\npanels. An instance will be automatically created by :class:`Settings`.\n\nInterface widgets may be anything you like, but *must* have a method\nadd_panel that recieves newly created json settings panels for the\ninterface to display. See the documentation for\n:class:`InterfaceWithSidebar` for more information. They may\noptionally dispatch an on_close event, for instance if a close button\nis clicked. This event is used by :class:`Settings` to trigger its own\non_close event.\n\n'''\n\n__all__ = ('Settings', 'SettingsPanel', 'SettingItem', 'SettingString',\n           'SettingPath', 'SettingBoolean', 'SettingNumeric', 'SettingOptions',\n           'SettingTitle', 'SettingsWithSidebar', 'SettingsWithSpinner',\n           'SettingsWithTabbedPanel', 'SettingsWithNoMenu',\n           'InterfaceWithSidebar', 'ContentPanel')\n\nimport json\nimport os\nfrom kivy.compat import string_types\nfrom kivy.factory import Factory\nfrom kivy.metrics import dp\nfrom kivy.config import ConfigParser\nfrom kivy.animation import Animation\nfrom kivy.compat import string_types, text_type\nfrom kivy.core.window import Window\nfrom kivy.uix.boxlayout import BoxLayout\nfrom kivy.uix.tabbedpanel import TabbedPanelHeader\nfrom kivy.uix.button import Button\nfrom kivy.uix.filechooser import FileChooserListView\nfrom kivy.uix.scrollview import ScrollView\nfrom kivy.uix.floatlayout import FloatLayout\nfrom kivy.uix.gridlayout import GridLayout\nfrom kivy.uix.label import Label\nfrom kivy.uix.popup import Popup\nfrom kivy.uix.textinput import TextInput\nfrom kivy.uix.togglebutton import ToggleButton\nfrom kivy.uix.widget import Widget\nfrom kivy.properties import ObjectProperty, StringProperty, ListProperty, \\\n    BooleanProperty, NumericProperty, DictProperty\n\n\nclass SettingSpacer(Widget):\n    # Internal class, not documented.\n    pass\n\n\nclass SettingItem(FloatLayout):\n    '''Base class for individual settings (within a panel). This class cannot\n    be used directly; it is used for implementing the other setting classes.\n    It builds a row with a title/description (left) and a setting control\n    (right).\n\n    Look at :class:`SettingBoolean`, :class:`SettingNumeric` and\n    :class:`SettingOptions` for usage examples.\n\n    :Events:\n        `on_release`\n            Fired when the item is touched and then released.\n\n    '''\n\n    title = StringProperty('<No title set>')\n    '''Title of the setting, defaults to '<No title set>'.\n\n    :attr:`title` is a :class:`~kivy.properties.StringProperty` and defaults to\n    '<No title set>'.\n    '''\n\n    desc = StringProperty(None, allownone=True)\n    '''Description of the setting, rendered on the line below the title.\n\n    :attr:`desc` is a :class:`~kivy.properties.StringProperty` and defaults to\n    None.\n    '''\n\n    disabled = BooleanProperty(False)\n    '''Indicate if this setting is disabled. If True, all touches on the\n    setting item will be discarded.\n\n    :attr:`disabled` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    section = StringProperty(None)\n    '''Section of the token inside the :class:`~kivy.config.ConfigParser`\n    instance.\n\n    :attr:`section` is a :class:`~kivy.properties.StringProperty` and defaults\n    to None.\n    '''\n\n    key = StringProperty(None)\n    '''Key of the token inside the :attr:`section` in the\n    :class:`~kivy.config.ConfigParser` instance.\n\n    :attr:`key` is a :class:`~kivy.properties.StringProperty` and defaults to\n    None.\n    '''\n\n    value = ObjectProperty(None)\n    '''Value of the token according to the :class:`~kivy.config.ConfigParser`\n    instance. Any change to this value will trigger a\n    :meth:`Settings.on_config_change` event.\n\n    :attr:`value` is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    panel = ObjectProperty(None)\n    '''(internal) Reference to the SettingsPanel for this setting. You don't\n    need to use it.\n\n    :attr:`panel` is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    content = ObjectProperty(None)\n    '''(internal) Reference to the widget that contains the real setting.\n    As soon as the content object is set, any further call to add_widget will\n    call the content.add_widget. This is automatically set.\n\n    :attr:`content` is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    selected_alpha = NumericProperty(0)\n    '''(internal) Float value from 0 to 1, used to animate the background when\n    the user touches the item.\n\n    :attr:`selected_alpha` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    __events__ = ('on_release', )\n\n    def __init__(self, **kwargs):\n        super(SettingItem, self).__init__(**kwargs)\n        self.value = self.panel.get_value(self.section, self.key)\n\n    def add_widget(self, *largs):\n        if self.content is None:\n            return super(SettingItem, self).add_widget(*largs)\n        return self.content.add_widget(*largs)\n\n    def on_touch_down(self, touch):\n        if not self.collide_point(*touch.pos):\n            return\n        if self.disabled:\n            return\n        touch.grab(self)\n        self.selected_alpha = 1\n        return super(SettingItem, self).on_touch_down(touch)\n\n    def on_touch_up(self, touch):\n        if touch.grab_current is self:\n            touch.ungrab(self)\n            self.dispatch('on_release')\n            Animation(selected_alpha=0, d=.25, t='out_quad').start(self)\n            return True\n        return super(SettingItem, self).on_touch_up(touch)\n\n    def on_release(self):\n        pass\n\n    def on_value(self, instance, value):\n        if not self.section or not self.key:\n            return\n        # get current value in config\n        panel = self.panel\n        if not isinstance(value, string_types):\n            value = str(value)\n        panel.set_value(self.section, self.key, value)\n\n\nclass SettingBoolean(SettingItem):\n    '''Implementation of a boolean setting on top of a :class:`SettingItem`. It\n    is visualized with a :class:`~kivy.uix.switch.Switch` widget. By default,\n    0 and 1 are used for values: you can change them by setting :attr:`values`.\n    '''\n\n    values = ListProperty(['0', '1'])\n    '''Values used to represent the state of the setting. If you want to use\n    \"yes\" and \"no\" in your ConfigParser instance::\n\n        SettingBoolean(..., values=['no', 'yes'])\n\n    .. warning::\n\n        You need a minimum of two values, the index 0 will be used as False,\n        and index 1 as True\n\n    :attr:`values` is a :class:`~kivy.properties.ListProperty` and defaults to\n    ['0', '1']\n    '''\n\n\nclass SettingString(SettingItem):\n    '''Implementation of a string setting on top of a :class:`SettingItem`.\n    It is visualized with a :class:`~kivy.uix.label.Label` widget that, when\n    clicked, will open a :class:`~kivy.uix.popup.Popup` with a\n    :class:`~kivy.uix.textinput.Textinput` so the user can enter a custom\n    value.\n    '''\n\n    popup = ObjectProperty(None, allownone=True)\n    '''(internal) Used to store the current popup when it's shown.\n\n    :attr:`popup` is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    textinput = ObjectProperty(None)\n    '''(internal) Used to store the current textinput from the popup and\n    to listen for changes.\n\n    :attr:`textinput` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    def on_panel(self, instance, value):\n        if value is None:\n            return\n        self.bind(on_release=self._create_popup)\n\n    def _dismiss(self, *largs):\n        if self.textinput:\n            self.textinput.focus = False\n        if self.popup:\n            self.popup.dismiss()\n        self.popup = None\n\n    def _validate(self, instance):\n        self._dismiss()\n        value = self.textinput.text.strip()\n        self.value = value\n\n    def _create_popup(self, instance):\n        # create popup layout\n        content = BoxLayout(orientation='vertical', spacing='5dp')\n        popup_width = min(0.95 * Window.width, dp(500))\n        self.popup = popup = Popup(\n            title=self.title, content=content, size_hint=(None, None),\n            size=(popup_width, '250dp'))\n\n        # create the textinput used for numeric input\n        self.textinput = textinput = TextInput(\n            text=self.value, font_size='24sp', multiline=False,\n            size_hint_y=None, height='42sp')\n        textinput.bind(on_text_validate=self._validate)\n        self.textinput = textinput\n\n        # construct the content, widget are used as a spacer\n        content.add_widget(Widget())\n        content.add_widget(textinput)\n        content.add_widget(Widget())\n        content.add_widget(SettingSpacer())\n\n        # 2 buttons are created for accept or cancel the current value\n        btnlayout = BoxLayout(size_hint_y=None, height='50dp', spacing='5dp')\n        btn = Button(text='Ok')\n        btn.bind(on_release=self._validate)\n        btnlayout.add_widget(btn)\n        btn = Button(text='Cancel')\n        btn.bind(on_release=self._dismiss)\n        btnlayout.add_widget(btn)\n        content.add_widget(btnlayout)\n\n        # all done, open the popup !\n        popup.open()\n\n\nclass SettingPath(SettingItem):\n    '''Implementation of a Path setting on top of a :class:`SettingItem`.\n    It is visualized with a :class:`~kivy.uix.label.Label` widget that, when\n    clicked, will open a :class:`~kivy.uix.popup.Popup` with a\n    :class:`~kivy.uix.filechooser.FileChooserListView` so the user can enter\n    a custom value.\n\n    .. versionadded:: 1.1.0\n    '''\n\n    popup = ObjectProperty(None, allownone=True)\n    '''(internal) Used to store the current popup when it is shown.\n\n    :attr:`popup` is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    textinput = ObjectProperty(None)\n    '''(internal) Used to store the current textinput from the popup and\n    to listen for changes.\n\n    :attr:`textinput` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    def on_panel(self, instance, value):\n        if value is None:\n            return\n        self.bind(on_release=self._create_popup)\n\n    def _dismiss(self, *largs):\n        if self.textinput:\n            self.textinput.focus = False\n        if self.popup:\n            self.popup.dismiss()\n        self.popup = None\n\n    def _validate(self, instance):\n        self._dismiss()\n        value = self.textinput.selection\n\n        if not value:\n            return\n\n        self.value = os.path.realpath(value[0])\n\n    def _create_popup(self, instance):\n        # create popup layout\n        content = BoxLayout(orientation='vertical', spacing=5)\n        popup_width = min(0.95 * Window.width, dp(500))\n        self.popup = popup = Popup(\n            title=self.title, content=content, size_hint=(None, 0.9),\n            width=popup_width)\n\n        # create the filechooser\n        self.textinput = textinput = FileChooserListView(\n            path=self.value, size_hint=(1, 1), dirselect=True)\n        textinput.bind(on_path=self._validate)\n        self.textinput = textinput\n\n        # construct the content\n        content.add_widget(textinput)\n        content.add_widget(SettingSpacer())\n\n        # 2 buttons are created for accept or cancel the current value\n        btnlayout = BoxLayout(size_hint_y=None, height='50dp', spacing='5dp')\n        btn = Button(text='Ok')\n        btn.bind(on_release=self._validate)\n        btnlayout.add_widget(btn)\n        btn = Button(text='Cancel')\n        btn.bind(on_release=self._dismiss)\n        btnlayout.add_widget(btn)\n        content.add_widget(btnlayout)\n\n        # all done, open the popup !\n        popup.open()\n\n\nclass SettingNumeric(SettingString):\n    '''Implementation of a numeric setting on top of a :class:`SettingString`.\n    It is visualized with a :class:`~kivy.uix.label.Label` widget that, when\n    clicked, will open a :class:`~kivy.uix.popup.Popup` with a\n    :class:`~kivy.uix.textinput.Textinput` so the user can enter a custom\n    value.\n    '''\n\n    def _validate(self, instance):\n        # we know the type just by checking if there is a '.' in the original\n        # value\n        is_float = '.' in str(self.value)\n        self._dismiss()\n        try:\n            if is_float:\n                self.value = text_type(float(self.textinput.text))\n            else:\n                self.value = text_type(int(self.textinput.text))\n        except ValueError:\n            return\n\n\nclass SettingOptions(SettingItem):\n    '''Implementation of an option list on top of a :class:`SettingItem`.\n    It is visualized with a :class:`~kivy.uix.label.Label` widget that, when\n    clicked, will open a :class:`~kivy.uix.popup.Popup` with a\n    list of options from which the user can select.\n    '''\n\n    options = ListProperty([])\n    '''List of all availables options. This must be a list of \"string\" items.\n    Otherwise, it will crash. :)\n\n    :attr:`options` is a :class:`~kivy.properties.ListProperty` and defaults\n    to [].\n    '''\n\n    popup = ObjectProperty(None, allownone=True)\n    '''(internal) Used to store the current popup when it is shown.\n\n    :attr:`popup` is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    def on_panel(self, instance, value):\n        if value is None:\n            return\n        self.bind(on_release=self._create_popup)\n\n    def _set_option(self, instance):\n        self.value = instance.text\n        self.popup.dismiss()\n\n    def _create_popup(self, instance):\n        # create the popup\n        content = BoxLayout(orientation='vertical', spacing='5dp')\n        popup_width = min(0.95 * Window.width, dp(500))\n        self.popup = popup = Popup(\n            content=content, title=self.title, size_hint=(None, None),\n            size=(popup_width, '400dp'))\n        popup.height = len(self.options) * dp(55) + dp(150)\n\n        # add all the options\n        content.add_widget(Widget(size_hint_y=None, height=1))\n        uid = str(self.uid)\n        for option in self.options:\n            state = 'down' if option == self.value else 'normal'\n            btn = ToggleButton(text=option, state=state, group=uid)\n            btn.bind(on_release=self._set_option)\n            content.add_widget(btn)\n\n        # finally, add a cancel button to return on the previous panel\n        content.add_widget(SettingSpacer())\n        btn = Button(text='Cancel', size_hint_y=None, height=dp(50))\n        btn.bind(on_release=popup.dismiss)\n        content.add_widget(btn)\n\n        # and open the popup !\n        popup.open()\n\n\nclass SettingTitle(Label):\n    '''A simple title label, used to organize the settings in sections.\n    '''\n\n    title = Label.text\n\n\nclass SettingsPanel(GridLayout):\n    '''This class is used to contruct panel settings, for use with a\n    :class:`Settings` instance or subclass.\n    '''\n\n    title = StringProperty('Default title')\n    '''Title of the panel. The title will be reused by the :class:`Settings` in\n    the sidebar.\n    '''\n\n    config = ObjectProperty(None, allownone=True)\n    '''A :class:`kivy.config.ConfigParser` instance. See module documentation\n    for more information.\n    '''\n\n    settings = ObjectProperty(None)\n    '''A :class:`Settings` instance that will be used to fire the\n    `on_config_change` event.\n    '''\n\n    def __init__(self, **kwargs):\n        kwargs.setdefault('cols', 1)\n        super(SettingsPanel, self).__init__(**kwargs)\n\n    def on_config(self, instance, value):\n        if value is None:\n            return\n        if not isinstance(value, ConfigParser):\n            raise Exception('Invalid config object, you must use a'\n                            'kivy.config.ConfigParser, not another one !')\n\n    def get_value(self, section, key):\n        '''Return the value of the section/key from the :attr:`config`\n        ConfigParser instance. This function is used by :class:`SettingItem` to\n        get the value for a given section/key.\n\n        If you don't want to use a ConfigParser instance, you might want to\n        override this function.\n        '''\n        config = self.config\n        if not config:\n            return\n        return config.get(section, key)\n\n    def set_value(self, section, key, value):\n        current = self.get_value(section, key)\n        if current == value:\n            return\n        config = self.config\n        if config:\n            config.set(section, key, value)\n            config.write()\n        settings = self.settings\n        if settings:\n            settings.dispatch('on_config_change',\n                              config, section, key, value)\n\n\nclass InterfaceWithSidebar(BoxLayout):\n    '''The default Settings interface class. It displays a sidebar menu\n    with names of available settings panels, which may be used to switch\n    which one is currently displayed.\n\n    See :meth:`~InterfaceWithSidebar.add_panel` for information on the\n    method you must implement if creating your own interface.\n\n    This class also dispatches an event 'on_close', which is triggered\n    when the sidebar menu's close button is released. If creating your\n    own interface widget, it should also dispatch such an event which\n    will automatically be caught by :class:`Settings` and used to\n    trigger its own 'on_close' event.\n\n    '''\n\n    menu = ObjectProperty()\n    '''(internal) A reference to the sidebar menu widget.\n\n    :attr:`menu` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    content = ObjectProperty()\n    '''(internal) A reference to the panel display widget (a\n    :class:`ContentPanel`).\n\n    :attr:`content` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n\n    '''\n\n    __events__ = ('on_close', )\n\n    def __init__(self, *args, **kwargs):\n        super(InterfaceWithSidebar, self).__init__(*args, **kwargs)\n        self.menu.close_button.bind(\n            on_release=lambda j: self.dispatch('on_close'))\n\n    def add_panel(self, panel, name, uid):\n        '''This method is used by Settings to add new panels for possible\n        display. Any replacement for ContentPanel *must* implement\n        this method.\n\n        :param panel: A :class:`SettingsPanel`. It should be stored\n                      and the interface should provide a way to switch\n                      between panels.\n\n        :param name: The name of the panel as a string. It\n                     may be used to represent the panel but isn't necessarily\n                     unique.\n\n        :param uid: A unique int identifying the panel. It should be\n                    used to identify and switch between panels.\n        '''\n        self.menu.add_item(name, uid)\n        self.content.add_panel(panel, name, uid)\n\n    def on_close(self, *args):\n        pass\n\n\nclass InterfaceWithSpinner(BoxLayout):\n    '''A settings interface that displays a spinner at the top for\n    switching between panels.\n\n    The workings of this class are considered internal and are not\n    documented. See :meth:`InterfaceWithSidebar` for\n    information on implementing your own interface class.\n\n    '''\n\n    __events__ = ('on_close', )\n\n    menu = ObjectProperty()\n    '''(internal) A reference to the sidebar menu widget.\n\n    :attr:`menu` is an :class:`~kivy.properties.ObjectProperty` and\n    defauls to None.\n    '''\n\n    content = ObjectProperty()\n    '''(internal) A reference to the panel display widget (a\n    :class:`ContentPanel`).\n\n    :attr:`menu` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n\n    '''\n\n    def __init__(self, *args, **kwargs):\n        super(InterfaceWithSpinner, self).__init__(*args, **kwargs)\n        self.menu.close_button.bind(\n            on_release=lambda j: self.dispatch('on_close'))\n\n    def add_panel(self, panel, name, uid):\n        '''This method is used by Settings to add new panels for possible\n        display. Any replacement for ContentPanel *must* implement\n        this method.\n\n        :param panel: A :class:`SettingsPanel`. It should be stored\n                      and the interface should provide a way to switch\n                      between panels.\n\n        :param name: The name of the panel as a string. It\n                     may be used to represent the panel but may not\n                     be unique.\n\n        :param uid: A unique int identifying the panel. It should be\n                    used to identify and switch between panels.\n\n        '''\n        self.content.add_panel(panel, name, uid)\n        self.menu.add_item(name, uid)\n\n    def on_close(self, *args):\n        pass\n\n\nclass ContentPanel(ScrollView):\n    '''A class for displaying settings panels. It displays a single\n    settings panel at a time, taking up the full size and shape of the\n    ContentPanel. It is used by :class:`InterfaceWithSidebar` and\n    :class:`InterfaceWithSpinner` to display settings.\n\n    '''\n\n    panels = DictProperty({})\n    '''(internal) Stores a dictionary mapping settings panels to their uids.\n\n    :attr:`panels` is a :class:`~kivy.properties.DictProperty` and\n    defaults to {}.\n\n    '''\n\n    container = ObjectProperty()\n    '''(internal) A reference to the GridLayout that contains the\n    settings panel.\n\n    :attr:`container` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n\n    '''\n\n    current_panel = ObjectProperty(None)\n    '''(internal) A reference to the current settings panel.\n\n    :attr:`current_panel` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n\n    '''\n\n    current_uid = NumericProperty(0)\n    '''(internal) A reference to the uid of the current settings panel.\n\n    :attr:`current_uid` is a\n    :class:`~kivy.properties.NumericProperty` and defaults to 0.\n\n    '''\n\n    def add_panel(self, panel, name, uid):\n        '''This method is used by Settings to add new panels for possible\n        display. Any replacement for ContentPanel *must* implement\n        this method.\n\n        :param panel: A :class:`SettingsPanel`. It should be stored\n                      and displayed when requested.\n\n        :param name: The name of the panel as a string. It\n                     may be used to represent the panel.\n\n        :param uid: A unique int identifying the panel. It should be\n                    stored and used to identify panels when switching.\n\n        '''\n        self.panels[uid] = panel\n        if not self.current_uid:\n            self.current_uid = uid\n\n    def on_current_uid(self, *args):\n        '''The uid of the currently displayed panel. Changing this will\n        automatically change the displayed panel.\n\n        :param uid: A panel uid. It should be used to retrieve and\n                    display a settings panel that has previously been\n                    added with :meth:`add_panel`.\n        '''\n        uid = self.current_uid\n        if uid in self.panels:\n            if self.current_panel is not None:\n                self.remove_widget(self.current_panel)\n            new_panel = self.panels[uid]\n            self.add_widget(new_panel)\n            self.current_panel = new_panel\n            return True\n        return False  # New uid doesn't exist\n\n    def add_widget(self, widget):\n        if self.container is None:\n            super(ContentPanel, self).add_widget(widget)\n        else:\n            self.container.add_widget(widget)\n\n    def remove_widget(self, widget):\n        self.container.remove_widget(widget)\n\n\nclass Settings(BoxLayout):\n\n    '''Settings UI. Check module documentation for more information on how\n    to use this class.\n\n    :Events:\n        `on_config_change`: ConfigParser instance, section, key, value\n            Fired when section/key/value of a ConfigParser changes.\n\n            .. warning:\n\n                value will be str/unicode type, regardless of the setting\n                type (numeric, boolean, etc)\n        `on_close`\n            Fired by the default panel when the Close button is pressed.\n\n        '''\n\n    interface = ObjectProperty(None)\n    '''(internal) Reference to the widget that will contain, organise and\n    display the panel configuration panel widgets.\n\n    :attr:`interface` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n\n    '''\n\n    interface_cls = ObjectProperty(InterfaceWithSidebar)\n    '''The widget class that will be used to display the graphical\n    interface for the settings panel. By default, it displays one Settings\n    panel at a time with a sidebar to switch between them.\n\n    :attr:`interface_cls` is an\n    :class:`~kivy.properties.ObjectProperty` and defaults to\n    :class`InterfaceWithSidebar`.\n\n    .. versionchanged:: 1.8.0\n        If you set a string, the :class:`~kivy.factory.Factory` will be used to\n        resolve the class.\n\n    '''\n\n    __events__ = ('on_close', 'on_config_change')\n\n    def __init__(self, *args, **kargs):\n        self._types = {}\n        super(Settings, self).__init__(*args, **kargs)\n        self.add_interface()\n        self.register_type('string', SettingString)\n        self.register_type('bool', SettingBoolean)\n        self.register_type('numeric', SettingNumeric)\n        self.register_type('options', SettingOptions)\n        self.register_type('title', SettingTitle)\n        self.register_type('path', SettingPath)\n\n    def on_touch_down(self, touch):\n        if self.collide_point(*touch.pos):\n            super(Settings, self).on_touch_down(touch)\n            return True\n\n    def register_type(self, tp, cls):\n        '''Register a new type that can be used in the JSON definition.\n        '''\n        self._types[tp] = cls\n\n    def on_close(self, *args):\n        pass\n\n    def add_interface(self):\n        '''(Internal) creates an instance of :attr:`Settings.interface_cls`,\n        and sets it to :attr:`~Settings.interface`. When json panels are\n        created, they will be added to this interface which will display them\n        to the user.\n        '''\n        cls = self.interface_cls\n        if isinstance(cls, string_types):\n            cls = Factory.get(cls)\n        interface = cls()\n        self.interface = interface\n        self.add_widget(interface)\n        self.interface.bind(on_close=lambda j: self.dispatch('on_close'))\n\n    def on_config_change(self, config, section, key, value):\n        pass\n\n    def add_json_panel(self, title, config, filename=None, data=None):\n        '''Create and add a new :class:`SettingsPanel` using the configuration\n        `config` with the JSON definition `filename`.\n\n        Check the :ref:`settings_json` section in the documentation for more\n        information about JSON format and the usage of this function.\n        '''\n        panel = self.create_json_panel(title, config, filename, data)\n        uid = panel.uid\n        if self.interface is not None:\n            self.interface.add_panel(panel, title, uid)\n\n    def create_json_panel(self, title, config, filename=None, data=None):\n        '''Create new :class:`SettingsPanel`.\n\n        .. versionadded:: 1.5.0\n\n        Check the documentation of :meth:`add_json_panel` for more information.\n        '''\n        if filename is None and data is None:\n            raise Exception('You must specify either the filename or data')\n        if filename is not None:\n            with open(filename, 'r') as fd:\n                data = json.loads(fd.read())\n        else:\n            data = json.loads(data)\n        if type(data) != list:\n            raise ValueError('The first element must be a list')\n        panel = SettingsPanel(title=title, settings=self, config=config)\n\n        for setting in data:\n            # determine the type and the class to use\n            if not 'type' in setting:\n                raise ValueError('One setting are missing the \"type\" element')\n            ttype = setting['type']\n            cls = self._types.get(ttype)\n            if cls is None:\n                raise ValueError(\n                    'No class registered to handle the <%s> type' %\n                    setting['type'])\n\n            # create a instance of the class, without the type attribute\n            del setting['type']\n            str_settings = {}\n            for key, item in setting.items():\n                str_settings[str(key)] = item\n\n            instance = cls(panel=panel, **str_settings)\n\n            # instance created, add to the panel\n            panel.add_widget(instance)\n\n        return panel\n\n    def add_kivy_panel(self):\n        '''Add a panel for configuring Kivy. This panel acts directly on the\n        kivy configuration. Feel free to include or exclude it in your\n        configuration.\n\n        See :meth:`~kivy.app.App.use_kivy_settings` for information on\n        enabling/disabling the automatic kivy panel.\n\n        '''\n        from kivy import kivy_data_dir\n        from kivy.config import Config\n        from os.path import join\n        self.add_json_panel('Kivy', Config,\n                            join(kivy_data_dir, 'settings_kivy.json'))\n\n\nclass SettingsWithSidebar(Settings):\n    '''A settings widget that displays settings panels with a sidebar to\n    switch between them. This is the default behaviour of\n    :class:`Settings`, and this widget is a trivial wrapper subclass.\n\n    '''\n\n\nclass SettingsWithSpinner(Settings):\n    '''A settings widget that displays one settings panel at a time with a\n    spinner at the top to switch between them.\n\n    '''\n    def __init__(self, *args, **kwargs):\n        self.interface_cls = InterfaceWithSpinner\n        super(SettingsWithSpinner, self).__init__(*args, **kwargs)\n\n\nclass SettingsWithTabbedPanel(Settings):\n    '''A settings widget that displays settings panels as pages in a\n    :class:`~kivy.uix.tabbedpanel.TabbedPanel`.\n    '''\n\n    __events__ = ('on_close', )\n\n    def __init__(self, *args, **kwargs):\n        self.interface_cls = InterfaceWithTabbedPanel\n        super(SettingsWithTabbedPanel, self).__init__(*args, **kwargs)\n\n    def on_close(self, *args):\n        pass\n\n\nclass SettingsWithNoMenu(Settings):\n    '''A settings widget that displays a single settings panel with *no*\n    Close button. It will not accept more than one Settings panel. It\n    is intended for use in programs with few enough settings that a\n    full panel switcher is not useful.\n\n    .. warning::\n\n        This Settings panel does *not* provide a Close\n        button, and so it is impossible to leave the settings screen\n        unless you also add other behaviour or override\n        :meth:`~kivy.app.App.display_settings` and\n        :meth:`~kivy.app.App.close_settings`.\n\n    '''\n    def __init__(self, *args, **kwargs):\n        self.interface_cls = InterfaceWithNoMenu\n        super(SettingsWithNoMenu, self).__init__(*args, **kwargs)\n\n\nclass InterfaceWithNoMenu(ContentPanel):\n    '''The interface widget used by :class:`SettingsWithNoMenu`. It\n    stores and displays a single settings panel.\n\n    This widget is considered internal and is not documented. See the\n    :class:`ContentPanel` for information on defining your own content\n    widget.\n\n    '''\n    def add_widget(self, widget):\n        if self.container is not None and len(self.container.children) > 0:\n            raise Exception(\n                'ContentNoMenu cannot accept more than one settings panel')\n        super(InterfaceWithNoMenu, self).add_widget(widget)\n\n\nclass InterfaceWithTabbedPanel(FloatLayout):\n    '''The content widget used by :class:`SettingsWithTabbedPanel`. It\n    stores and displays Settings panels in tabs of a TabbedPanel.\n\n    This widget is considered internal and is not documented. See\n    :class:`InterfaceWithSidebar` for information on defining your own\n    interface widget.\n\n    '''\n    tabbedpanel = ObjectProperty()\n    close_button = ObjectProperty()\n\n    __events__ = ('on_close', )\n\n    def __init__(self, *args, **kwargs):\n        super(InterfaceWithTabbedPanel, self).__init__(*args, **kwargs)\n        self.close_button.bind(on_release=lambda j: self.dispatch('on_close'))\n\n    def add_panel(self, panel, name, uid):\n        scrollview = ScrollView()\n        scrollview.add_widget(panel)\n        if not self.tabbedpanel.default_tab_content:\n            self.tabbedpanel.default_tab_text = name\n            self.tabbedpanel.default_tab_content = scrollview\n        else:\n            panelitem = TabbedPanelHeader(text=name, content=scrollview)\n            self.tabbedpanel.add_widget(panelitem)\n\n    def on_close(self, *args):\n        pass\n\n\nclass MenuSpinner(BoxLayout):\n    '''The menu class used by :class:`SettingsWithSpinner`. It provides a\n    sidebar with an entry for each settings panel.\n\n    This widget is considered internal and is not documented. See\n    :class:`MenuSidebar` for information on menus and creating your own menu\n    class.\n\n    '''\n    selected_uid = NumericProperty(0)\n    close_button = ObjectProperty(0)\n    spinner = ObjectProperty()\n    panel_names = DictProperty({})\n    spinner_text = StringProperty()\n    close_button = ObjectProperty()\n\n    def add_item(self, name, uid):\n        values = self.spinner.values\n        if name in values:\n            i = 2\n            while name + ' {}'.format(i) in values:\n                i += 1\n            name = name + ' {}'.format(i)\n        self.panel_names[name] = uid\n        self.spinner.values.append(name)\n        if not self.spinner.text:\n            self.spinner.text = name\n\n    def on_spinner_text(self, *args):\n        text = self.spinner_text\n        self.selected_uid = self.panel_names[text]\n\n\nclass MenuSidebar(FloatLayout):\n    '''The menu used by :class:`InterfaceWithSidebar`. It provides a\n    sidebar with an entry for each settings panel, which the user may\n    click to select.\n\n    '''\n\n    selected_uid = NumericProperty(0)\n    '''The uid of the currently selected panel. This may be used to switch\n    between displayed panels, e.g. by binding it to the\n    :attr:`~ContentPanel.current_uid` of a :class:`ContentPanel`.\n\n    :attr:`selected_uid` is a\n    :class`~kivy.properties.NumericProperty` and defaults to 0.\n\n    '''\n\n    buttons_layout = ObjectProperty(None)\n    '''(internal) Reference to the GridLayout that contains individual\n    settings panel menu buttons.\n\n    :attr:`buttons_layout` is an\n    :class:`~kivy.properties.ObjectProperty` and defaults to None.\n\n    '''\n\n    close_button = ObjectProperty(None)\n    '''(internal) Reference to the widget's Close button.\n\n    :attr:`buttons_layout` is an\n    :class:`~kivy.properties.ObjectProperty` and defaults to None.\n\n    '''\n\n    def add_item(self, name, uid):\n        '''This method is used to add new panels to the menu.\n\n        :param name: The name (a string) of the panel. It should be\n                     used to represent the panel in the menu.\n\n        :param uid: The name (an int) of the panel. It should be used\n                    internally to represent the panel and used to set\n                    self.selected_uid when the panel is changed.\n\n        '''\n\n        label = SettingSidebarLabel(text=name, uid=uid, menu=self)\n        if len(self.buttons_layout.children) == 0:\n            label.selected = True\n        if self.buttons_layout is not None:\n            self.buttons_layout.add_widget(label)\n\n    def on_selected_uid(self, *args):\n        '''(internal) unselects any currently selected menu buttons, unless\n        they represent the current panel.\n\n        '''\n        for button in self.buttons_layout.children:\n            if button.uid != self.selected_uid:\n                button.selected = False\n\n\nclass SettingSidebarLabel(Label):\n    # Internal class, not documented.\n    selected = BooleanProperty(False)\n    uid = NumericProperty(0)\n    menu = ObjectProperty(None)\n\n    def on_touch_down(self, touch):\n        if not self.collide_point(*touch.pos):\n            return\n        self.selected = True\n        self.menu.selected_uid = self.uid\n\n\nif __name__ == '__main__':\n    from kivy.app import App\n\n    class SettingsApp(App):\n\n        def build(self):\n            s = Settings()\n            s.add_kivy_panel()\n            s.bind(on_close=self.stop)\n            return s\n\n    SettingsApp().run()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/slider.py",
    "content": "\"\"\"\nSlider\n======\n\n.. image:: images/slider.jpg\n\nThe :class:`Slider` widget looks like a scrollbar. It supports horizontal and\nvertical orientations, min/max values and a default value.\n\nTo create a slider from -100 to 100 starting from 25::\n\n    from kivy.uix.slider import Slider\n    s = Slider(min=-100, max=100, value=25)\n\nTo create a vertical slider::\n\n    from kivy.uix.slider import Slider\n    s = Slider(orientation='vertical')\n\n\"\"\"\n__all__ = ('Slider', )\n\nfrom kivy.uix.widget import Widget\nfrom kivy.properties import (NumericProperty, AliasProperty, OptionProperty,\n                             ReferenceListProperty, BoundedNumericProperty)\nfrom kivy.metrics import sp\n\n\nclass Slider(Widget):\n    \"\"\"Class for creating a Slider widget.\n\n    Check module documentation for more details.\n    \"\"\"\n\n    value = NumericProperty(0.)\n    '''Current value used for the slider.\n\n    :attr:`value` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 0.'''\n\n    min = NumericProperty(0.)\n    '''Minimum value allowed for :attr:`value`.\n\n    :attr:`min` is a :class:`~kivy.properties.NumericProperty` and defaults to\n    0.'''\n\n    max = NumericProperty(100.)\n    '''Maximum value allowed for :attr:`value`.\n\n    :attr:`max` is a :class:`~kivy.properties.NumericProperty` and defaults to\n    100.'''\n\n    padding = NumericProperty(sp(16))\n    '''Padding of the slider. The padding is used for graphical representation\n    and interaction. It prevents the cursor from going out of the bounds of the\n    slider bounding box.\n\n    By default, padding is sp(16). The range of the slider is reduced from\n    padding \\*2 on the screen. It allows drawing the default cursor of sp(32)\n    width without having the cursor go out of the widget.\n\n    :attr:`padding` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to sp(16).'''\n\n    orientation = OptionProperty('horizontal', options=(\n        'vertical', 'horizontal'))\n    '''Orientation of the slider.\n\n    :attr:`orientation` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to 'horizontal'. Can take a value of 'vertical' or 'horizontal'.\n    '''\n\n    range = ReferenceListProperty(min, max)\n    '''Range of the slider in the format (minimum value, maximum value)::\n\n        >>> slider = Slider(min=10, max=80)\n        >>> slider.range\n        [10, 80]\n        >>> slider.range = (20, 100)\n        >>> slider.min\n        20\n        >>> slider.max\n        100\n\n    :attr:`range` is a :class:`~kivy.properties.ReferenceListProperty` of\n    (:attr:`min`, :attr:`max`) properties.\n    '''\n\n    step = BoundedNumericProperty(0, min=0)\n    '''Step size of the slider.\n\n    .. versionadded:: 1.4.0\n\n    Determines the size of each interval or step the slider takes between\n    min and max. If the value range can't be evenly divisible by step the\n    last step will be capped by slider.max\n\n    :attr:`step` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 1.'''\n\n    # The following two methods constrain the slider's value\n    # to range(min,max). Otherwise it may happen that self.value < self.min\n    # at init.\n\n    def on_min(self, *largs):\n        self.value = min(self.max, max(self.min, self.value))\n\n    def on_max(self, *largs):\n        self.value = min(self.max, max(self.min, self.value))\n\n    def get_norm_value(self):\n        vmin = self.min\n        d = self.max - vmin\n        if d == 0:\n            return 0\n        return (self.value - vmin) / float(d)\n\n    def set_norm_value(self, value):\n        vmin = self.min\n        step = self.step\n        val = value * (self.max - vmin) + vmin\n        if step == 0:\n            self.value = val\n        else:\n            self.value = min(round((val - vmin) / step) * step + vmin,\n                             self.max)\n    value_normalized = AliasProperty(get_norm_value, set_norm_value,\n                                     bind=('value', 'min', 'max', 'step'))\n    '''Normalized value inside the :attr:`range` (min/max) to 0-1 range::\n\n        >>> slider = Slider(value=50, min=0, max=100)\n        >>> slider.value\n        50\n        >>> slider.value_normalized\n        0.5\n        >>> slider.value = 0\n        >>> slider.value_normalized\n        0\n        >>> slider.value = 100\n        >>> slider.value_normalized\n        1\n\n    You can also use it for setting the real value without knowing the minimum\n    and maximum::\n\n        >>> slider = Slider(min=0, max=200)\n        >>> slider.value_normalized = .5\n        >>> slider.value\n        100\n        >>> slider.value_normalized = 1.\n        >>> slider.value\n        200\n\n    :attr:`value_normalized` is an :class:`~kivy.properties.AliasProperty`.\n    '''\n\n    def get_value_pos(self):\n        padding = self.padding\n        x = self.x\n        y = self.y\n        nval = self.value_normalized\n        if self.orientation == 'horizontal':\n            return (x + padding + nval * (self.width - 2 * padding), y)\n        else:\n            return (x, y + padding + nval * (self.height - 2 * padding))\n\n    def set_value_pos(self, pos):\n        padding = self.padding\n        x = min(self.right - padding, max(pos[0], self.x + padding))\n        y = min(self.top - padding, max(pos[1], self.y + padding))\n        if self.orientation == 'horizontal':\n            if self.width == 0:\n                self.value_normalized = 0\n            else:\n                self.value_normalized = (x - self.x - padding\n                                         ) / float(self.width - 2 * padding)\n        else:\n            if self.height == 0:\n                self.value_normalized = 0\n            else:\n                self.value_normalized = (y - self.y - padding\n                                         ) / float(self.height - 2 * padding)\n    value_pos = AliasProperty(get_value_pos, set_value_pos,\n                              bind=('x', 'y', 'width', 'height', 'min',\n                                    'max', 'value_normalized', 'orientation'))\n    '''Position of the internal cursor, based on the normalized value.\n\n    :attr:`value_pos` is an :class:`~kivy.properties.AliasProperty`.\n    '''\n\n    def on_touch_down(self, touch):\n        if self.disabled or not self.collide_point(*touch.pos):\n            return\n        if touch.is_mouse_scrolling:\n            if 'down' in touch.button or 'left' in touch.button:\n                if self.step:\n                    self.value = min(self.max, self.value + self.step)\n                else:\n                    self.value = min(\n                        self.max,\n                        self.value + (self.max - self.min) / 20)\n            if 'up' in touch.button or 'right' in touch.button:\n                if self.step:\n                    self.value = max(self.min, self.value - self.step)\n                else:\n                    self.value = max(\n                        self.min,\n                        self.value - (self.max - self.min) / 20)\n        else:\n            touch.grab(self)\n            self.value_pos = touch.pos\n        return True\n\n    def on_touch_move(self, touch):\n        if touch.grab_current == self:\n            self.value_pos = touch.pos\n            return True\n\n    def on_touch_up(self, touch):\n        if touch.grab_current == self:\n            self.value_pos = touch.pos\n            return True\n\nif __name__ == '__main__':\n    from kivy.app import App\n\n    class SliderApp(App):\n        def build(self):\n            return Slider(padding=25)\n\n    SliderApp().run()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/spinner.py",
    "content": "'''\nSpinner\n=======\n\n.. versionadded:: 1.4.0\n\n.. image:: images/spinner.jpg\n    :align: right\n\nSpinner is a widget that provides a quick way to select one value from a set.\nIn the default state, a spinner shows its currently selected value.\nTouching the spinner displays a dropdown menu with all the other available\nvalues from which the user can select a new one.\n\nExample::\n\n    from kivy.base import runTouchApp\n    from kivy.uix.spinner import Spinner\n\n    spinner = Spinner(\n        # default value shown\n        text='Home',\n        # available values\n        values=('Home', 'Work', 'Other', 'Custom'),\n        # just for positioning in our example\n        size_hint=(None, None),\n        size=(100, 44),\n        pos_hint={'center_x': .5, 'center_y': .5})\n\n    def show_selected_value(spinner, text):\n        print('The spinner', spinner, 'have text', text)\n\n    spinner.bind(text=show_selected_value)\n\n    runTouchApp(spinner)\n\n'''\n\n__all__ = ('Spinner', 'SpinnerOption')\n\nfrom kivy.compat import string_types\nfrom kivy.factory import Factory\nfrom kivy.properties import ListProperty, ObjectProperty, BooleanProperty\nfrom kivy.uix.button import Button\nfrom kivy.uix.dropdown import DropDown\n\n\nclass SpinnerOption(Button):\n    '''Special button used in the dropdown list. We just set the default\n    size_hint_y and height.\n    '''\n    pass\n\n\nclass Spinner(Button):\n    '''Spinner class, see module documentation for more information.\n    '''\n\n    values = ListProperty()\n    '''Values that can be selected by the user. It must be a list of strings.\n\n    :attr:`values` is a :class:`~kivy.properties.ListProperty` and defaults to\n    [].\n    '''\n\n    option_cls = ObjectProperty(SpinnerOption)\n    '''Class used to display the options within the dropdown list displayed\n    under the Spinner. The `text` property of the class will be used to\n    represent the value.\n\n    The option class requires at least:\n\n    - a `text` property, used to display the value.\n    - an `on_release` event, used to trigger the option when pressed/touched.\n\n    :attr:`option_cls` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to :class:`SpinnerOption`.\n\n    .. versionchanged:: 1.8.0\n        If you set a string, the :class:`~kivy.factory.Factory` will be used to\n        resolve the class.\n\n    '''\n\n    dropdown_cls = ObjectProperty(DropDown)\n    '''Class used to display the dropdown list when the Spinner is pressed.\n\n    :attr:`dropdown_cls` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to :class:`~kivy.uix.dropdown.DropDown`.\n\n    .. versionchanged:: 1.8.0\n        If you set a string, the :class:`~kivy.factory.Factory` will be used to\n        resolve the class.\n\n    '''\n\n    is_open = BooleanProperty(False)\n    '''By default, the spinner is not open. Set to True to open it.\n\n    :attr:`is_open` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n\n    .. versionadded:: 1.4.0\n    '''\n\n    def __init__(self, **kwargs):\n        self._dropdown = None\n        super(Spinner, self).__init__(**kwargs)\n        self.bind(\n            on_release=self._toggle_dropdown,\n            dropdown_cls=self._build_dropdown,\n            option_cls=self._build_dropdown,\n            values=self._update_dropdown)\n        self._build_dropdown()\n\n    def _build_dropdown(self, *largs):\n        if self._dropdown:\n            self._dropdown.unbind(on_select=self._on_dropdown_select)\n            self._dropdown.unbind(on_dismiss=self._close_dropdown)\n            self._dropdown.dismiss()\n            self._dropdown = None\n        cls = self.dropdown_cls\n        if isinstance(cls, string_types):\n            cls = Factory.get(cls)\n        self._dropdown = cls()\n        self._dropdown.bind(on_select=self._on_dropdown_select)\n        self._dropdown.bind(on_dismiss=self._close_dropdown)\n        self._update_dropdown()\n\n    def _update_dropdown(self, *largs):\n        dp = self._dropdown\n        cls = self.option_cls\n        if isinstance(cls, string_types):\n            cls = Factory.get(cls)\n        dp.clear_widgets()\n        for value in self.values:\n            item = cls(text=value)\n            item.bind(on_release=lambda option: dp.select(option.text))\n            dp.add_widget(item)\n\n    def _toggle_dropdown(self, *largs):\n        self.is_open = not self.is_open\n\n    def _close_dropdown(self, *largs):\n        self.is_open = False\n\n    def _on_dropdown_select(self, instance, data, *largs):\n        self.text = data\n        self.is_open = False\n\n    def on_is_open(self, instance, value):\n        if value:\n            self._dropdown.open(self)\n        else:\n            if self._dropdown.attach_to:\n                self._dropdown.dismiss()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/splitter.py",
    "content": "'''Splitter\n======\n\n.. versionadded:: 1.5.0\n\n.. image:: images/splitter.jpg\n    :align: right\n\nThe :class:`Splitter` is a widget that helps you re-size it's child\nwidget/layout by letting you re-size it via dragging the boundary or\ndouble tapping the boundary. This widget is similar to the\n:class:`~kivy.uix.scrollview.ScrollView` in that it allows only one\nchild widget.\n\nUsage::\n\n    splitter = Splitter(sizable_from = 'right')\n    splitter.add_widget(layout_or_widget_instance)\n    splitter.min_size = 100\n    splitter.max_size = 250\n\nTo change the size of the strip/border used for resizing::\n\n    splitter.strip_size = '10pt'\n\nTo change its appearance::\n\n    splitter.strip_cls = your_custom_class\n\nYou can also change the appearance of the `strip_cls`, which defaults to\n:class:`SplitterStrip`, by overriding the `kv` rule in your app::\n\n    <SplitterStrip>:\n        horizontal: True if self.parent and self.parent.sizable_from[0] \\\nin ('t', 'b') else False\n        background_normal: 'path to normal horizontal image' \\\nif self.horizontal else 'path to vertical normal image'\n        background_down: 'path to pressed horizontal image' \\\nif self.horizontal else 'path to vertical pressed image'\n\n'''\n\n\n__all__ = ('Splitter', )\n\nfrom kivy.compat import string_types\nfrom kivy.factory import Factory\nfrom kivy.uix.button import Button\nfrom kivy.properties import (OptionProperty, NumericProperty, ObjectProperty,\n                             ListProperty, BooleanProperty)\nfrom kivy.uix.boxlayout import BoxLayout\n\n\nclass SplitterStrip(Button):\n    '''Class used for tbe graphical representation of a\n    :class:`kivy.uix.splitter.SplitterStripe`.\n    '''\n    pass\n\n\nclass Splitter(BoxLayout):\n    '''See module documentation.\n\n    :Events:\n        `on_press`:\n            Fired when the splitter is pressed.\n        `on_release`:\n            Fired when the splitter is released.\n\n    .. versionchanged:: 1.6.0\n        Added `on_press` and `on_release` events.\n\n    '''\n\n    border = ListProperty([4, 4, 4, 4])\n    '''Border used for the\n    :class:`~kivy.graphics.vertex_instructions.BorderImage`\n    graphics instruction.\n\n    This must be a list of four values: (top, right, bottom, left).\n    Read the BorderImage instructions for more information about how\n    to use it.\n\n    :attr:`border` is a :class:`~kivy.properties.ListProperty` and\n    defaults to (4, 4, 4, 4).\n    '''\n\n    strip_cls = ObjectProperty(SplitterStrip)\n    '''Specifies the class of the resize Strip.\n\n    :attr:`strip_cls` is an :class:`kivy.properties.ObjectProperty` and\n    defaults to :class:`~kivy.uix.splitter.SplitterStrip`, which is of type\n    :class:`~kivy.uix.button.Button`.\n\n    .. versionchanged:: 1.8.0\n        If you set a string, the :class:`~kivy.factory.Factory` will be used to\n        resolve the class.\n\n    '''\n\n    sizable_from = OptionProperty('left', options=(\n        'left', 'right', 'top', 'bottom'))\n    '''Specifies whether the widget is resizable. Options are::\n        `left`, `right`, `top` or `bottom`\n\n    :attr:`sizable_from` is an :class:`~kivy.properties.OptionProperty`\n    and defaults to `left`.\n    '''\n\n    strip_size = NumericProperty('10pt')\n    '''Specifies the size of resize strip\n\n    :attr:`strp_size` is a :class:`~kivy.properties.NumericProperty`\n    defaults to `10pt`\n    '''\n\n    min_size = NumericProperty('100pt')\n    '''Specifies the minimum size beyond which the widget is not resizable.\n\n    :attr:`min_size` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to `100pt`.\n    '''\n\n    max_size = NumericProperty('500pt')\n    '''Specifies the maximum size beyond which the widget is not resizable.\n\n    :attr:`max_size` is a :class:`~kivy.properties.NumericProperty`\n    and defaults to `500pt`.\n    '''\n\n    _parent_proportion = NumericProperty(0.)\n    '''(internal) Specifies the distance that the slider has travelled\n    across its parent, used to automatically maintain a sensible\n    position if the parent is resized.\n\n    :attr:`_parent_proportion` is a\n    :class:`~kivy.properties.NumericProperty` and defaults to 0.\n\n    .. versionadded:: 1.9.0\n    '''\n\n    _bound_parent = ObjectProperty(None, allownone=True)\n    '''(internal) References the widget whose size is currently being\n    tracked by :attr:`_parent_proportion`.\n\n    :attr:`_bound_parent` is a\n    :class:`~kivy.properties.ObjectProperty` and defaults to None.\n\n    .. versionadded:: 1.9.0\n    '''\n\n    keep_within_parent = BooleanProperty(False)\n    '''If True, will limit the splitter to stay within its parent widget.\n\n    :attr:`keep_within_parent` is a\n    :class:`~kivy.properties.BooleanProperty` and defaults to False.\n\n    .. versionadded:: 1.9.0\n    '''\n\n    rescale_with_parent = BooleanProperty(False)\n    '''If True, will automatically change size to take up the same\n    proportion of the parent widget when it is resized, while\n    staying within :attr:`min_size` and :attr:`max_size`. As long as\n    these attributes can be satisfied, this stops the\n    :class:`Splitter` from exceeding the parent size during rescaling.\n\n    :attr:`rescale_with_parent` is a\n    :class:`~kivy.properties.BooleanProperty` and defaults to False.\n\n    .. versionadded:: 1.9.0\n    '''\n\n    __events__ = ('on_press', 'on_release')\n\n    def __init__(self, **kwargs):\n        self._container = None\n        self._strip = None\n        super(Splitter, self).__init__(**kwargs)\n        self.bind(max_size=self._do_size,\n                  min_size=self._do_size,\n                  parent=self._rebind_parent)\n\n    def on_sizable_from(self, instance, sizable_from):\n        if not instance._container:\n            return\n\n        sup = super(Splitter, instance)\n        _strp = instance._strip\n        if _strp:\n            # remove any previous binds\n            _strp.unbind(on_touch_down=instance.strip_down)\n            _strp.unbind(on_touch_move=instance.strip_move)\n            _strp.unbind(on_touch_up=instance.strip_up)\n            self.unbind(disabled=_strp.setter('disabled'))\n\n            sup.remove_widget(instance._strip)\n        else:\n            cls = instance.strip_cls\n            if isinstance(cls, string_types):\n                cls = Factory.get(cls)\n            instance._strip = _strp = cls()\n\n        sz_frm = instance.sizable_from[0]\n        if sz_frm in ('l', 'r'):\n            _strp.size_hint = None, 1\n            _strp.width = instance.strip_size\n            instance.orientation = 'horizontal'\n            instance.unbind(strip_size=_strp.setter('width'))\n            instance.bind(strip_size=_strp.setter('width'))\n        else:\n            _strp.size_hint = 1, None\n            _strp.height = instance.strip_size\n            instance.orientation = 'vertical'\n            instance.unbind(strip_size=_strp.setter('height'))\n            instance.bind(strip_size=_strp.setter('height'))\n\n        index = 1\n        if sz_frm in ('r', 'b'):\n            index = 0\n        sup.add_widget(_strp, index)\n\n        _strp.bind(on_touch_down=instance.strip_down)\n        _strp.bind(on_touch_move=instance.strip_move)\n        _strp.bind(on_touch_up=instance.strip_up)\n        _strp.disabled = self.disabled\n        self.bind(disabled=_strp.setter('disabled'))\n\n    def add_widget(self, widget, index=0):\n        if self._container or not widget:\n            return Exception('Splitter accepts only one Child')\n        self._container = widget\n        sz_frm = self.sizable_from[0]\n        if sz_frm in ('l', 'r'):\n            widget.size_hint_x = 1\n        else:\n            widget.size_hint_y = 1\n\n        index = 0\n        if sz_frm in ('r', 'b'):\n            index = 1\n        super(Splitter, self).add_widget(widget, index)\n        self.on_sizable_from(self, self.sizable_from)\n\n    def remove_widget(self, widget, *largs):\n        super(Splitter, self).remove_widget(widget)\n        if widget == self._container:\n            self._container = None\n\n    def clear_widgets(self):\n        self.remove_widget(self._container)\n\n    def strip_down(self, instance, touch):\n        if not instance.collide_point(*touch.pos):\n            return False\n        touch.grab(self)\n        self.dispatch('on_press')\n\n    def on_press(self):\n        pass\n\n    def _rebind_parent(self, instance, new_parent):\n        if self._bound_parent is not None:\n            self._bound_parent.unbind(size=self.rescale_parent_proportion)\n        if self.parent is not None:\n            new_parent.bind(size=self.rescale_parent_proportion)\n        self._bound_parent = new_parent\n        self.rescale_parent_proportion()\n\n    def rescale_parent_proportion(self, *args):\n        if self.rescale_with_parent:\n            parent_proportion = self._parent_proportion\n            if self.sizable_from in ('top', 'bottom'):\n                new_height = parent_proportion * self.parent.height\n                self.height = max(self.min_size, min(new_height, self.max_size))\n            else:\n                new_width = parent_proportion * self.parent.width\n                self.width = max(self.min_size, min(new_width, self.max_size))\n\n    def _do_size(self, instance, value):\n        if self.sizable_from[0] in ('l', 'r'):\n            self.width = max(self.min_size, min(self.width, self.max_size))\n        else:\n            self.height = max(self.min_size, min(self.height, self.max_size))\n\n    def strip_move(self, instance, touch):\n        if touch.grab_current is not instance:\n            return False\n        max_size = self.max_size\n        min_size = self.min_size\n        sz_frm = self.sizable_from[0]\n\n        if sz_frm in ('t', 'b'):\n            diff_y = (touch.dy)\n            if self.keep_within_parent:\n                if sz_frm == 't' and (self.top + diff_y) > self.parent.top:\n                    diff_y = self.parent.top - self.top\n                elif sz_frm == 'b' and (self.y + diff_y) < self.parent.y:\n                    diff_y = self.parent.y - self.y\n            if sz_frm == 'b':\n                diff_y *= -1\n            if self.size_hint_y:\n                self.size_hint_y = None\n            if self.height > 0:\n                self.height += diff_y\n            else:\n                self.height = 1\n\n            height = self.height\n            self.height = max(min_size, min(height, max_size))\n\n            self._parent_proportion = self.height / self.parent.height\n        else:\n            diff_x = (touch.dx)\n            if self.keep_within_parent:\n                if sz_frm == 'l' and (self.x + diff_x) < self.parent.x:\n                    diff_x = self.parent.x - self.x\n                elif (sz_frm == 'r' and\n                      (self.right + diff_x) > self.parent.right):\n                    diff_x = self.parent.right - self.right\n            if sz_frm == 'l':\n                diff_x *= -1\n            if self.size_hint_x:\n                self.size_hint_x = None\n            if self.width > 0:\n                self.width += diff_x\n            else:\n                self.width = 1\n\n            width = self.width\n            self.width = max(min_size, min(width, max_size))\n\n            self._parent_proportion = self.width / self.parent.width\n\n    def strip_up(self, instance, touch):\n        if touch.grab_current is not instance:\n            return\n\n        if touch.is_double_tap:\n            max_size = self.max_size\n            min_size = self.min_size\n            sz_frm = self.sizable_from[0]\n            s = self.size\n\n            if sz_frm in ('t', 'b'):\n                if self.size_hint_y:\n                    self.size_hint_y = None\n                if s[1] - min_size <= max_size - s[1]:\n                    self.height = max_size\n                else:\n                    self.height = min_size\n            else:\n                if self.size_hint_x:\n                    self.size_hint_x = None\n                if s[0] - min_size <= max_size - s[0]:\n                    self.width = max_size\n                else:\n                    self.width = min_size\n        touch.ungrab(instance)\n        self.dispatch('on_release')\n\n    def on_release(self):\n        pass\n\n\nif __name__ == '__main__':\n    from kivy.app import App\n    from kivy.uix.button import Button\n    from kivy.uix.floatlayout import FloatLayout\n\n    class SplitterApp(App):\n\n        def build(self):\n            root = FloatLayout()\n            bx = BoxLayout()\n            bx.add_widget(Button())\n            bx.add_widget(Button())\n            bx2 = BoxLayout()\n            bx2.add_widget(Button())\n            bx2.add_widget(Button())\n            bx2.add_widget(Button())\n            spl = Splitter(\n                size_hint=(1, .25),\n                pos_hint = {'top': 1},\n                sizable_from = 'bottom')\n            spl1 = Splitter(\n                sizable_from='left',\n                size_hint=(None, 1), width=90)\n            spl1.add_widget(Button())\n            bx.add_widget(spl1)\n            spl.add_widget(bx)\n\n            spl2 = Splitter(size_hint=(.25, 1))\n            spl2.add_widget(bx2)\n            spl2.sizable_from = 'right'\n            root.add_widget(spl)\n            root.add_widget(spl2)\n            return root\n\n    SplitterApp().run()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/stacklayout.py",
    "content": "'''\nStack Layout\n============\n\n.. only:: html\n\n    .. image:: images/stacklayout.gif\n        :align: right\n\n.. only:: latex\n\n    .. image:: images/stacklayout.png\n        :align: right\n\n.. versionadded:: 1.0.5\n\nThe :class:`StackLayout` arranges children vertically or horizontally, as many\nas the layout can fit. The size of the individual children widgets do not\nhave to be uniform.\n\nFor example, to display widgets that get progressively larger in width::\n\n    root = StackLayout()\n    for i in range(25):\n        btn = Button(text=str(i), width=40 + i * 5, size_hint=(None, 0.15))\n        root.add_widget(btn)\n\n.. image:: images/stacklayout_sizing.png\n    :align: left\n'''\n\n__all__ = ('StackLayout', )\n\nfrom kivy.uix.layout import Layout\nfrom kivy.properties import NumericProperty, OptionProperty, \\\n    ReferenceListProperty, VariableListProperty\n\n\nclass StackLayout(Layout):\n    '''Stack layout class. See module documentation for more information.\n    '''\n\n    spacing = VariableListProperty([0, 0], length=2)\n    '''Spacing between children: [spacing_horizontal, spacing_vertical].\n\n    spacing also accepts a single argument form [spacing].\n\n    :attr:`spacing` is a\n    :class:`~kivy.properties.VariableListProperty` and defaults to [0, 0].\n\n    '''\n\n    padding = VariableListProperty([0, 0, 0, 0])\n    '''Padding between the layout box and it's children: [padding_left,\n    padding_top, padding_right, padding_bottom].\n\n    padding also accepts a two argument form [padding_horizontal,\n    padding_vertical] and a single argument form [padding].\n\n    .. versionchanged:: 1.7.0\n        Replaced the NumericProperty with a VariableListProperty.\n\n    :attr:`padding` is a\n    :class:`~kivy.properties.VariableListProperty` and defaults to\n    [0, 0, 0, 0].\n\n    '''\n\n    orientation = OptionProperty('lr-tb', options=(\n        'lr-tb', 'tb-lr', 'rl-tb', 'tb-rl', 'lr-bt', 'bt-lr', 'rl-bt',\n        'bt-rl'))\n    '''Orientation of the layout.\n\n    :attr:`orientation` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to 'lr-tb'.\n\n    Valid orientations are 'lr-tb', 'tb-lr', 'rl-tb', 'tb-rl', 'lr-bt',\n    'bt-lr', 'rl-bt' and 'bt-rl'.\n\n    .. versionchanged:: 1.5.0\n        :attr:`orientation` now correctly handles all valid combinations of\n        'lr','rl','tb','bt'. Before this version only 'lr-tb' and\n        'tb-lr' were supported, and 'tb-lr' was misnamed and placed\n        widgets from bottom to top and from right to left (reversed compared\n        to what was expected).\n\n    .. note::\n\n        'lr' means Left to Right.\n        'rl' means Right to Left.\n        'tb' means Top to Bottom.\n        'bt' means Bottom to Top.\n    '''\n\n    minimum_width = NumericProperty(0)\n    '''Minimum width needed to contain all children. It is automatically set\n    by the layout.\n\n    .. versionadded:: 1.0.8\n\n    :attr:`minimum_width` is a :class:`kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    minimum_height = NumericProperty(0)\n    '''Minimum height needed to contain all children. It is automatically set\n    by the layout.\n\n    .. versionadded:: 1.0.8\n\n    :attr:`minimum_height` is a :class:`kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    minimum_size = ReferenceListProperty(minimum_width, minimum_height)\n    '''Minimum size needed to contain all children. It is automatically set\n    by the layout.\n\n    .. versionadded:: 1.0.8\n\n    :attr:`minimum_size` is a\n    :class:`~kivy.properties.ReferenceListProperty` of\n    (:attr:`minimum_width`, :attr:`minimum_height`) properties.\n    '''\n\n    def __init__(self, **kwargs):\n        super(StackLayout, self).__init__(**kwargs)\n        self.bind(\n            padding=self._trigger_layout,\n            spacing=self._trigger_layout,\n            children=self._trigger_layout,\n            orientation=self._trigger_layout,\n            size=self._trigger_layout,\n            pos=self._trigger_layout)\n\n    def do_layout(self, *largs):\n        if not self.children:\n            return\n\n        # optimize layout by preventing looking at the same attribute in a loop\n        selfpos = self.pos\n        selfsize = self.size\n        orientation = self.orientation.split('-')\n        padding_left = self.padding[0]\n        padding_top = self.padding[1]\n        padding_right = self.padding[2]\n        padding_bottom = self.padding[3]\n\n        padding_x = padding_left + padding_right\n        padding_y = padding_top + padding_bottom\n        spacing_x, spacing_y = self.spacing\n\n        lc = []\n\n        # Determine which direction and in what order to place the widgets\n        posattr = [0] * 2\n        posdelta = [0] * 2\n        posstart = [0] * 2\n        for i in (0, 1):\n            posattr[i] = 1 * (orientation[i] in ('tb', 'bt'))\n            k = posattr[i]\n            if orientation[i] == 'lr':\n                # left to right\n                posdelta[i] = 1\n                posstart[i] = selfpos[k] + padding_left\n            elif orientation[i] == 'bt':\n                # bottom to top\n                posdelta[i] = 1\n                posstart[i] = selfpos[k] + padding_bottom\n            elif orientation[i] == 'rl':\n                # right to left\n                posdelta[i] = -1\n                posstart[i] = selfpos[k] + selfsize[k] - padding_right\n            else:\n                # top to bottom\n                posdelta[i] = -1\n                posstart[i] = selfpos[k] + selfsize[k] - padding_top\n\n        innerattr, outerattr = posattr\n        ustart, vstart = posstart\n        deltau, deltav = posdelta\n        del posattr, posdelta, posstart\n\n        u = ustart  # inner loop position variable\n        v = vstart  # outer loop position variable\n\n        # space calculation, used for determining when a row or column is full\n\n        if orientation[0] in ('lr', 'rl'):\n            sv = padding_y  # size in v-direction, for minimum_size property\n            su = padding_x  # size in h-direction\n            spacing_u = spacing_x\n            spacing_v = spacing_y\n            padding_u = padding_x\n            padding_v = padding_y\n        else:\n            sv = padding_x  # size in v-direction, for minimum_size property\n            su = padding_y  # size in h-direction\n            spacing_u = spacing_y\n            spacing_v = spacing_x\n            padding_u = padding_y\n            padding_v = padding_x\n\n        # space calculation, row height or column width, for arranging widgets\n        lv = 0\n\n        urev = (deltau < 0)\n        vrev = (deltav < 0)\n        firstchild = self.children[0]\n        sizes = []\n        for c in reversed(self.children):\n            if c.size_hint[outerattr]:\n                c.size[outerattr] = max(1,\n                    c.size_hint[outerattr] * (selfsize[outerattr] - padding_v))\n\n            # does the widget fit in the row/column?\n            ccount = len(lc)\n            totalsize = availsize = max(\n                0, selfsize[innerattr] - padding_u - spacing_u * ccount)\n            if not lc:\n                if c.size_hint[innerattr]:\n                    childsize = max(1, c.size_hint[innerattr] * totalsize)\n                else:\n                    childsize = max(0, c.size[innerattr])\n                availsize = selfsize[innerattr] - padding_u - childsize\n                testsizes = [childsize]\n            else:\n                testsizes = [0] * (ccount + 1)\n                for i, child in enumerate(lc):\n                    if availsize <= 0:\n                        # no space left but we're trying to add another widget.\n                        availsize = -1\n                        break\n                    if child.size_hint[innerattr]:\n                        testsizes[i] = childsize = max(\n                            1, child.size_hint[innerattr] * totalsize)\n                    else:\n                        testsizes[i] = childsize = max(0, child.size[innerattr])\n                    availsize -= childsize\n                if c.size_hint[innerattr]:\n                    testsizes[-1] = max(1, c.size_hint[innerattr] * totalsize)\n                else:\n                    testsizes[-1] = max(0, c.size[innerattr])\n                availsize -= testsizes[-1]\n\n            if availsize >= 0 or not lc:\n                # even if there's no space, we always add one widget to a row\n                lc.append(c)\n                sizes = testsizes\n                lv = max(lv, c.size[outerattr])\n                continue\n\n            # apply the sizes\n            for i, child in enumerate(lc):\n                if child.size_hint[innerattr]:\n                    child.size[innerattr] = sizes[i]\n\n            # push the line\n            sv += lv + spacing_v\n            for c2 in lc:\n                if urev:\n                    u -= c2.size[innerattr]\n                c2.pos[innerattr] = u\n                pos_outer = v\n                if vrev:\n                    # v position is actually the top/right side of the widget\n                    # when going from high to low coordinate values,\n                    # we need to subtract the height/width from the position.\n                    pos_outer -= c2.size[outerattr]\n                c2.pos[outerattr] = pos_outer\n                if urev:\n                    u -= spacing_u\n                else:\n                    u += c2.size[innerattr] + spacing_u\n\n            v += deltav * lv\n            v += deltav * spacing_v\n            lc = [c]\n            lv = c.size[outerattr]\n            if c.size_hint[innerattr]:\n                sizes = [max(1, c.size_hint[innerattr] *\n                             (selfsize[innerattr] - padding_u))]\n            else:\n                sizes = [max(0, c.size[innerattr])]\n            u = ustart\n\n        if lc:\n            # apply the sizes\n            for i, child in enumerate(lc):\n                if child.size_hint[innerattr]:\n                    child.size[innerattr] = sizes[i]\n\n            # push the last (incomplete) line\n            sv += lv + spacing_v\n            for c2 in lc:\n                if urev:\n                    u -= c2.size[innerattr]\n                c2.pos[innerattr] = u\n                pos_outer = v\n                if vrev:\n                    pos_outer -= c2.size[outerattr]\n                c2.pos[outerattr] = pos_outer\n                if urev:\n                    u -= spacing_u\n                else:\n                    u += c2.size[innerattr] + spacing_u\n\n        self.minimum_size[outerattr] = sv\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/stencilview.py",
    "content": "'''\nStencil View\n============\n\n.. versionadded:: 1.0.4\n\n:class:`StencilView` limits the drawing of child widgets to the StencilView's\nbounding box. Any drawing outside the bounding box will be clipped (trashed).\n\nThe StencilView uses the stencil graphics instructions under the hood. It\nprovides an efficient way to clip the drawing area of children.\n\n.. note::\n\n    As with the stencil graphics instructions, you cannot stack more than 8\n    stencil-aware widgets.\n\n.. note::\n\n    StencilView is not a layout. Consequently, you have to manage the size and\n    position of its children directly. You can combine (subclass both)\n    a StencilView and a Layout in order to achieve a layout's behavior.\n    For example::\n\n        class BoxStencil(BoxLayout, StencilView):\n            pass\n'''\n\n__all__ = ('StencilView', )\n\nfrom kivy.uix.widget import Widget\n\n\nclass StencilView(Widget):\n    '''StencilView class. See module documentation for more information.\n    '''\n    pass\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/switch.py",
    "content": "'''\nSwitch\n======\n\n.. versionadded:: 1.0.7\n\n.. image:: images/switch-on.jpg\n    :align: right\n\n.. image:: images/switch-off.jpg\n    :align: right\n\nThe :class:`Switch` widget is active or inactive, like a mechanical light\nswitch. The user can swipe to the left/right to activate/deactivate it::\n\n    switch = Switch(active=True)\n\nTo attach a callback that listens to the activation state::\n\n    def callback(instance, value):\n        print('the switch', instance, 'is', value)\n\n    switch = Switch()\n    switch.bind(active=callback)\n\nBy default, the representation of the widget is static. The minimum size\nrequired is 83x32 pixels (defined by the background image). The image is\ncentered within the widget.\n\nThe entire widget is active, not just the part with graphics. As long as you\nswipe over the widget's bounding box, it will work.\n\n.. note::\n\n    If you want to control the state with a single touch instead of a swipe,\n    use the :class:`ToggleButton` instead.\n'''\n\n\nfrom kivy.uix.widget import Widget\nfrom kivy.animation import Animation\nfrom kivy.properties import BooleanProperty, ObjectProperty, NumericProperty\n\n\nclass Switch(Widget):\n    '''Switch class. See module documentation for more information.\n    '''\n    active = BooleanProperty(False)\n    '''Indicate whether the switch is active or inactive.\n\n    :attr:`active` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    touch_control = ObjectProperty(None, allownone=True)\n    '''(internal) Contains the touch that currently interacts with the switch.\n\n    :attr:`touch_control` is an :class:`~kivy.properties.ObjectProperty`\n    and defaults to None.\n    '''\n\n    touch_distance = NumericProperty(0)\n    '''(internal) Contains the distance between the initial position of the\n    touch and the current position to determine if the swipe is from the left\n    or right.\n\n    :attr:`touch_distance` is a :class:`~kivy.properties.NumericProperty`\n    and defaults to 0.\n    '''\n\n    active_norm_pos = NumericProperty(0)\n    '''(internal) Contains the normalized position of the movable element\n    inside the switch, in the 0-1 range.\n\n    :attr:`active_norm_pos` is a :class:`~kivy.properties.NumericProperty`\n    and defaults to 0.\n    '''\n\n    def on_touch_down(self, touch):\n        if self.disabled or self.touch_control is not None:\n            return\n        if not self.collide_point(*touch.pos):\n            return\n        touch.grab(self)\n        self.touch_distance = 0\n        self.touch_control = touch\n        return True\n\n    def on_touch_move(self, touch):\n        if touch.grab_current is not self:\n            return\n        self.touch_distance = touch.x - touch.ox\n        return True\n\n    def on_touch_up(self, touch):\n        if touch.grab_current is not self:\n            return\n        touch.ungrab(self)\n        # depending of the distance, activate by norm pos or invert\n        if abs(touch.ox - touch.x) < 5:\n            self.active = not self.active\n        else:\n            self.active = self.active_norm_pos > 0.5\n        Animation(active_norm_pos=int(self.active), t='out_quad',\n                  d=.2).start(self)\n        self.touch_control = None\n        return True\n\nif __name__ == '__main__':\n    from kivy.base import runTouchApp\n    runTouchApp(Switch())\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/tabbedpanel.py",
    "content": "'''\nTabbedPanel\n===========\n\n.. image:: images/tabbed_panel.jpg\n    :align: right\n\n.. versionadded:: 1.3.0\n\n\nThe `TabbedPanel` widget manages different widgets in tabs, with a header area\nfor the actual tab buttons and a content area for showing the current tab\ncontent.\n\nThe :class:`TabbedPanel` provides one default tab.\n\nSimple example\n--------------\n\n.. include:: ../../examples/widgets/tabbedpanel.py\n    :literal:\n\n.. note::\n\n    A new class :class:`TabbedPanelItem` has been introduced in 1.5.0 for\n    convenience. So now one can simply add a :class:`TabbedPanelItem` to a\n    :class:`TabbedPanel` and `content` to the :class:`TabbedPanelItem`\n    as in the example provided above.\n\nCustomize the Tabbed Panel\n--------------------------\n\nYou can choose the position in which the tabs are displayed::\n\n    tab_pos = 'top_mid'\n\nAn individual tab is called a TabbedPanelHeader. It is a special button\ncontaining a `content` property. You add the TabbedPanelHeader first, and set\nits `content` property separately::\n\n    tp = TabbedPanel()\n    th = TabbedPanelHeader(text='Tab2')\n    tp.add_widget(th)\n\nAn individual tab, represented by a TabbedPanelHeader, needs its content set.\nThis content can be any widget. It could be a layout with a deep\nhierarchy of widgets, or it could be an individual widget, such as a label or a\nbutton::\n\n    th.content = your_content_instance\n\nThere is one \"shared\" main content area active at any given time, for all\nthe tabs. Your app is responsible for adding the content of individual tabs\nand for managing them, but it's not responsible for content switching. The\ntabbed panel handles switching of the main content object as per user action.\n\nThere is a default tab added when the tabbed panel is instantiated.\nTabs that you add individually as above, are added in addition to the default\ntab. Thus, depending on your needs and design, you will want to customize the\ndefault tab::\n\n    tp.default_tab_text = 'Something Specific To Your Use'\n\n\nThe default tab machinery requires special consideration and management.\nAccordingly, an `on_default_tab` event is provided for associating a callback::\n\n    tp.bind(default_tab = my_default_tab_callback)\n\nIt's important to note that by default, :attr:`default_tab_cls` is of type\n:class:`TabbedPanelHeader` and thus has the same properties as other tabs.\n\nSince 1.5.0, it is now possible to disable the creation of the\n:attr:`default_tab` by setting :attr:`do_default_tab` to False.\n\nTabs and content can be removed in several ways::\n\n    tp.remove_widget(widget/tabbed_panel_header)\n    or\n    tp.clear_widgets() # to clear all the widgets in the content area\n    or\n    tp.clear_tabs() # to remove the TabbedPanelHeaders\n\nTo access the children of the tabbed panel, use content.children::\n\n    tp.content.children\n\nTo access the list of tabs::\n\n    tp.tab_list\n\nTo change the appearance of the main tabbed panel content::\n\n    background_color = (1, 0, 0, .5) #50% translucent red\n    border = [0, 0, 0, 0]\n    background_image = 'path/to/background/image'\n\nTo change the background of a individual tab, use these two properties::\n\n    tab_header_instance.background_normal = 'path/to/tab_head/img'\n    tab_header_instance.background_down = 'path/to/tab_head/img_pressed'\n\nA TabbedPanelStrip contains the individual tab headers. To change the\nappearance of this tab strip, override the canvas of TabbedPanelStrip.\nFor example, in the kv language::\n\n    <TabbedPanelStrip>\n        canvas:\n            Color:\n                rgba: (0, 1, 0, 1) # green\n            Rectangle:\n                size: self.size\n                pos: self.pos\n\nBy default the tabbed panel strip takes its background image and color from the\ntabbed panel's background_image and background_color.\n\n'''\n\n__all__ = ('StripLayout', 'TabbedPanel', 'TabbedPanelContent',\n           'TabbedPanelHeader', 'TabbedPanelItem', 'TabbedPanelStrip',\n           'TabbedPanelException')\n\nfrom functools import partial\nfrom kivy.clock import Clock\nfrom kivy.compat import string_types\nfrom kivy.factory import Factory\nfrom kivy.uix.togglebutton import ToggleButton\nfrom kivy.uix.widget import Widget\nfrom kivy.uix.scatter import Scatter\nfrom kivy.uix.scrollview import ScrollView\nfrom kivy.uix.gridlayout import GridLayout\nfrom kivy.uix.floatlayout import FloatLayout\nfrom kivy.logger import Logger\nfrom kivy.metrics import dp\nfrom kivy.properties import ObjectProperty, StringProperty, OptionProperty, \\\n    ListProperty, NumericProperty, AliasProperty, BooleanProperty\n\n\nclass TabbedPanelException(Exception):\n    '''The TabbedPanelException class.\n    '''\n    pass\n\n\nclass TabbedPanelHeader(ToggleButton):\n    '''A Base for implementing a Tabbed Panel Head. A button intended to be\n    used as a Heading/Tab for a TabbedPanel widget.\n\n    You can use this TabbedPanelHeader widget to add a new tab to a\n    TabbedPanel.\n    '''\n\n    content = ObjectProperty(None, allownone=True)\n    '''Content to be loaded when this tab header is selected.\n\n    :attr:`content` is an :class:`~kivy.properties.ObjectProperty` and defaults\n    to None.\n    '''\n\n    # only allow selecting the tab if not already selected\n    def on_touch_down(self, touch):\n        if self.state == 'down':\n            #dispatch to children, not to self\n            for child in self.children:\n                child.dispatch('on_touch_down', touch)\n            return\n        else:\n            super(TabbedPanelHeader, self).on_touch_down(touch)\n\n    def on_release(self, *largs):\n        # Tabbed panel header is a child of tab_strib which has a\n        # `tabbed_panel` property\n        if self.parent:\n            self.parent.tabbed_panel.switch_to(self)\n        else:\n            # tab removed before we could switch to it. Switch back to\n            # previous tab\n            self.panel.switch_to(self.panel.current_tab)\n\n\nclass TabbedPanelItem(TabbedPanelHeader):\n    '''This is a convenience class that provides a header of type\n    TabbedPanelHeader and links it with the content automatically. Thus\n    facilitating you to simply do the following in kv language::\n\n        <TabbedPanel>:\n            ...other settings\n            TabbedPanelItem:\n                BoxLayout:\n                    Label:\n                        text: 'Second tab content area'\n                    Button:\n                        text: 'Button that does nothing'\n\n    .. versionadded:: 1.5.0\n    '''\n\n    def add_widget(self, widget, index=0):\n        self.content = widget\n        if not self.parent:\n            return\n        panel = self.parent.tabbed_panel\n        if panel.current_tab == self:\n            panel.switch_to(self)\n\n    def remove_widget(self, widget):\n        self.content = None\n        if not self.parent:\n            return\n        panel = self.parent.tabbed_panel\n        if panel.current_tab == self:\n            panel.remove_widget(widget)\n\n\nclass TabbedPanelStrip(GridLayout):\n    '''A strip intended to be used as background for Heading/Tab.\n    This does not cover the blank areas in case the tabs don't cover\n    the entire width/height of the TabbedPanel(use StripLayout for that).\n    '''\n    tabbed_panel = ObjectProperty(None)\n    '''Link to the panel that the tab strip is a part of.\n\n    :attr:`tabbed_panel` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None .\n    '''\n\n\nclass StripLayout(GridLayout):\n    ''' The main layout that is used to house the entire tabbedpanel strip\n    including the blank areas in case the tabs don't cover the entire\n    width/height.\n\n    .. versionadded:: 1.8.0\n\n    '''\n\n    border = ListProperty([4, 4, 4, 4])\n    '''Border property for the :attr:`background_image`.\n\n    :attr:`border` is a :class:`~kivy.properties.ListProperty` and defaults\n    to [4, 4, 4, 4]\n    '''\n\n    background_image = StringProperty(\n        'atlas://data/images/defaulttheme/action_view')\n    '''Background image to be used for the Strip layout of the TabbedPanel.\n\n    :attr:`background_image` is a :class:`~kivy.properties.StringProperty` and\n     defaults to a transparent image.\n    '''\n\n\nclass TabbedPanelContent(FloatLayout):\n    '''The TabbedPanelContent class.\n    '''\n    pass\n\n\nclass TabbedPanel(GridLayout):\n    '''The TabbedPanel class. See module documentation for more information.\n    '''\n\n    background_color = ListProperty([1, 1, 1, 1])\n    '''Background color, in the format (r, g, b, a).\n\n    :attr:`background_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [1, 1, 1, 1].\n    '''\n\n    border = ListProperty([16, 16, 16, 16])\n    '''Border used for :class:`~kivy.graphics.vertex_instructions.BorderImage`\n    graphics instruction, used itself for :attr:`background_image`.\n    Can be changed for a custom background.\n\n    It must be a list of four values: (top, right, bottom, left). Read the\n    BorderImage instructions for more information.\n\n    :attr:`border` is a :class:`~kivy.properties.ListProperty` and\n    defaults to (16, 16, 16, 16)\n    '''\n\n    background_image = StringProperty('atlas://data/images/defaulttheme/tab')\n    '''Background image of the main shared content object.\n\n    :attr:`background_image` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/tab'.\n    '''\n\n    background_disabled_image = StringProperty(\n        'atlas://data/images/defaulttheme/tab_disabled')\n    '''Background image of the main shared content object when disabled.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`background_disabled_image` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/tab'.\n    '''\n\n    strip_image = StringProperty(\n        'atlas://data/images/defaulttheme/action_view')\n    '''Background image of the tabbed strip.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`strip_image` is a :class:`~kivy.properties.StringProperty`\n    and defaults to a empty image.\n    '''\n\n    strip_border = ListProperty([4, 4, 4, 4])\n    '''Border to be used on :attr:`strip_image`.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`strip_border` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [4, 4, 4, 4].\n    '''\n\n    _current_tab = ObjectProperty(None)\n\n    def get_current_tab(self):\n        return self._current_tab\n\n    current_tab = AliasProperty(get_current_tab, None, bind=('_current_tab', ))\n    '''Links to the currently selected or active tab.\n\n    .. versionadded:: 1.4.0\n\n    :attr:`current_tab` is an :class:`~kivy.AliasProperty`, read-only.\n    '''\n\n    tab_pos = OptionProperty(\n        'top_left',\n        options=('left_top', 'left_mid', 'left_bottom', 'top_left',\n                 'top_mid', 'top_right', 'right_top', 'right_mid',\n                 'right_bottom', 'bottom_left', 'bottom_mid', 'bottom_right'))\n    '''Specifies the position of the tabs relative to the content.\n    Can be one of: `left_top`, `left_mid`, `left_bottom`, `top_left`,\n    `top_mid`, `top_right`, `right_top`, `right_mid`, `right_bottom`,\n    `bottom_left`, `bottom_mid`, `bottom_right`.\n\n    :attr:`tab_pos` is an :class:`~kivy.properties.OptionProperty` and\n    defaults to 'top_left'.\n    '''\n\n    tab_height = NumericProperty('40dp')\n    '''Specifies the height of the tab header.\n\n    :attr:`tab_height` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 40.\n    '''\n\n    tab_width = NumericProperty('100dp', allownone=True)\n    '''Specifies the width of the tab header.\n\n    :attr:`tab_width` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 100.\n    '''\n\n    do_default_tab = BooleanProperty(True)\n    '''Specifies whether a default_tab head is provided.\n\n    .. versionadded:: 1.5.0\n\n    :attr:`do_default_tab` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to 'True'.\n    '''\n\n    default_tab_text = StringProperty('Default tab')\n    '''Specifies the text displayed on the default tab header.\n\n    :attr:`default_tab_text` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'default tab'.\n    '''\n\n    default_tab_cls = ObjectProperty(TabbedPanelHeader)\n    '''Specifies the class to use for the styling of the default tab.\n\n    .. versionadded:: 1.4.0\n\n    .. warning::\n        `default_tab_cls` should be subclassed from `TabbedPanelHeader`\n\n    :attr:`default_tab_cls` is an :class:`~kivy.properties.ObjectProperty`\n    and defaults to `TabbedPanelHeader`. If you set a string, the\n    :class:`~kivy.factory.Factory` will be used to resolve the class.\n\n    .. versionchanged:: 1.8.0\n        The :class:`~kivy.factory.Factory` will resolve the class if a string is\n        set.\n    '''\n\n    def get_tab_list(self):\n        if self._tab_strip:\n            return self._tab_strip.children\n        return 1.\n\n    tab_list = AliasProperty(get_tab_list, None)\n    '''List of all the tab headers.\n\n    :attr:`tab_list` is an :class:`~kivy.properties.AliasProperty` and is\n    read-only.\n    '''\n\n    content = ObjectProperty(None)\n    '''This is the object holding (current_tab's content is added to this)\n    the content of the current tab. To Listen to the changes in the content\n    of the current tab, you should bind to current_tabs `content` property.\n\n    :attr:`content` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to 'None'.\n    '''\n\n    _default_tab = ObjectProperty(None, allow_none=True)\n\n    def get_def_tab(self):\n        return self._default_tab\n\n    def set_def_tab(self, new_tab):\n        if not issubclass(new_tab.__class__, TabbedPanelHeader):\n            raise TabbedPanelException('`default_tab_class` should be\\\n                subclassed from `TabbedPanelHeader`')\n        if self._default_tab == new_tab:\n            return\n        oltab = self._default_tab\n        self._default_tab = new_tab\n        self.remove_widget(oltab)\n        self._original_tab = None\n        self.switch_to(new_tab)\n        new_tab.state = 'down'\n\n    default_tab = AliasProperty(get_def_tab, set_def_tab,\n                                bind=('_default_tab', ))\n    '''Holds the default tab.\n\n    .. Note:: For convenience, the automatically provided default tab is\n              deleted when you change default_tab to something else.\n              As of 1.5.0, this behaviour has been extended to every\n              `default_tab` for consistency and not just the automatically\n              provided one.\n\n    :attr:`default_tab` is an :class:`~kivy.properties.AliasProperty`.\n    '''\n\n    def get_def_tab_content(self):\n        return self.default_tab.content\n\n    def set_def_tab_content(self, *l):\n        self.default_tab.content = l[0]\n\n    default_tab_content = AliasProperty(get_def_tab_content,\n                                        set_def_tab_content)\n    '''Holds the default tab content.\n\n    :attr:`default_tab_content` is an :class:`~kivy.properties.AliasProperty`.\n    '''\n\n    def __init__(self, **kwargs):\n        # these variables need to be initialized before the kv lang is\n        # processed setup the base layout for the tabbed panel\n        self._childrens = []\n        self._tab_layout = StripLayout(rows=1)\n        self.rows = 1\n        self._tab_strip = TabbedPanelStrip(\n            tabbed_panel=self,\n            rows=1, cols=99, size_hint=(None, None),\n            height=self.tab_height, width=self.tab_width)\n\n        self._partial_update_scrollview = None\n        self.content = TabbedPanelContent()\n        self._current_tab = self._original_tab \\\n            = self._default_tab = TabbedPanelHeader()\n\n        super(TabbedPanel, self).__init__(**kwargs)\n\n        self.bind(size=self._reposition_tabs)\n        if not self.do_default_tab:\n            Clock.schedule_once(self._switch_to_first_tab)\n            return\n        self._setup_default_tab()\n        self.switch_to(self.default_tab)\n\n    def switch_to(self, header):\n        '''Switch to a specific panel header.\n        '''\n        header_content = header.content\n        self._current_tab.state = 'normal'\n        header.state = 'down'\n        self._current_tab = header\n        self.clear_widgets()\n        if header_content is None:\n            return\n        # if content has a previous parent remove it from that parent\n        parent = header_content.parent\n        if parent:\n            parent.remove_widget(header_content)\n        self.add_widget(header_content)\n\n    def clear_tabs(self, *l):\n        self_tabs = self._tab_strip\n        self_tabs.clear_widgets()\n        if self.do_default_tab:\n            self_default_tab = self._default_tab\n            self_tabs.add_widget(self_default_tab)\n            self_tabs.width = self_default_tab.width\n        self._reposition_tabs()\n\n    def add_widget(self, widget, index=0):\n        content = self.content\n        if content is None:\n            return\n        parent = widget.parent\n        if parent:\n            parent.remove_widget(widget)\n        if widget in (content, self._tab_layout):\n            super(TabbedPanel, self).add_widget(widget, index)\n        elif isinstance(widget, TabbedPanelHeader):\n            self_tabs = self._tab_strip\n            self_tabs.add_widget(widget, index)\n            widget.group = '__tab%r__' % self_tabs.uid\n            self.on_tab_width()\n        else:\n            widget.pos_hint = {'x': 0, 'top': 1}\n            self._childrens.append(widget)\n            content.disabled = self.current_tab.disabled\n            content.add_widget(widget, index)\n\n    def remove_widget(self, widget):\n        content = self.content\n        if content is None:\n            return\n        if widget in (content, self._tab_layout):\n            super(TabbedPanel, self).remove_widget(widget)\n        elif isinstance(widget, TabbedPanelHeader):\n            if not (self.do_default_tab and widget is self._default_tab):\n                self_tabs = self._tab_strip\n                self_tabs.width -= widget.width\n                self_tabs.remove_widget(widget)\n                if widget.state == 'down' and self.do_default_tab:\n                    self._default_tab.on_release()\n                self._reposition_tabs()\n            else:\n                Logger.info('TabbedPanel: default tab! can\\'t be removed.\\n' +\n                            'Change `default_tab` to a different tab.')\n        else:\n            self._childrens.pop(widget, None)\n            if widget in content.children:\n                content.remove_widget(widget)\n\n    def clear_widgets(self, **kwargs):\n        content = self.content\n        if content is None:\n            return\n        if kwargs.get('do_super', False):\n            super(TabbedPanel, self).clear_widgets()\n        else:\n            content.clear_widgets()\n\n    def on_strip_image(self, instance, value):\n        if not self._tab_layout:\n            return\n        self._tab_layout.background_image = value\n\n    def on_strip_border(self, instance, value):\n        if not self._tab_layout:\n            return\n        self._tab_layout.border = value\n\n    def on_do_default_tab(self, instance, value):\n        if not value:\n            dft = self.default_tab\n            if dft in self.tab_list:\n                self.remove_widget(dft)\n                self._switch_to_first_tab()\n                self._default_tab = self._current_tab\n        else:\n            self._current_tab.state = 'normal'\n            self._setup_default_tab()\n\n    def on_default_tab_text(self, *args):\n        self._default_tab.text = self.default_tab_text\n\n    def on_tab_width(self, *l):\n        Clock.unschedule(self._update_tab_width)\n        Clock.schedule_once(self._update_tab_width, 0)\n\n    def on_tab_height(self, *l):\n        self._tab_layout.height = self._tab_strip.height = self.tab_height\n        self._reposition_tabs()\n\n    def on_tab_pos(self, *l):\n        # ensure canvas\n        self._reposition_tabs()\n\n    def _setup_default_tab(self):\n        if self._default_tab in self.tab_list:\n            return\n        content = self._default_tab.content\n        _tabs = self._tab_strip\n        cls = self.default_tab_cls\n\n        if isinstance(cls, string_types):\n            cls = Factory.get(cls)\n\n        if not issubclass(cls, TabbedPanelHeader):\n            raise TabbedPanelException('`default_tab_class` should be\\\n                subclassed from `TabbedPanelHeader`')\n\n        # no need to instanciate if class is TabbedPanelHeader\n        if cls != TabbedPanelHeader:\n            self._current_tab = self._original_tab = self._default_tab = cls()\n\n        default_tab = self.default_tab\n        if self._original_tab == self.default_tab:\n            default_tab.text = self.default_tab_text\n\n        default_tab.height = self.tab_height\n        default_tab.group = '__tab%r__' % _tabs.uid\n        default_tab.state = 'down'\n        default_tab.width = self.tab_width if self.tab_width else 100\n        default_tab.content = content\n\n        tl = self.tab_list\n        if default_tab not in tl:\n            _tabs.add_widget(default_tab, len(tl))\n\n        if default_tab.content:\n            self.clear_widgets()\n            self.add_widget(self.default_tab.content)\n        else:\n            Clock.schedule_once(self._load_default_tab_content)\n        self._current_tab = default_tab\n\n    def _switch_to_first_tab(self, *l):\n        ltl = len(self.tab_list) - 1\n        if ltl > -1:\n            self._current_tab = dt = self._original_tab \\\n                = self.tab_list[ltl]\n            self.switch_to(dt)\n\n    def _load_default_tab_content(self, dt):\n        if self.default_tab:\n            self.switch_to(self.default_tab)\n\n    def _reposition_tabs(self, *l):\n        Clock.unschedule(self._update_tabs)\n        Clock.schedule_once(self._update_tabs, 0)\n\n    def _update_tabs(self, *l):\n        self_content = self.content\n        if not self_content:\n            return\n        # cache variables for faster access\n        tab_pos = self.tab_pos\n        tab_layout = self._tab_layout\n        tab_layout.clear_widgets()\n        scrl_v = ScrollView(size_hint=(None, 1))\n        tabs = self._tab_strip\n        parent = tabs.parent\n        if parent:\n            parent.remove_widget(tabs)\n        scrl_v.add_widget(tabs)\n        scrl_v.pos = (0, 0)\n        self_update_scrollview = self._update_scrollview\n\n        # update scrlv width when tab width changes depends on tab_pos\n        if self._partial_update_scrollview is not None:\n            tabs.unbind(width=self._partial_update_scrollview)\n        self._partial_update_scrollview = partial(\n            self_update_scrollview, scrl_v)\n        tabs.bind(width=self._partial_update_scrollview)\n\n        # remove all widgets from the tab_strip\n        self.clear_widgets(do_super=True)\n        tab_height = self.tab_height\n\n        widget_list = []\n        tab_list = []\n        pos_letter = tab_pos[0]\n        if pos_letter == 'b' or pos_letter == 't':\n            # bottom or top positions\n            # one col containing the tab_strip and the content\n            self.cols = 1\n            self.rows = 2\n            # tab_layout contains the scrollview containing tabs and two blank\n            # dummy widgets for spacing\n            tab_layout.rows = 1\n            tab_layout.cols = 3\n            tab_layout.size_hint = (1, None)\n            tab_layout.height = (tab_height + tab_layout.padding[1] +\n                                 tab_layout.padding[3] + dp(2))\n            self_update_scrollview(scrl_v)\n\n            if pos_letter == 'b':\n                # bottom\n                if tab_pos == 'bottom_mid':\n                    tab_list = (Widget(), scrl_v, Widget())\n                    widget_list = (self_content, tab_layout)\n                else:\n                    if tab_pos == 'bottom_left':\n                        tab_list = (scrl_v, Widget(), Widget())\n                    elif tab_pos == 'bottom_right':\n                        #add two dummy widgets\n                        tab_list = (Widget(), Widget(), scrl_v)\n                    widget_list = (self_content, tab_layout)\n            else:\n                # top\n                if tab_pos == 'top_mid':\n                    tab_list = (Widget(), scrl_v, Widget())\n                elif tab_pos == 'top_left':\n                    tab_list = (scrl_v, Widget(), Widget())\n                elif tab_pos == 'top_right':\n                    tab_list = (Widget(), Widget(), scrl_v)\n                widget_list = (tab_layout, self_content)\n        elif pos_letter == 'l' or pos_letter == 'r':\n            # left ot right positions\n            # one row containing the tab_strip and the content\n            self.cols = 2\n            self.rows = 1\n            # tab_layout contains two blank dummy widgets for spacing\n            # \"vertically\" and the scatter containing scrollview\n            # containing tabs\n            tab_layout.rows = 3\n            tab_layout.cols = 1\n            tab_layout.size_hint = (None, 1)\n            tab_layout.width = tab_height\n            scrl_v.height = tab_height\n            self_update_scrollview(scrl_v)\n\n            # rotate the scatter for vertical positions\n            rotation = 90 if tab_pos[0] == 'l' else -90\n            sctr = Scatter(do_translation=False,\n                           rotation=rotation,\n                           do_rotation=False,\n                           do_scale=False,\n                           size_hint=(None, None),\n                           auto_bring_to_front=False,\n                           size=scrl_v.size)\n            sctr.add_widget(scrl_v)\n\n            lentab_pos = len(tab_pos)\n\n            # Update scatter's top when it's pos changes.\n            # Needed for repositioning scatter to the correct place after its\n            # added to the parent. Use clock_schedule_once to ensure top is\n            # calculated after the parent's pos on canvas has been calculated.\n            # This is needed for when tab_pos changes to correctly position\n            # scatter. Without clock.schedule_once the positions would look\n            # fine but touch won't translate to the correct position\n\n            if tab_pos[lentab_pos - 4:] == '_top':\n                #on positions 'left_top' and 'right_top'\n                sctr.bind(pos=partial(self._update_top, sctr, 'top', None))\n                tab_list = (sctr, )\n            elif tab_pos[lentab_pos - 4:] == '_mid':\n                #calculate top of scatter\n                sctr.bind(pos=partial(self._update_top, sctr, 'mid',\n                                      scrl_v.width))\n                tab_list = (Widget(), sctr, Widget())\n            elif tab_pos[lentab_pos - 7:] == '_bottom':\n                tab_list = (Widget(), Widget(), sctr)\n\n            if pos_letter == 'l':\n                widget_list = (tab_layout, self_content)\n            else:\n                widget_list = (self_content, tab_layout)\n\n        # add widgets to tab_layout\n        add = tab_layout.add_widget\n        for widg in tab_list:\n            add(widg)\n\n        # add widgets to self\n        add = self.add_widget\n        for widg in widget_list:\n            add(widg)\n\n    def _update_tab_width(self, *l):\n        if self.tab_width:\n            for tab in self.tab_list:\n                tab.size_hint_x = 1\n            tsw = self.tab_width * len(self._tab_strip.children)\n        else:\n            # tab_width = None\n            tsw = 0\n            for tab in self.tab_list:\n                if tab.size_hint_x:\n                    # size_hint_x: x/.xyz\n                    tab.size_hint_x = 1\n                    #drop to default tab_width\n                    tsw += 100\n                else:\n                    # size_hint_x: None\n                    tsw += tab.width\n        self._tab_strip.width = tsw\n        self._reposition_tabs()\n\n    def _update_top(self, *args):\n        sctr, top, scrl_v_width, x, y = args\n        Clock.unschedule(partial(self._updt_top, sctr, top, scrl_v_width))\n        Clock.schedule_once(\n            partial(self._updt_top, sctr, top, scrl_v_width), 0)\n\n    def _updt_top(self, sctr, top, scrl_v_width, *args):\n        if top[0] == 't':\n            sctr.top = self.top\n        else:\n            sctr.top = self.top - (self.height - scrl_v_width) / 2\n\n    def _update_scrollview(self, scrl_v, *l):\n        self_tab_pos = self.tab_pos\n        self_tabs = self._tab_strip\n        if self_tab_pos[0] == 'b' or self_tab_pos[0] == 't':\n            #bottom or top\n            scrl_v.width = min(self.width, self_tabs.width)\n            #required for situations when scrl_v's pos is calculated\n            #when it has no parent\n            scrl_v.top += 1\n            scrl_v.top -= 1\n        else:\n            # left or right\n            scrl_v.width = min(self.height, self_tabs.width)\n            self_tabs.pos = (0, 0)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/textinput.py",
    "content": "# -*- encoding: utf-8 -*-\n'''\nText Input\n==========\n\n.. versionadded:: 1.0.4\n\n.. image:: images/textinput-mono.jpg\n.. image:: images/textinput-multi.jpg\n\nThe :class:`TextInput` widget provides a box of editable plain text.\n\nUnicode, multiline, cursor navigation, selection and clipboard features\nare supported.\n\n.. note::\n\n    Two different coordinate systems are used with TextInput:\n\n        - (x, y) - coordinates in pixels, mostly used for rendering on screen.\n        - (row, col) - cursor index in characters / lines, used for selection\n          and cursor movement.\n\n\nUsage example\n-------------\n\nTo create a multiline textinput ('enter' key adds a new line)::\n\n    from kivy.uix.textinput import TextInput\n    textinput = TextInput(text='Hello world')\n\nTo create a singleline textinput, set the multiline property to False ('enter'\nkey will defocus the textinput and emit on_text_validate event)::\n\n    def on_enter(instance, value):\n        print('User pressed enter in', instance)\n\n    textinput = TextInput(text='Hello world', multiline=False)\n    textinput.bind(on_text_validate=on_enter)\n\nThe textinput's text is stored on its :attr:`TextInput.text` property. To run a\ncallback when the text changes::\n\n    def on_text(instance, value):\n        print('The widget', instance, 'have:', value)\n\n    textinput = TextInput()\n    textinput.bind(text=on_text)\n\nYou can 'focus' a textinput, meaning that the input box will be highlighted\nand keyboard focus will be requested::\n\n    textinput = TextInput(focus=True)\n\nThe textinput is defocused if the 'escape' key is pressed, or if another\nwidget requests the keyboard. You can bind a callback to the focus property to\nget notified of focus changes::\n\n    def on_focus(instance, value):\n        if value:\n            print('User focused', instance)\n        else:\n            print('User defocused', instance)\n\n    textinput = TextInput()\n    textinput.bind(focus=on_focus)\n\nSee :class:`~kivy.uix.behaviors.FocusBehavior` from which :class:`TextInput`\ninherits for more details.\n\n\nSelection\n---------\n\nThe selection is automatically updated when the cursor position changes.\nYou can get the currently selected text from the\n:attr:`TextInput.selection_text` property.\n\nFiltering\n---------\n\nYou can control which text can be added to the :class:`TextInput` by\noverwriting :meth:`TextInput.insert_text`.Every string that is typed, pasted\nor inserted by any other means to the :class:`TextInput` is passed through\nthis function. By overwriting it you can reject or change unwanted characters.\n\nFor example, to write only in capitalized characters::\n\n    class CapitalInput(TextInput):\n\n        def insert_text(self, substring, from_undo=False):\n            s = substring.upper()\n            return super(CapitalInput, self).insert_text(s,\\\n from_undo=from_undo)\n\nOr to only allow floats (0 - 9 and a single period)::\n\n    class FloatInput(TextInput):\n\n        pat = re.compile('[^0-9]')\n        def insert_text(self, substring, from_undo=False):\n            pat = self.pat\n            if '.' in self.text:\n                s = re.sub(pat, '', substring)\n            else:\n                s = '.'.join([re.sub(pat, '', s) for s in\\\n substring.split('.', 1)])\n            return super(FloatInput, self).insert_text(s, from_undo=from_undo)\n\nDefault shortcuts\n-----------------\n\n=============== ========================================================\n   Shortcuts    Description\n--------------- --------------------------------------------------------\nLeft            Move cursor to left\nRight           Move cursor to right\nUp              Move cursor to up\nDown            Move cursor to down\nHome            Move cursor at the beginning of the line\nEnd             Move cursor at the end of the line\nPageUp          Move cursor to 3 lines before\nPageDown        Move cursor to 3 lines after\nBackspace       Delete the selection or character before the cursor\nDel             Delete the selection of character after the cursor\nShift + <dir>   Start a text selection. Dir can be Up, Down, Left, Right\nControl + c     Copy selection\nControl + x     Cut selection\nControl + p     Paste selection\nControl + a     Select all the content\nControl + z     undo\nControl + r     redo\n=============== ========================================================\n\n'''\n\n\n__all__ = ('TextInput', )\n\n\nimport re\nimport sys\nfrom functools import partial\nfrom os import environ\nfrom weakref import ref\n\nfrom kivy.animation import Animation\nfrom kivy.base import EventLoop\nfrom kivy.cache import Cache\nfrom kivy.clock import Clock\nfrom kivy.config import Config\nfrom kivy.compat import PY2\nfrom kivy.logger import Logger\nfrom kivy.metrics import inch\nfrom kivy.utils import boundary, platform\nfrom kivy.uix.behaviors import FocusBehavior\n\nfrom kivy.core.text import Label\nfrom kivy.graphics import Color, Rectangle, PushMatrix, PopMatrix, Callback\nfrom kivy.graphics.context_instructions import Transform\nfrom kivy.graphics.texture import Texture\n\nfrom kivy.uix.widget import Widget\nfrom kivy.uix.bubble import Bubble\nfrom kivy.uix.behaviors import ButtonBehavior\nfrom kivy.uix.image import Image\n\nfrom kivy.properties import StringProperty, NumericProperty, \\\n    BooleanProperty, AliasProperty, \\\n    ListProperty, ObjectProperty, VariableListProperty, OptionProperty\n\nCache_register = Cache.register\nCache_append = Cache.append\nCache_get = Cache.get\nCache_remove = Cache.remove\nCache_register('textinput.label', timeout=60.)\nCache_register('textinput.width', timeout=60.)\n\nFL_IS_NEWLINE = 0x01\n\n# late binding\nClipboard = None\nMarkupLabel = None\n_platform = platform\n\n# for reloading, we need to keep a list of textinput to retrigger the rendering\n_textinput_list = []\n\n# cache the result\n_is_osx = sys.platform == 'darwin'\n\n# When we are generating documentation, Config doesn't exist\n_is_desktop = False\nif Config:\n    _is_desktop = Config.getboolean('kivy', 'desktop')\n\n# register an observer to clear the textinput cache when OpenGL will reload\nif 'KIVY_DOC' not in environ:\n\n    def _textinput_clear_cache(*l):\n        Cache_remove('textinput.label')\n        Cache_remove('textinput.width')\n        for wr in _textinput_list[:]:\n            textinput = wr()\n            if textinput is None:\n                _textinput_list.remove(wr)\n            else:\n                textinput._trigger_refresh_text()\n                textinput._refresh_hint_text()\n\n    from kivy.graphics.context import get_context\n    get_context().add_reload_observer(_textinput_clear_cache, True)\n\n\nclass Selector(ButtonBehavior, Image):\n    # Internal class for managing the selection Handles.\n\n    window = ObjectProperty()\n    target = ObjectProperty()\n    matrix = ObjectProperty()\n\n    def __init__(self, **kwargs):\n        super(Selector, self).__init__(**kwargs)\n        self.window.bind(on_touch_down=self.on_window_touch_down)\n        self.matrix = self.target.get_window_matrix()\n\n        with self.canvas.before:\n            Callback(self.update_transform)\n            PushMatrix()\n            self.transform = Transform()\n\n        with self.canvas.after:\n            PopMatrix()\n\n    def update_transform(self, cb):\n        m = self.target.get_window_matrix()\n        if self.matrix != m:\n            self.matrix = m\n            self.transform.identity()\n            self.transform.transform(self.matrix)\n\n    def transform_touch(self, touch):\n        matrix = self.matrix.inverse()\n        touch.apply_transform_2d(\n            lambda x, y: matrix.transform_point(x, y, 0)[:2])\n\n    def on_window_touch_down(self, win, touch):\n        if self.parent is not win:\n            return\n\n        try:\n            touch.push()\n            self.transform_touch(touch)\n            self._touch_diff = self.top - touch.y\n            if self.collide_point(*touch.pos):\n                FocusBehavior.ignored_touch.append(touch)\n            return super(Selector, self).on_touch_down(touch)\n        finally:\n            touch.pop()\n\n\nclass TextInputCutCopyPaste(Bubble):\n    # Internal class used for showing the little bubble popup when\n    # copy/cut/paste happen.\n\n    textinput = ObjectProperty(None)\n    ''' Holds a reference to the TextInput this Bubble belongs to.\n    '''\n\n    but_cut = ObjectProperty(None)\n    but_copy = ObjectProperty(None)\n    but_paste = ObjectProperty(None)\n    but_selectall = ObjectProperty(None)\n\n    matrix = ObjectProperty(None)\n\n    def __init__(self, **kwargs):\n        self.mode = 'normal'\n        super(TextInputCutCopyPaste, self).__init__(**kwargs)\n        Clock.schedule_interval(self._check_parent, .5)\n        self.matrix = self.textinput.get_window_matrix()\n\n        with self.canvas.before:\n            Callback(self.update_transform)\n            PushMatrix()\n            self.transform = Transform()\n\n        with self.canvas.after:\n            PopMatrix()\n\n    def update_transform(self, cb):\n        m = self.textinput.get_window_matrix()\n        if self.matrix != m:\n            self.matrix = m\n            self.transform.identity()\n            self.transform.transform(self.matrix)\n\n    def transform_touch(self, touch):\n        matrix = self.matrix.inverse()\n        touch.apply_transform_2d(\n            lambda x, y: matrix.transform_point(x, y, 0)[:2])\n\n    def on_touch_down(self, touch):\n        try:\n            touch.push()\n            self.transform_touch(touch)\n            if self.collide_point(*touch.pos):\n                FocusBehavior.ignored_touch.append(touch)\n            return super(TextInputCutCopyPaste, self).on_touch_down(touch)\n        finally:\n            touch.pop()\n\n    def on_textinput(self, instance, value):\n        global Clipboard\n        if value and not Clipboard and not _is_desktop:\n            value._ensure_clipboard()\n\n    def _check_parent(self, dt):\n        # this is a prevention to get the Bubble staying on the screen, if the\n        # attached textinput is not on the screen anymore.\n        parent = self.textinput\n        while parent is not None:\n            if parent == parent.parent:\n                break\n            parent = parent.parent\n        if parent is None:\n            Clock.unschedule(self._check_parent)\n            if self.textinput:\n                self.textinput._hide_cut_copy_paste()\n\n    def on_parent(self, instance, value):\n        parent = self.textinput\n        mode = self.mode\n\n        if parent:\n            self.clear_widgets()\n            if mode == 'paste':\n                # show only paste on long touch\n                self.but_selectall.opacity = 1\n                widget_list = [self.but_selectall, ]\n                if not parent.readonly:\n                    widget_list.append(self.but_paste)\n            elif parent.readonly:\n                # show only copy for read only text input\n                widget_list = (self.but_copy, )\n            else:\n                # normal mode\n                widget_list = (self.but_cut, self.but_copy, self.but_paste)\n\n            for widget in widget_list:\n                self.add_widget(widget)\n\n    def do(self, action):\n        textinput = self.textinput\n\n        if action == 'cut':\n            textinput._cut(textinput.selection_text)\n        elif action == 'copy':\n            textinput.copy()\n        elif action == 'paste':\n            textinput.paste()\n        elif action == 'selectall':\n            textinput.select_all()\n            self.mode = ''\n            anim = Animation(opacity=0, d=.333)\n            anim.bind(on_complete=lambda *args:\n                      self.on_parent(self, self.parent))\n            anim.start(self.but_selectall)\n            return\n\n        self.hide()\n\n    def hide(self):\n        parent = self.parent\n        if not parent:\n            return\n\n        anim = Animation(opacity=0, d=.225)\n        anim.bind(on_complete=lambda *args: parent.remove_widget(self))\n        anim.start(self)\n\n\nclass TextInput(FocusBehavior, Widget):\n    '''TextInput class. See module documentation for more information.\n\n    :Events:\n        `on_text_validate`\n            Fired only in multiline=False mode when the user hits 'enter'.\n            This will also unfocus the textinput.\n        `on_double_tap`\n            Fired when a double tap happens in the text input. The default\n            behavior selects the text around the cursor position. More info at\n            :meth:`on_double_tap`.\n        `on_triple_tap`\n            Fired when a triple tap happens in the text input. The default\n            behavior selects the line around the cursor position. More info at\n            :meth:`on_triple_tap`.\n        `on_quad_touch`\n            Fired when four fingers are touching the text input. The default\n            behavior selects the whole text. More info at\n            :meth:`on_quad_touch`.\n\n    .. warning::\n        When changing a :class:`TextInput` property that requires re-drawing,\n        e.g. modifying the :attr:`text`, the updates occur on the next\n        clock cycle and not instantly. This might cause any changes to the\n        :class:`TextInput` that occur between the modification and the next\n        cycle to be ignored, or to use previous values. For example, after\n        a update to the :attr:`text`, changing the cursor in the same clock\n        frame will move it using the previous text and will likely end up in an\n        incorrect position. The solution is to schedule any updates to occur\n        on the next clock cycle using\n        :meth:`~kivy.clock.ClockBase.schedule_once`.\n\n    .. Note::\n        Selection is cancelled when TextInput is focused. If you need to\n        show selection when TextInput is focused, you should delay\n        (use Clock.schedule) the call to the functions for selecting\n        text (select_all, select_text).\n\n    .. versionchanged:: 1.9.0\n        :class:`TextInput` now inherits from\n        :class:`~kivy.uix.behaviors.FocusBehavior`.\n\n        :attr:`~kivy.uix.behaviors.FocusBehavior.keyboard_mode`,\n        :meth:`~kivy.uix.behaviors.FocusBehavior.show_keyboard`,\n        :meth:`~kivy.uix.behaviors.FocusBehavior.hide_keyboard`,\n        :meth:`~kivy.uix.behaviors.FocusBehavior.focus`,\n        and :attr:`~kivy.uix.behaviors.FocusBehavior.input_type`,\n        have been removed from :class:`TextInput` since they already inherit\n        them from :class:`~kivy.uix.behaviors.FocusBehavior`.\n\n    .. versionchanged:: 1.7.0\n        `on_double_tap`, `on_triple_tap` and `on_quad_touch` events added.\n    '''\n\n    __events__ = ('on_text_validate', 'on_double_tap', 'on_triple_tap',\n                  'on_quad_touch')\n\n    def __init__(self, **kwargs):\n        self.is_focusable = kwargs.get('is_focusable', True)\n        self._cursor_blink_time = Clock.get_time()\n        self._cursor = [0, 0]\n        self._selection = False\n        self._selection_finished = True\n        self._selection_touch = None\n        self.selection_text = u''\n        self._selection_from = None\n        self._selection_to = None\n        self._handle_left = None\n        self._handle_right = None\n        self._handle_middle = None\n        self._bubble = None\n        self._lines_flags = []\n        self._lines_labels = []\n        self._lines_rects = []\n        self._hint_text_flags = []\n        self._hint_text_labels = []\n        self._hint_text_rects = []\n        self._label_cached = None\n        self._line_options = None\n        self._keyboard_mode = Config.get('kivy', 'keyboard_mode')\n        self._command_mode = False\n        self._command = ''\n        self.reset_undo()\n        self._touch_count = 0\n        self.interesting_keys = {\n            8: 'backspace',\n            13: 'enter',\n            127: 'del',\n            271: 'enter',\n            273: 'cursor_up',\n            274: 'cursor_down',\n            275: 'cursor_right',\n            276: 'cursor_left',\n            278: 'cursor_home',\n            279: 'cursor_end',\n            280: 'cursor_pgup',\n            281: 'cursor_pgdown',\n            303: 'shift_L',\n            304: 'shift_R'}\n\n        super(TextInput, self).__init__(**kwargs)\n\n        self.bind(font_size=self._trigger_refresh_line_options,\n                  font_name=self._trigger_refresh_line_options)\n\n        def handle_readonly(instance, value):\n            if value and (not _is_desktop or not self.allow_copy):\n                self.is_focusable = False\n\n        self.bind(padding=self._update_text_options,\n                  tab_width=self._update_text_options,\n                  font_size=self._update_text_options,\n                  font_name=self._update_text_options,\n                  size=self._update_text_options,\n                  password=self._update_text_options)\n\n        self.bind(pos=self._trigger_update_graphics,\n                  readonly=handle_readonly, focus=self._on_textinput_focused)\n        handle_readonly(self, self.readonly)\n\n        self._trigger_position_handles = Clock.create_trigger(\n            self._position_handles)\n        self._trigger_show_handles = Clock.create_trigger(\n            self._show_handles, .05)\n        self._trigger_refresh_line_options()\n        self._trigger_refresh_text()\n\n        self.bind(pos=self._trigger_position_handles,\n                  size=self._trigger_position_handles)\n\n        # when the gl context is reloaded, trigger the text rendering again.\n        _textinput_list.append(ref(self, TextInput._reload_remove_observer))\n\n    def on_text_validate(self):\n        pass\n\n    def cursor_index(self, cursor=None):\n        '''Return the cursor index in the text/value.\n        '''\n        if not cursor:\n            cursor = self.cursor\n        try:\n            l = self._lines\n            if len(l) == 0:\n                return 0\n            lf = self._lines_flags\n            index, cr = cursor\n            for row in range(cr):\n                if row >= len(l):\n                    continue\n                index += len(l[row])\n                if lf[row] & FL_IS_NEWLINE:\n                    index += 1\n            if lf[cr] & FL_IS_NEWLINE:\n                index += 1\n            return index\n        except IndexError:\n            return 0\n\n    def cursor_offset(self):\n        '''Get the cursor x offset on the current line.\n        '''\n        offset = 0\n        row = self.cursor_row\n        col = self.cursor_col\n        _lines = self._lines\n        if col and row < len(_lines):\n            offset = self._get_text_width(\n                _lines[row][:col], self.tab_width,\n                self._label_cached)\n        return offset\n\n    def get_cursor_from_index(self, index):\n        '''Return the (row, col) of the cursor from text index.\n        '''\n        index = boundary(index, 0, len(self.text))\n        if index <= 0:\n            return 0, 0\n        lf = self._lines_flags\n        l = self._lines\n        i = 0\n        for row in range(len(l)):\n            ni = i + len(l[row])\n            if lf[row] & FL_IS_NEWLINE:\n                ni += 1\n                i += 1\n            if ni >= index:\n                return index - i, row\n            i = ni\n        return index, row\n\n    def select_text(self, start, end):\n        ''' Select a portion of text displayed in this TextInput.\n\n        .. versionadded:: 1.4.0\n\n        :Parameters:\n            `start`\n                Index of textinput.text from where to start selection\n            `end`\n                Index of textinput.text till which the selection should be\n                displayed\n        '''\n        if end < start:\n            raise Exception('end must be superior to start')\n        m = len(self.text)\n        self._selection_from = boundary(start, 0, m)\n        self._selection_to = boundary(end, 0, m)\n        self._selection_finished = True\n        self._update_selection(True)\n        self._update_graphics_selection()\n\n    def select_all(self):\n        ''' Select all of the text displayed in this TextInput.\n\n        .. versionadded:: 1.4.0\n        '''\n        self.select_text(0, len(self.text))\n\n    re_indent = re.compile('^(\\s*|)')\n\n    def _auto_indent(self, substring):\n        index = self.cursor_index()\n        _text = self._get_text(encode=False)\n        if index > 0:\n            line_start = _text.rfind('\\n', 0, index)\n            if line_start > -1:\n                line = _text[line_start + 1:index]\n                indent = self.re_indent.match(line).group()\n                substring += indent\n        return substring\n\n    def insert_text(self, substring, from_undo=False):\n        '''Insert new text at the current cursor position. Override this\n        function in order to pre-process text for input validation.\n        '''\n        if self.readonly or not substring:\n            return\n\n        mode = self.input_filter\n        if mode is not None:\n            chr = type(substring)\n            if chr is bytes:\n                int_pat = self._insert_int_patb\n            else:\n                int_pat = self._insert_int_patu\n\n            if mode == 'int':\n                substring = re.sub(int_pat, chr(''), substring)\n            elif mode == 'float':\n                if '.' in self.text:\n                    substring = re.sub(int_pat, chr(''), substring)\n                else:\n                    substring = '.'.join([re.sub(int_pat, chr(''), k) for k\n                                          in substring.split(chr('.'), 1)])\n            else:\n                substring = mode(substring, from_undo)\n            if not substring:\n                return\n\n        self._hide_handles(EventLoop.window)\n\n        if not from_undo and self.multiline and self.auto_indent \\\n                and substring == u'\\n':\n            substring = self._auto_indent(substring)\n\n        cc, cr = self.cursor\n        sci = self.cursor_index\n        ci = sci()\n        text = self._lines[cr]\n        len_str = len(substring)\n        new_text = text[:cc] + substring + text[cc:]\n        self._set_line_text(cr, new_text)\n\n        wrap = (self._get_text_width(\n            new_text,\n            self.tab_width,\n            self._label_cached) > self.width)\n        if len_str > 1 or substring == u'\\n' or wrap:\n            # Avoid refreshing text on every keystroke.\n            # Allows for faster typing of text when the amount of text in\n            # TextInput gets large.\n\n            start, finish, lines,\\\n                lineflags, len_lines = self._get_line_from_cursor(cr, new_text)\n            # calling trigger here could lead to wrong cursor positioning\n            # and repeating of text when keys are added rapidly in a automated\n            # fashion. From Android Keyboard for example.\n            self._refresh_text_from_property('insert', start, finish, lines,\n                                             lineflags, len_lines)\n\n        self.cursor = self.get_cursor_from_index(ci + len_str)\n        # handle undo and redo\n        self._set_unredo_insert(ci, ci + len_str, substring, from_undo)\n\n    def _get_line_from_cursor(self, start, new_text):\n        # get current paragraph from cursor position\n        finish = start\n        lines = self._lines\n        linesflags = self._lines_flags\n        if start and not linesflags[start]:\n            start -= 1\n            new_text = u''.join((lines[start], new_text))\n        try:\n            while not linesflags[finish + 1]:\n                new_text = u''.join((new_text, lines[finish + 1]))\n                finish += 1\n        except IndexError:\n            pass\n        lines, lineflags = self._split_smart(new_text)\n        len_lines = max(1, len(lines))\n        return start, finish, lines, lineflags, len_lines\n\n    def _set_unredo_insert(self, ci, sci, substring, from_undo):\n        # handle undo and redo\n        if from_undo:\n            return\n        self._undo.append({'undo_command': ('insert', ci, sci),\n                           'redo_command': (ci, substring)})\n        # reset redo when undo is appended to\n        self._redo = []\n\n    def reset_undo(self):\n        '''Reset undo and redo lists from memory.\n\n        .. versionadded:: 1.3.0\n\n        '''\n        self._redo = self._undo = []\n\n    def do_redo(self):\n        '''Do redo operation.\n\n        .. versionadded:: 1.3.0\n\n        This action re-does any command that has been un-done by\n        do_undo/ctrl+z. This function is automatically called when\n        `ctrl+r` keys are pressed.\n        '''\n        try:\n            x_item = self._redo.pop()\n            undo_type = x_item['undo_command'][0]\n            _get_cusror_from_index = self.get_cursor_from_index\n\n            if undo_type == 'insert':\n                ci, substring = x_item['redo_command']\n                self.cursor = _get_cusror_from_index(ci)\n                self.insert_text(substring, True)\n            elif undo_type == 'bkspc':\n                self.cursor = _get_cusror_from_index(x_item['redo_command'])\n                self.do_backspace(from_undo=True)\n            else:\n                # delsel\n                ci, sci = x_item['redo_command']\n                self._selection_from = ci\n                self._selection_to = sci\n                self._selection = True\n                self.delete_selection(True)\n                self.cursor = _get_cusror_from_index(ci)\n            self._undo.append(x_item)\n        except IndexError:\n            # reached at top of undo list\n            pass\n\n    def do_undo(self):\n        '''Do undo operation.\n\n        .. versionadded:: 1.3.0\n\n        This action un-does any edits that have been made since the last\n        call to reset_undo().\n        This function is automatically called when `ctrl+z` keys are pressed.\n        '''\n        try:\n            x_item = self._undo.pop()\n            undo_type = x_item['undo_command'][0]\n            self.cursor = self.get_cursor_from_index(x_item['undo_command'][1])\n\n            if undo_type == 'insert':\n                ci, sci = x_item['undo_command'][1:]\n                self._selection_from = ci\n                self._selection_to = sci\n                self._selection = True\n                self.delete_selection(True)\n            elif undo_type == 'bkspc':\n                substring = x_item['undo_command'][2:][0]\n                self.insert_text(substring, True)\n            else:\n                # delsel\n                substring = x_item['undo_command'][2:][0]\n                self.insert_text(substring, True)\n            self._redo.append(x_item)\n        except IndexError:\n            # reached at top of undo list\n            pass\n\n    def do_backspace(self, from_undo=False, mode='bkspc'):\n        '''Do backspace operation from the current cursor position.\n        This action might do several things:\n\n            - removing the current selection if available.\n            - removing the previous char and move the cursor back.\n            - do nothing, if we are at the start.\n\n        '''\n        if self.readonly:\n            return\n        cc, cr = self.cursor\n        _lines = self._lines\n        text = _lines[cr]\n        cursor_index = self.cursor_index()\n        text_last_line = _lines[cr - 1]\n\n        if cc == 0 and cr == 0:\n            return\n        _lines_flags = self._lines_flags\n        start = cr\n        if cc == 0:\n            substring = u'\\n' if _lines_flags[cr] else u' '\n            new_text = text_last_line + text\n            self._set_line_text(cr - 1, new_text)\n            self._delete_line(cr)\n            start = cr - 1\n        else:\n            #ch = text[cc-1]\n            substring = text[cc - 1]\n            new_text = text[:cc - 1] + text[cc:]\n            self._set_line_text(cr, new_text)\n\n        # refresh just the current line instead of the whole text\n        start, finish, lines, lineflags, len_lines =\\\n            self._get_line_from_cursor(start, new_text)\n        # avoid trigger refresh, leads to issue with\n        # keys/text send rapidly through code.\n        self._refresh_text_from_property('del', start, finish, lines,\n                                         lineflags, len_lines)\n\n        self.cursor = self.get_cursor_from_index(cursor_index - 1)\n        # handle undo and redo\n        self._set_undo_redo_bkspc(\n            cursor_index,\n            cursor_index - 1,\n            substring, from_undo)\n\n    def _set_undo_redo_bkspc(self, ol_index, new_index, substring, from_undo):\n        # handle undo and redo for backspace\n        if from_undo:\n            return\n        self._undo.append({\n            'undo_command': ('bkspc', new_index, substring),\n            'redo_command': ol_index})\n        #reset redo when undo is appended to\n        self._redo = []\n\n    def do_cursor_movement(self, action):\n        '''Move the cursor relative to it's current position.\n        Action can be one of :\n\n            - cursor_left: move the cursor to the left\n            - cursor_right: move the cursor to the right\n            - cursor_up: move the cursor on the previous line\n            - cursor_down: move the cursor on the next line\n            - cursor_home: move the cursor at the start of the current line\n            - cursor_end: move the cursor at the end of current line\n            - cursor_pgup: move one \"page\" before\n            - cursor_pgdown: move one \"page\" after\n\n        '''\n        pgmove_speed = int(self.height /\n            (self.line_height + self.line_spacing) - 1)\n        col, row = self.cursor\n        if action == 'cursor_up':\n            row = max(row - 1, 0)\n            col = min(len(self._lines[row]), col)\n        elif action == 'cursor_down':\n            row = min(row + 1, len(self._lines) - 1)\n            col = min(len(self._lines[row]), col)\n        elif action == 'cursor_left':\n            if col == 0:\n                if row:\n                    row -= 1\n                    col = len(self._lines[row])\n            else:\n                col, row = col - 1, row\n        elif action == 'cursor_right':\n            if col == len(self._lines[row]):\n                if row < len(self._lines) - 1:\n                    col = 0\n                    row += 1\n            else:\n                col, row = col + 1, row\n        elif action == 'cursor_home':\n            col = 0\n        elif action == 'cursor_end':\n            col = len(self._lines[row])\n        elif action == 'cursor_pgup':\n            row = max(0, row - pgmove_speed)\n            col = min(len(self._lines[row]), col)\n        elif action == 'cursor_pgdown':\n            row = min(row + pgmove_speed, len(self._lines) - 1)\n            col = min(len(self._lines[row]), col)\n        self.cursor = (col, row)\n\n    def get_cursor_from_xy(self, x, y):\n        '''Return the (row, col) of the cursor from an (x, y) position.\n        '''\n        padding_left = self.padding[0]\n        padding_top = self.padding[1]\n        l = self._lines\n        dy = self.line_height + self.line_spacing\n        cx = x - self.x\n        scrl_y = self.scroll_y\n        scrl_x = self.scroll_x\n        scrl_y = scrl_y / dy if scrl_y > 0 else 0\n        cy = (self.top - padding_top + scrl_y * dy) - y\n        cy = int(boundary(round(cy / dy - 0.5), 0, len(l) - 1))\n        dcx = 0\n        _get_text_width = self._get_text_width\n        _tab_width = self.tab_width\n        _label_cached = self._label_cached\n        for i in range(1, len(l[cy]) + 1):\n            if _get_text_width(l[cy][:i],\n                               _tab_width,\n                               _label_cached) + padding_left >= cx + scrl_x:\n                break\n            dcx = i\n        cx = dcx\n        return cx, cy\n\n    #\n    # Selection control\n    #\n    def cancel_selection(self):\n        '''Cancel current selection (if any).\n        '''\n        self._selection_from = self._selection_to = self.cursor_index()\n        self._selection = False\n        self._selection_finished = True\n        self._selection_touch = None\n        self._trigger_update_graphics()\n\n    def delete_selection(self, from_undo=False):\n        '''Delete the current text selection (if any).\n        '''\n        if self.readonly:\n            return\n        self._hide_handles(EventLoop.window)\n        scrl_x = self.scroll_x\n        scrl_y = self.scroll_y\n        cc, cr = self.cursor\n        if not self._selection:\n            return\n        v = self._get_text(encode=False)\n        a, b = self._selection_from, self._selection_to\n        if a > b:\n            a, b = b, a\n        self.cursor = cursor = self.get_cursor_from_index(a)\n        start = cursor\n        finish = self.get_cursor_from_index(b)\n        cur_line = self._lines[start[1]][:start[0]] +\\\n            self._lines[finish[1]][finish[0]:]\n        lines, lineflags = self._split_smart(cur_line)\n        len_lines = len(lines)\n        if start[1] == finish[1]:\n            self._set_line_text(start[1], cur_line)\n        else:\n            self._refresh_text_from_property('del', start[1], finish[1], lines,\n                                             lineflags, len_lines)\n        self.scroll_x = scrl_x\n        self.scroll_y = scrl_y\n        # handle undo and redo for delete selecttion\n        self._set_unredo_delsel(a, b, v[a:b], from_undo)\n        self.cancel_selection()\n\n    def _set_unredo_delsel(self, a, b, substring, from_undo):\n        # handle undo and redo for backspace\n        if from_undo:\n            return\n\n        self._undo.append({\n            'undo_command': ('delsel', a, substring),\n            'redo_command': (a, b)})\n        # reset redo when undo is appended to\n        self._redo = []\n\n    def _update_selection(self, finished=False):\n        '''Update selection text and order of from/to if finished is True.\n        Can be called multiple times until finished is True.\n        '''\n        a, b = self._selection_from, self._selection_to\n        if a > b:\n            a, b = b, a\n        self._selection_finished = finished\n        _selection_text = self._get_text(encode=False)[a:b]\n        self.selection_text = (\"\" if not self.allow_copy else\n                               (('*' * (b - a)) if self.password else\n                                _selection_text))\n        if not finished:\n            self._selection = True\n        else:\n            self._selection = bool(len(_selection_text))\n            self._selection_touch = None\n        if a == 0:\n            # update graphics only on new line\n            # allows smoother scrolling, noticeably\n            # faster when dealing with large text.\n            self._update_graphics_selection()\n            #self._trigger_update_graphics()\n\n    #\n    # Touch control\n    #\n    def long_touch(self, dt):\n        if self._selection_to == self._selection_from:\n            pos = self.to_local(*self._long_touch_pos, relative=True)\n            self._show_cut_copy_paste(\n                pos, EventLoop.window, mode='paste')\n\n    def on_double_tap(self):\n        '''This event is dispatched when a double tap happens\n        inside TextInput. The default behavior is to select the\n        word around the current cursor position. Override this to provide\n        different behavior. Alternatively, you can bind to this\n        event to provide additional functionality.\n        '''\n        ci = self.cursor_index()\n        cc = self.cursor_col\n        line = self._lines[self.cursor_row]\n        len_line = len(line)\n        start = max(0, len(line[:cc]) - line[:cc].rfind(u' ') - 1)\n        end = line[cc:].find(u' ')\n        end = end if end > - 1 else (len_line - cc)\n        Clock.schedule_once(lambda dt: self.select_text(ci - start, ci + end))\n\n    def on_triple_tap(self):\n        '''This event is dispatched when a triple tap happens\n        inside TextInput. The default behavior is to select the\n        line around current cursor position. Override this to provide\n        different behavior. Alternatively, you can bind to this\n        event to provide additional functionality.\n        '''\n        ci = self.cursor_index()\n        cc = self.cursor_col\n        line = self._lines[self.cursor_row]\n        len_line = len(line)\n        Clock.schedule_once(lambda dt:\n                            self.select_text(ci - cc, ci + (len_line - cc)))\n\n    def on_quad_touch(self):\n        '''This event is dispatched when four fingers are touching\n        inside TextInput. The default behavior is to select all text.\n        Override this to provide different behavior. Alternatively,\n        you can bind to this event to provide additional functionality.\n        '''\n        Clock.schedule_once(lambda dt: self.select_all())\n\n    def on_touch_down(self, touch):\n        if self.disabled:\n            return\n\n        touch_pos = touch.pos\n        if not self.collide_point(*touch_pos):\n            return False\n        if super(TextInput, self).on_touch_down(touch):\n            return True\n\n        # Check for scroll wheel\n        if 'button' in touch.profile and touch.button.startswith('scroll'):\n            scroll_type = touch.button[6:]\n            if scroll_type == 'down':\n                if self.multiline:\n                    if self.scroll_y <= 0:\n                        return\n                    self.scroll_y -= self.line_height\n                else:\n                    if self.scroll_x <= 0:\n                        return\n                    self.scroll_x -= self.line_height\n            if scroll_type == 'up':\n                if self.multiline:\n                    if (self._lines_rects[-1].pos[1] > self.y +\n                        self.line_height):\n                        return\n                    self.scroll_y += self.line_height\n                else:\n                    if (self.scroll_x + self.width >=\n                        self._lines_rects[-1].texture.size[0]):\n                        return\n                    self.scroll_x += self.line_height\n\n        touch.grab(self)\n        self._touch_count += 1\n        if touch.is_double_tap:\n            self.dispatch('on_double_tap')\n        if touch.is_triple_tap:\n            self.dispatch('on_triple_tap')\n        if self._touch_count == 4:\n            self.dispatch('on_quad_touch')\n\n        self._hide_cut_copy_paste(EventLoop.window)\n        # schedule long touch for paste\n        self._long_touch_pos = touch.pos\n        Clock.schedule_once(self.long_touch, .5)\n\n        self.cursor = self.get_cursor_from_xy(*touch_pos)\n        if not self._selection_touch:\n            self.cancel_selection()\n            self._selection_touch = touch\n            self._selection_from = self._selection_to = self.cursor_index()\n            self._update_selection()\n        return False\n\n    def on_touch_move(self, touch):\n        if touch.grab_current is not self:\n            return\n        if not self.focus:\n            touch.ungrab(self)\n            if self._selection_touch is touch:\n                self._selection_touch = None\n            return False\n        if self._selection_touch is touch:\n            self.cursor = self.get_cursor_from_xy(touch.x, touch.y)\n            self._selection_to = self.cursor_index()\n            self._update_selection()\n            return True\n\n    def on_touch_up(self, touch):\n        if touch.grab_current is not self:\n            return\n        touch.ungrab(self)\n        self._touch_count -= 1\n\n        # schedule long touch for paste\n        Clock.unschedule(self.long_touch)\n\n        if not self.focus:\n            return False\n\n        if self._selection_touch is touch:\n            self._selection_to = self.cursor_index()\n            self._update_selection(True)\n            # show Bubble\n            win = EventLoop.window\n            if self._selection_to != self._selection_from:\n                self._show_cut_copy_paste(touch.pos, win)\n            elif self.use_handles:\n                self._hide_handles()\n                handle_middle = self._handle_middle\n                if handle_middle is None:\n                    self._handle_middle = handle_middle = Selector(\n                        source=self.handle_image_middle,\n                        window=win,\n                        target=self,\n                        size_hint=(None, None),\n                        size=('45dp', '45dp'))\n                    handle_middle.bind(on_press=self._handle_pressed,\n                                       on_touch_move=self._handle_move,\n                                       on_release=self._handle_released)\n                if not self._handle_middle.parent and self.text:\n                    EventLoop.window.add_widget(handle_middle, canvas='after')\n                self._position_handles(mode='middle')\n            return True\n\n    def _handle_pressed(self, instance):\n        self._hide_cut_copy_paste()\n        sf, st = self._selection_from, self.selection_to\n        if sf > st:\n            self._selection_from, self._selection_to = st, sf\n\n    def _handle_released(self, instance):\n        sf, st = self._selection_from, self.selection_to\n        if sf == st:\n            return\n\n        self._update_selection()\n        self._show_cut_copy_paste(\n            (instance.right if instance is self._handle_left else instance.x,\n             instance.top + self.line_height),\n            EventLoop.window)\n\n    def _handle_move(self, instance, touch):\n        if touch.grab_current != instance:\n            return\n        get_cursor = self.get_cursor_from_xy\n        handle_right = self._handle_right\n        handle_left = self._handle_left\n        handle_middle = self._handle_middle\n\n        try:\n            touch.push()\n            touch.apply_transform_2d(self.to_widget)\n            x, y = touch.pos\n        finally:\n            touch.pop()\n\n        cursor = get_cursor(\n            x,\n            y + instance._touch_diff + (self.line_height / 2))\n\n        if instance != touch.grab_current:\n            return\n\n        if instance == handle_middle:\n            self.cursor = cursor\n            self._position_handles(mode='middle')\n            return\n\n        ci = self.cursor_index(cursor=cursor)\n        sf, st = self._selection_from, self.selection_to\n\n        if instance == handle_left:\n            self._selection_from = ci\n        elif instance == handle_right:\n            self._selection_to = ci\n        self._trigger_update_graphics()\n        self._trigger_position_handles()\n\n    def _position_handles(self, *args, **kwargs):\n        if not self.text:\n            return\n        mode = kwargs.get('mode', 'both')\n\n        lh = self.line_height\n\n        handle_middle = self._handle_middle\n        if handle_middle:\n            hp_mid = self.cursor_pos\n            pos = self.to_local(*hp_mid, relative=True)\n            handle_middle.x = pos[0] - handle_middle.width / 2\n            handle_middle.top = pos[1] - lh\n        if mode[0] == 'm':\n            return\n\n        group = self.canvas.get_group('selection')\n        if not group:\n            return\n\n        EventLoop.window.remove_widget(self._handle_middle)\n\n        handle_left = self._handle_left\n        if not handle_left:\n            return\n        hp_left = group[2].pos\n        handle_left.pos = self.to_local(*hp_left, relative=True)\n        handle_left.x -= handle_left.width\n        handle_left.y -= handle_left.height\n\n        handle_right = self._handle_right\n        last_rect = group[-1]\n        hp_right = last_rect.pos[0], last_rect.pos[1]\n        x, y = self.to_local(*hp_right, relative=True)\n        handle_right.x = x + last_rect.size[0]\n        handle_right.y = y - handle_right.height\n\n    def _hide_handles(self, win=None):\n        win = win or EventLoop.window\n        if win is None:\n            return\n        win.remove_widget(self._handle_right)\n        win.remove_widget(self._handle_left)\n        win.remove_widget(self._handle_middle)\n\n    def _show_handles(self, dt):\n        if not self.use_handles or not self.text:\n            return\n\n        win = EventLoop.window\n\n        handle_right = self._handle_right\n        handle_left = self._handle_left\n        if self._handle_left is None:\n            self._handle_left = handle_left = Selector(\n                source=self.handle_image_left,\n                target=self,\n                window=win,\n                size_hint=(None, None),\n                size=('45dp', '45dp'))\n            handle_left.bind(on_press=self._handle_pressed,\n                             on_touch_move=self._handle_move,\n                             on_release=self._handle_released)\n            self._handle_right = handle_right = Selector(\n                source=self.handle_image_right,\n                target=self,\n                window=win,\n                size_hint=(None, None),\n                size=('45dp', '45dp'))\n            handle_right.bind(on_press=self._handle_pressed,\n                              on_touch_move=self._handle_move,\n                              on_release=self._handle_released)\n        else:\n            if self._handle_left.parent:\n                self._position_handles()\n                return\n            if not self.parent:\n                return\n\n        self._trigger_position_handles()\n        if self.selection_from != self.selection_to:\n            self._handle_left.opacity = self._handle_right.opacity = 0\n            win.add_widget(self._handle_left, canvas='after')\n            win.add_widget(self._handle_right, canvas='after')\n            anim = Animation(opacity=1, d=.4)\n            anim.start(self._handle_right)\n            anim.start(self._handle_left)\n\n    def _show_cut_copy_paste(self, pos, win, parent_changed=False,\n                             mode='', pos_in_window=False, *l):\n        # Show a bubble with cut copy and paste buttons\n        if not self.use_bubble:\n            return\n\n        bubble = self._bubble\n        if bubble is None:\n            self._bubble = bubble = TextInputCutCopyPaste(textinput=self)\n            self.bind(parent=partial(self._show_cut_copy_paste,\n                                     pos, win, True))\n            win.bind(\n                size=lambda *args: self._hide_cut_copy_paste(win))\n            self.bind(cursor_pos=lambda *args: self._hide_cut_copy_paste(win))\n        else:\n            win.remove_widget(bubble)\n            if not self.parent:\n                return\n        if parent_changed:\n            return\n\n        # Search the position from the touch to the window\n        lh, ls = self.line_height, self.line_spacing\n\n        x, y = pos\n        t_pos = (x, y) if pos_in_window else self.to_window(x, y)\n        bubble_size = bubble.size\n        bubble_hw = bubble_size[0] / 2.\n        win_size = win.size\n        bubble_pos = (t_pos[0], t_pos[1] + inch(.25))\n\n        if (bubble_pos[0] - bubble_hw) < 0:\n            # bubble beyond left of window\n            if bubble_pos[1] > (win_size[1] - bubble_size[1]):\n                # bubble above window height\n                bubble_pos = (bubble_hw, (t_pos[1]) - (lh + ls + inch(.25)))\n                bubble.arrow_pos = 'top_left'\n            else:\n                bubble_pos = (bubble_hw, bubble_pos[1])\n                bubble.arrow_pos = 'bottom_left'\n        elif (bubble_pos[0] + bubble_hw) > win_size[0]:\n            # bubble beyond right of window\n            if bubble_pos[1] > (win_size[1] - bubble_size[1]):\n                # bubble above window height\n                bubble_pos = (win_size[0] - bubble_hw,\n                             (t_pos[1]) - (lh + ls + inch(.25)))\n                bubble.arrow_pos = 'top_right'\n            else:\n                bubble_pos = (win_size[0] - bubble_hw, bubble_pos[1])\n                bubble.arrow_pos = 'bottom_right'\n        else:\n            if bubble_pos[1] > (win_size[1] - bubble_size[1]):\n                # bubble above window height\n                bubble_pos = (bubble_pos[0],\n                             (t_pos[1]) - (lh + ls + inch(.25)))\n                bubble.arrow_pos = 'top_mid'\n            else:\n                bubble.arrow_pos = 'bottom_mid'\n\n        bubble_pos = self.to_widget(*bubble_pos)\n        bubble.center_x = bubble_pos[0]\n        if bubble.arrow_pos[0] == 't':\n            bubble.top = bubble_pos[1]\n        else:\n            bubble.y = bubble_pos[1]\n        bubble.mode = mode\n        Animation.cancel_all(bubble)\n        bubble.opacity = 0\n        win.add_widget(bubble, canvas='after')\n        Animation(opacity=1, d=.225).start(bubble)\n\n    def _hide_cut_copy_paste(self, win=None):\n        bubble = self._bubble\n        if not bubble:\n            return\n\n        bubble.hide()\n\n    #\n    # Private\n    #\n\n    @staticmethod\n    def _reload_remove_observer(wr):\n        # called when the textinput is deleted\n        if wr in _textinput_list:\n            _textinput_list.remove(wr)\n\n    def _on_textinput_focused(self, instance, value, *largs):\n        self.focus = value\n\n        win = EventLoop.window\n        self.cancel_selection()\n        self._hide_cut_copy_paste(win)\n\n        if value:\n            if (not (self.readonly or self.disabled) or _is_desktop and\n                self._keyboard_mode == 'system'):\n                Clock.schedule_interval(self._do_blink_cursor, 1 / 2.)\n                self._editable = True\n            else:\n                self._editable = False\n        else:\n            Clock.unschedule(self._do_blink_cursor)\n            self._hide_handles(win)\n\n    def _ensure_clipboard(self):\n        global Clipboard\n        if not Clipboard:\n            from kivy.core.clipboard import Clipboard\n\n    def cut(self):\n        ''' Copy current selection to clipboard then delete it from TextInput.\n\n        .. versionadded:: 1.8.0\n\n        '''\n        self._cut(self.selection_text)\n\n    def _cut(self, data):\n        self._ensure_clipboard()\n        Clipboard.copy(data)\n        self.delete_selection()\n\n    def copy(self, data=''):\n        ''' Copy the value provided in argument `data` into current clipboard.\n        If data is not of type string it will be converted to string.\n        If no data is provided then current selection if present is copied.\n\n        .. versionadded:: 1.8.0\n\n        '''\n        self._ensure_clipboard()\n        if data:\n            return Clipboard.copy(data)\n        if self.selection_text:\n            return Clipboard.copy(self.selection_text)\n\n    def paste(self):\n        ''' Insert text from system :class:`~kivy.core.clipboard.Clipboard`\n        into the :class:`~kivy.uix.textinput.TextInput` at current cursor\n        position.\n\n        .. versionadded:: 1.8.0\n\n        '''\n        self._ensure_clipboard()\n        data = Clipboard.paste()\n        self.delete_selection()\n        self.insert_text(data)\n\n    def _get_text_width(self, text, tab_width, _label_cached):\n        # Return the width of a text, according to the current line options\n        kw = self._get_line_options()\n\n        try:\n            cid = u'{}\\0{}\\0{}'.format(text, self.password, kw)\n        except UnicodeDecodeError:\n            cid = '{}\\0{}\\0{}'.format(text, self.password, kw)\n\n        width = Cache_get('textinput.width', cid)\n        if width:\n            return width\n        if not _label_cached:\n            _label_cached = self._label_cached\n        text = text.replace('\\t', ' ' * tab_width)\n        if not self.password:\n            width = _label_cached.get_extents(text)[0]\n        else:\n            width = _label_cached.get_extents('*' * len(text))[0]\n        Cache_append('textinput.width', cid, width)\n        return width\n\n    def _do_blink_cursor(self, dt):\n        # Callback called by the timer to blink the cursor, according to the\n        # last activity in the widget\n        b = (Clock.get_time() - self._cursor_blink_time)\n        self.cursor_blink = int(b * 2) % 2\n\n    def on_cursor(self, instance, value):\n        # When the cursor is moved, reset the activity timer, and update all\n        # the graphics.\n        self._cursor_blink_time = Clock.get_time()\n        self._trigger_update_graphics()\n\n    def _delete_line(self, idx):\n        # Delete current line, and fix cursor position\n        assert(idx < len(self._lines))\n        self._lines_flags.pop(idx)\n        self._lines_labels.pop(idx)\n        self._lines.pop(idx)\n        self.cursor = self.cursor\n\n    def _set_line_text(self, line_num, text):\n        # Set current line with other text than the default one.\n        self._lines_labels[line_num] = self._create_line_label(text)\n        self._lines[line_num] = text\n\n    def _trigger_refresh_line_options(self, *largs):\n        Clock.unschedule(self._refresh_line_options)\n        Clock.schedule_once(self._refresh_line_options, 0)\n\n    def _refresh_line_options(self, *largs):\n        self._line_options = None\n        self._get_line_options()\n        self._refresh_text_from_property()\n        self._refresh_hint_text()\n        self.cursor = self.get_cursor_from_index(len(self.text))\n\n    def _trigger_refresh_text(self, *largs):\n        if len(largs) and largs[0] == self:\n            largs = ()\n        Clock.unschedule(lambda dt: self._refresh_text_from_property(*largs))\n        Clock.schedule_once(lambda dt:\n                            self._refresh_text_from_property(*largs))\n\n    def _update_text_options(self, *largs):\n        Cache_remove('textinput.width')\n        self._trigger_refresh_text()\n\n    def _refresh_text_from_trigger(self, dt, *largs):\n        self._refresh_text_from_property(*largs)\n\n    def _refresh_text_from_property(self, *largs):\n        self._refresh_text(self._get_text(encode=False), *largs)\n\n    def _refresh_text(self, text, *largs):\n        # Refresh all the lines from a new text.\n        # By using cache in internal functions, this method should be fast.\n        mode = 'all'\n        if len(largs) > 1:\n            mode, start, finish, _lines, _lines_flags, len_lines = largs\n            #start = max(0, start)\n            cursor = None\n        else:\n            cursor = self.cursor_index()\n            _lines, self._lines_flags = self._split_smart(text)\n        _lines_labels = []\n        _line_rects = []\n        _create_label = self._create_line_label\n\n        for x in _lines:\n            lbl = _create_label(x)\n            _lines_labels.append(lbl)\n            _line_rects.append(Rectangle(size=lbl.size))\n\n        if mode == 'all':\n            self._lines_labels = _lines_labels\n            self._lines_rects = _line_rects\n            self._lines = _lines\n        elif mode == 'del':\n            if finish > start:\n                self._insert_lines(start,\n                                   finish if start == finish else (finish + 1),\n                                   len_lines, _lines_flags,\n                                   _lines, _lines_labels, _line_rects)\n        elif mode == 'insert':\n            self._insert_lines(\n                start,\n                finish if (start == finish and not len_lines)\n                else (finish + 1),\n                len_lines, _lines_flags, _lines, _lines_labels,\n                _line_rects)\n\n        min_line_ht = self._label_cached.get_extents('_')[1]\n        # with markup texture can be of height `1`\n        self.line_height = max(_lines_labels[0].height, min_line_ht)\n        #self.line_spacing = 2\n        # now, if the text change, maybe the cursor is not at the same place as\n        # before. so, try to set the cursor on the good place\n        row = self.cursor_row\n        self.cursor = self.get_cursor_from_index(self.cursor_index()\n                                                 if cursor is None else cursor)\n        # if we back to a new line, reset the scroll, otherwise, the effect is\n        # ugly\n        if self.cursor_row != row:\n            self.scroll_x = 0\n        # with the new text don't forget to update graphics again\n        self._trigger_update_graphics()\n\n    def _insert_lines(self, start, finish, len_lines, _lines_flags,\n                      _lines, _lines_labels, _line_rects):\n            self_lines_flags = self._lines_flags\n            _lins_flags = []\n            _lins_flags.extend(self_lines_flags[:start])\n            if len_lines:\n                # if not inserting at first line then\n                if start:\n                    # make sure line flags restored for first line\n                    # _split_smart assumes first line to be not a new line\n                    _lines_flags[0] = self_lines_flags[start]\n                _lins_flags.extend(_lines_flags)\n            _lins_flags.extend(self_lines_flags[finish:])\n            self._lines_flags = _lins_flags\n\n            _lins_lbls = []\n            _lins_lbls.extend(self._lines_labels[:start])\n            if len_lines:\n                _lins_lbls.extend(_lines_labels)\n            _lins_lbls.extend(self._lines_labels[finish:])\n            self._lines_labels = _lins_lbls\n\n            _lins_rcts = []\n            _lins_rcts.extend(self._lines_rects[:start])\n            if len_lines:\n                _lins_rcts.extend(_line_rects)\n            _lins_rcts.extend(self._lines_rects[finish:])\n            self._lines_rects = _lins_rcts\n\n            _lins = []\n            _lins.extend(self._lines[:start])\n            if len_lines:\n                _lins.extend(_lines)\n            _lins.extend(self._lines[finish:])\n            self._lines = _lins\n\n    def _trigger_update_graphics(self, *largs):\n        Clock.unschedule(self._update_graphics)\n        Clock.schedule_once(self._update_graphics, -1)\n\n    def _update_graphics(self, *largs):\n        # Update all the graphics according to the current internal values.\n        #\n        # This is a little bit complex, cause we have to :\n        #     - handle scroll_x\n        #     - handle padding\n        #     - create rectangle for the lines matching the viewport\n        #     - crop the texture coordinates to match the viewport\n        #\n        # This is the first step of graphics, the second is the selection.\n\n        self.canvas.clear()\n        add = self.canvas.add\n\n        lh = self.line_height\n        dy = lh + self.line_spacing\n\n        # adjust view if the cursor is going outside the bounds\n        sx = self.scroll_x\n        sy = self.scroll_y\n\n        # draw labels\n        if not self.focus and (not self._lines or (\n                not self._lines[0] and len(self._lines) == 1)):\n            rects = self._hint_text_rects\n            labels = self._hint_text_labels\n            lines = self._hint_text_lines\n        else:\n            rects = self._lines_rects\n            labels = self._lines_labels\n            lines = self._lines\n        padding_left, padding_top, padding_right, padding_bottom = self.padding\n        x = self.x + padding_left\n        y = self.top - padding_top + sy\n        miny = self.y + padding_bottom\n        maxy = self.top - padding_top\n        for line_num, value in enumerate(lines):\n            if miny <= y <= maxy + dy:\n                texture = labels[line_num]\n                size = list(texture.size)\n                texc = texture.tex_coords[:]\n\n                # calcul coordinate\n                viewport_pos = sx, 0\n                vw = self.width - padding_left - padding_right\n                vh = self.height - padding_top - padding_bottom\n                tw, th = list(map(float, size))\n                oh, ow = tch, tcw = texc[1:3]\n                tcx, tcy = 0, 0\n\n                # adjust size/texcoord according to viewport\n                if viewport_pos:\n                    tcx, tcy = viewport_pos\n                    tcx = tcx / tw * (ow)\n                    tcy = tcy / th * oh\n                if tw - viewport_pos[0] < vw:\n                    tcw = tcw - tcx\n                    size[0] = tcw * size[0]\n                elif vw < tw:\n                    tcw = (vw / tw) * tcw\n                    size[0] = vw\n                if vh < th:\n                    tch = (vh / th) * tch\n                    size[1] = vh\n\n                # cropping\n                mlh = lh\n                if y > maxy:\n                    vh = (maxy - y + lh)\n                    tch = (vh / float(lh)) * oh\n                    tcy = oh - tch\n                    size[1] = vh\n                if y - lh < miny:\n                    diff = miny - (y - lh)\n                    y += diff\n                    vh = lh - diff\n                    tch = (vh / float(lh)) * oh\n                    size[1] = vh\n\n                texc = (\n                    tcx,\n                    tcy + tch,\n                    tcx + tcw,\n                    tcy + tch,\n                    tcx + tcw,\n                    tcy,\n                    tcx,\n                    tcy)\n\n                # add rectangle.\n                r = rects[line_num]\n                r.pos = int(x), int(y - mlh)\n                r.size = size\n                r.texture = texture\n                r.tex_coords = texc\n                add(r)\n\n            y -= dy\n\n        self._update_graphics_selection()\n\n    def _update_graphics_selection(self):\n        if not self._selection:\n            return\n        self.canvas.remove_group('selection')\n        dy = self.line_height + self.line_spacing\n        rects = self._lines_rects\n        padding_top = self.padding[1]\n        padding_bottom = self.padding[3]\n        _top = self.top\n        y = _top - padding_top + self.scroll_y\n        miny = self.y + padding_bottom\n        maxy = _top - padding_top\n        draw_selection = self._draw_selection\n        a, b = self._selection_from, self._selection_to\n        if a > b:\n            a, b = b, a\n        get_cursor_from_index = self.get_cursor_from_index\n        s1c, s1r = get_cursor_from_index(a)\n        s2c, s2r = get_cursor_from_index(b)\n        s2r += 1\n        # pass only the selection lines[]\n        # passing all the lines can get slow when dealing with a lot of text\n        y -= s1r * dy\n        _lines = self._lines\n        _get_text_width = self._get_text_width\n        tab_width = self.tab_width\n        _label_cached = self._label_cached\n        width = self.width\n        padding_left = self.padding[0]\n        padding_right = self.padding[2]\n        x = self.x\n        canvas_add = self.canvas.add\n        selection_color = self.selection_color\n        for line_num, value in enumerate(_lines[s1r:s2r], start=s1r):\n            if miny <= y <= maxy + dy:\n                r = rects[line_num]\n                draw_selection(r.pos, r.size, line_num, (s1c, s1r),\n                               (s2c, s2r - 1), _lines, _get_text_width,\n                               tab_width, _label_cached, width,\n                               padding_left, padding_right, x,\n                               canvas_add, selection_color)\n            y -= dy\n        self._position_handles('both')\n\n    def _draw_selection(self, *largs):\n        pos, size, line_num, (s1c, s1r), (s2c, s2r),\\\n            _lines, _get_text_width, tab_width, _label_cached, width,\\\n            padding_left, padding_right, x, canvas_add, selection_color = largs\n        # Draw the current selection on the widget.\n        if line_num < s1r or line_num > s2r:\n            return\n        x, y = pos\n        w, h = size\n        x1 = x\n        x2 = x + w\n        if line_num == s1r:\n            lines = _lines[line_num]\n            x1 -= self.scroll_x\n            x1 += _get_text_width(lines[:s1c], tab_width, _label_cached)\n        if line_num == s2r:\n            lines = _lines[line_num]\n            x2 = (x - self.scroll_x) + _get_text_width(lines[:s2c],\n                                                       tab_width,\n                                                       _label_cached)\n        width_minus_padding = width - (padding_right + padding_left)\n        maxx = x + width_minus_padding\n        if x1 > maxx:\n            return\n        x1 = max(x1, x)\n        x2 = min(x2, x + width_minus_padding)\n        canvas_add(Color(*selection_color, group='selection'))\n        canvas_add(Rectangle(\n            pos=(x1, pos[1]), size=(x2 - x1, size[1]), group='selection'))\n\n    def on_size(self, instance, value):\n        # if the size change, we might do invalid scrolling / text split\n        # size the text maybe be put after size_hint have been resolved.\n        self._trigger_refresh_text()\n        self._refresh_hint_text()\n        self.scroll_x = self.scroll_y = 0\n\n    def _get_cursor_pos(self):\n        # return the current cursor x/y from the row/col\n        dy = self.line_height + self.line_spacing\n        padding_left = self.padding[0]\n        padding_top = self.padding[1]\n        left = self.x + padding_left\n        top = self.top - padding_top\n        y = top + self.scroll_y\n        y -= self.cursor_row * dy\n        x, y = left + self.cursor_offset() - self.scroll_x, y\n        if x < left:\n            self.scroll_x = 0\n            x = left\n        if y > top:\n            y = top\n            self.scroll_y = 0\n        return x, y\n\n    def _get_line_options(self):\n        # Get or create line options, to be used for Label creation\n        if self._line_options is None:\n            self._line_options = kw = {\n                'font_size': self.font_size,\n                'font_name': self.font_name,\n                'anchor_x': 'left',\n                'anchor_y': 'top',\n                'padding_x': 0,\n                'padding_y': 0,\n                'padding': (0, 0)}\n            self._label_cached = Label(**kw)\n        return self._line_options\n\n    def _create_line_label(self, text, hint=False):\n        # Create a label from a text, using line options\n        ntext = text.replace(u'\\n', u'').replace(u'\\t', u' ' * self.tab_width)\n        if self.password and not hint:  # Don't replace hint_text with *\n            ntext = u'*' * len(ntext)\n        kw = self._get_line_options()\n        cid = '%s\\0%s' % (ntext, str(kw))\n        texture = Cache_get('textinput.label', cid)\n\n        if texture is None:\n            # FIXME right now, we can't render very long line...\n            # if we move on \"VBO\" version as fallback, we won't need to\n            # do this. try to found the maximum text we can handle\n            label = None\n            label_len = len(ntext)\n            ld = None\n\n            # check for blank line\n            if not ntext:\n                texture = Texture.create(size=(1, 1))\n                Cache_append('textinput.label', cid, texture)\n                return texture\n\n            while True:\n                try:\n                    label = Label(text=ntext[:label_len], **kw)\n                    label.refresh()\n                    if ld is not None and ld > 2:\n                        ld = int(ld / 2)\n                        label_len += ld\n                    else:\n                        break\n                except:\n                    # exception happen when we tried to render the text\n                    # reduce it...\n                    if ld is None:\n                        ld = len(ntext)\n                    ld = int(ld / 2)\n                    if ld < 2 and label_len:\n                        label_len -= 1\n                    label_len -= ld\n                    continue\n\n            # ok, we found it.\n            texture = label.texture\n            Cache_append('textinput.label', cid, texture)\n        return texture\n\n    def _tokenize(self, text):\n        # Tokenize a text string from some delimiters\n        if text is None:\n            return\n        delimiters = u' ,\\'\".;:\\n\\r\\t'\n        oldindex = 0\n        for index, char in enumerate(text):\n            if char not in delimiters:\n                continue\n            if oldindex != index:\n                yield text[oldindex:index]\n            yield text[index:index + 1]\n            oldindex = index + 1\n        yield text[oldindex:]\n\n    def _split_smart(self, text):\n        # Do a \"smart\" split. If autowidth or autosize is set,\n        # we are not doing smart split, just a split on line break.\n        # Otherwise, we are trying to split as soon as possible, to prevent\n        # overflow on the widget.\n\n        # depend of the options, split the text on line, or word\n        if not self.multiline:\n            lines = text.split(u'\\n')\n            lines_flags = [0] + [FL_IS_NEWLINE] * (len(lines) - 1)\n            return lines, lines_flags\n\n        # no autosize, do wordwrap.\n        x = flags = 0\n        line = []\n        lines = []\n        lines_flags = []\n        _join = u''.join\n        lines_append, lines_flags_append = lines.append, lines_flags.append\n        padding_left = self.padding[0]\n        padding_right = self.padding[2]\n        width = self.width - padding_left - padding_right\n        text_width = self._get_text_width\n        _tab_width, _label_cached = self.tab_width, self._label_cached\n\n        # try to add each word on current line.\n        for word in self._tokenize(text):\n            is_newline = (word == u'\\n')\n            w = text_width(word, _tab_width, _label_cached)\n            # if we have more than the width, or if it's a newline,\n            # push the current line, and create a new one\n            if (x + w > width and line) or is_newline:\n                lines_append(_join(line))\n                lines_flags_append(flags)\n                flags = 0\n                line = []\n                x = 0\n            if is_newline:\n                flags |= FL_IS_NEWLINE\n            else:\n                x += w\n                line.append(word)\n        if line or flags & FL_IS_NEWLINE:\n            lines_append(_join(line))\n            lines_flags_append(flags)\n\n        return lines, lines_flags\n\n    def _key_down(self, key, repeat=False):\n        displayed_str, internal_str, internal_action, scale = key\n        if internal_action is None:\n            if self._selection:\n                self.delete_selection()\n            self.insert_text(displayed_str)\n        elif internal_action in ('shift', 'shift_L', 'shift_R'):\n            if not self._selection:\n                self._selection_from = self._selection_to = self.cursor_index()\n                self._selection = True\n            self._selection_finished = False\n        elif internal_action.startswith('cursor_'):\n            cc, cr = self.cursor\n            self.do_cursor_movement(internal_action)\n            if self._selection and not self._selection_finished:\n                self._selection_to = self.cursor_index()\n                self._update_selection()\n            else:\n                self.cancel_selection()\n        elif self._selection and internal_action in ('del', 'backspace'):\n            self.delete_selection()\n        elif internal_action == 'del':\n            # Move cursor one char to the right. If that was successful,\n            # do a backspace (effectively deleting char right of cursor)\n            cursor = self.cursor\n            self.do_cursor_movement('cursor_right')\n            if cursor != self.cursor:\n                self.do_backspace(mode='del')\n        elif internal_action == 'backspace':\n            self.do_backspace()\n        elif internal_action == 'enter':\n            if self.multiline:\n                self.insert_text(u'\\n')\n            else:\n                self.dispatch('on_text_validate')\n                self.focus = False\n        elif internal_action == 'escape':\n            self.focus = False\n        if internal_action != 'escape':\n            #self._recalc_size()\n            pass\n\n    def _key_up(self, key, repeat=False):\n        displayed_str, internal_str, internal_action, scale = key\n        if internal_action in ('shift', 'shift_L', 'shift_R'):\n            if self._selection:\n                self._update_selection(True)\n\n    def keyboard_on_key_down(self, window, keycode, text, modifiers):\n        # Keycodes on OSX:\n        ctrl, cmd = 64, 1024\n        key, key_str = keycode\n        win = EventLoop.window\n\n        # This allows *either* ctrl *or* cmd, but not both.\n        is_shortcut = (modifiers == ['ctrl'] or (\n            _is_osx and modifiers == ['meta']))\n        is_interesting_key = key in (list(self.interesting_keys.keys()) + [27])\n\n        if not self.write_tab and super(TextInput,\n            self).keyboard_on_key_down(window, keycode, text, modifiers):\n            return True\n\n        if not self._editable:\n            # duplicated but faster testing for non-editable keys\n            if text and not is_interesting_key:\n                if is_shortcut and key == ord('c'):\n                    self.copy()\n            elif key == 27:\n                self.focus = False\n            return True\n\n        if text and not is_interesting_key:\n\n            self._hide_handles(win)\n            self._hide_cut_copy_paste(win)\n            win.remove_widget(self._handle_middle)\n\n            # check for command modes\n            # we use \\x01INFO\\x02 to get info from IME on mobiles\n            # pygame seems to pass \\x01 as the unicode for ctrl+a\n            # checking for modifiers ensures conflict resolution.\n\n            first_char = ord(text[0])\n            if not modifiers and first_char == 1:\n                self._command_mode = True\n                self._command = ''\n            if not modifiers and first_char == 2:\n                self._command_mode = False\n                self._command = self._command[1:]\n\n            if self._command_mode:\n                self._command += text\n                return\n\n            _command = self._command\n            if _command and first_char == 2:\n                from_undo = True\n                _command, data = _command.split(':')\n                self._command = ''\n                if self._selection:\n                    self.delete_selection()\n                if _command == 'DEL':\n                    count = int(data)\n                    if not count:\n                        self.delete_selection(from_undo=True)\n                    end = self.cursor_index()\n                    self._selection_from = max(end - count, 0)\n                    self._selection_to = end\n                    self._selection = True\n                    self.delete_selection(from_undo=True)\n                    return\n                elif _command == 'INSERT':\n                    self.insert_text(data, from_undo)\n                elif _command == 'INSERTN':\n                    from_undo = False\n                    self.insert_text(data, from_undo)\n                elif _command == 'SELWORD':\n                    self.dispatch('on_double_tap')\n                elif _command == 'SEL':\n                    if data == '0':\n                        Clock.schedule_once(lambda dt: self.cancel_selection())\n                elif _command == 'CURCOL':\n                    self.cursor = int(data), self.cursor_row\n                return\n\n            if is_shortcut:\n                if key == ord('x'):  # cut selection\n                    self._cut(self.selection_text)\n                elif key == ord('c'):  # copy selection\n                    self.copy()\n                elif key == ord('v'):  # paste selection\n                    self.paste()\n                elif key == ord('a'):  # select all\n                    self.select_all()\n                elif key == ord('z'):  # undo\n                    self.do_undo()\n                elif key == ord('r'):  # redo\n                    self.do_redo()\n            else:\n                if EventLoop.window.__class__.__module__ == \\\n                    'kivy.core.window.window_sdl2':\n                    return\n                if self._selection:\n                    self.delete_selection()\n                self.insert_text(text)\n            #self._recalc_size()\n            return\n\n        if is_interesting_key:\n            self._hide_cut_copy_paste(win)\n            self._hide_handles(win)\n\n        if key == 27:  # escape\n            self.focus = False\n            return True\n        elif key == 9:  # tab\n            self.insert_text(u'\\t')\n            return True\n\n        k = self.interesting_keys.get(key)\n        if k:\n            key = (None, None, k, 1)\n            self._key_down(key)\n\n    def keyboard_on_key_up(self, window, keycode):\n        key, key_str = keycode\n        k = self.interesting_keys.get(key)\n        if k:\n            key = (None, None, k, 1)\n            self._key_up(key)\n\n    def keyboard_on_textinput(self, window, text):\n        if self._selection:\n            self.delete_selection()\n        self.insert_text(text, False)\n\n    def on_hint_text(self, instance, value):\n        self._refresh_hint_text()\n\n    def _refresh_hint_text(self):\n        _lines, self._hint_text_flags = self._split_smart(self.hint_text)\n        _hint_text_labels = []\n        _hint_text_rects = []\n        _create_label = self._create_line_label\n\n        for x in _lines:\n            lbl = _create_label(x, hint=True)\n            _hint_text_labels.append(lbl)\n            _hint_text_rects.append(Rectangle(size=lbl.size))\n\n        self._hint_text_lines = _lines\n        self._hint_text_labels = _hint_text_labels\n        self._hint_text_rects = _hint_text_rects\n\n        # Remember to update graphics\n        self._trigger_update_graphics()\n\n    #\n    # Properties\n    #\n\n    _lines = ListProperty([])\n    _hint_text_lines = ListProperty([])\n    _editable = BooleanProperty(True)\n    _insert_int_patu = re.compile(u'[^0-9]')\n    _insert_int_patb = re.compile(b'[^0-9]')\n\n    readonly = BooleanProperty(False)\n    '''If True, the user will not be able to change the content of a textinput.\n\n    .. versionadded:: 1.3.0\n\n    :attr:`readonly` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    multiline = BooleanProperty(True)\n    '''If True, the widget will be able show multiple lines of text. If False,\n    the \"enter\" keypress will defocus the textinput instead of adding a new\n    line.\n\n    :attr:`multiline` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n\n    password = BooleanProperty(False)\n    '''If True, the widget will display its characters as the character '*'.\n\n    .. versionadded:: 1.2.0\n\n    :attr:`password` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    keyboard_suggestions = BooleanProperty(True)\n    '''If True provides auto suggestions on top of keyboard.\n    This will only work if :attr:`input_type` is set to `text`.\n\n     .. versionadded:: 1.8.0\n\n     :attr:`keyboard_suggestions` is a\n     :class:`~kivy.properties.BooleanProperty` defaults to True.\n    '''\n\n    cursor_blink = BooleanProperty(False)\n    '''This property is used to blink the cursor graphic. The value of\n    :attr:`cursor_blink` is automatically computed. Setting a value on it will\n    have no impact.\n\n    :attr:`cursor_blink` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    def _get_cursor(self):\n        return self._cursor\n\n    def _set_cursor(self, pos):\n        if not self._lines:\n            self._trigger_refresh_text()\n            return\n        l = self._lines\n        cr = boundary(pos[1], 0, len(l) - 1)\n        cc = boundary(pos[0], 0, len(l[cr]))\n        cursor = cc, cr\n        if self._cursor == cursor:\n            return\n\n        self._cursor = cursor\n\n        # adjust scrollview to ensure that the cursor will be always inside our\n        # viewport.\n        padding_left = self.padding[0]\n        padding_right = self.padding[2]\n        viewport_width = self.width - padding_left - padding_right\n        sx = self.scroll_x\n        offset = self.cursor_offset()\n\n        # if offset is outside the current bounds, reajust\n        if offset > viewport_width + sx:\n            self.scroll_x = offset - viewport_width\n        if offset < sx:\n            self.scroll_x = offset\n\n        # do the same for Y\n        # this algo try to center the cursor as much as possible\n        dy = self.line_height + self.line_spacing\n        offsety = cr * dy\n        sy = self.scroll_y\n        padding_top = self.padding[1]\n        padding_bottom = self.padding[3]\n        viewport_height = self.height - padding_top - padding_bottom - dy\n        if offsety > viewport_height + sy:\n            sy = offsety - viewport_height\n        if offsety < sy:\n            sy = offsety\n        self.scroll_y = sy\n\n        return True\n\n    cursor = AliasProperty(_get_cursor, _set_cursor)\n    '''Tuple of (row, col) values indicating the current cursor position.\n    You can set a new (row, col) if you want to move the cursor. The scrolling\n    area will be automatically updated to ensure that the cursor is\n    visible inside the viewport.\n\n    :attr:`cursor` is an :class:`~kivy.properties.AliasProperty`.\n    '''\n\n    def _get_cursor_col(self):\n        return self._cursor[0]\n\n    cursor_col = AliasProperty(_get_cursor_col, None, bind=('cursor', ))\n    '''Current column of the cursor.\n\n    :attr:`cursor_col` is an :class:`~kivy.properties.AliasProperty` to\n    cursor[0], read-only.\n    '''\n\n    def _get_cursor_row(self):\n        return self._cursor[1]\n\n    cursor_row = AliasProperty(_get_cursor_row, None, bind=('cursor', ))\n    '''Current row of the cursor.\n\n    :attr:`cursor_row` is an :class:`~kivy.properties.AliasProperty` to\n    cursor[1], read-only.\n    '''\n\n    cursor_pos = AliasProperty(_get_cursor_pos, None, bind=(\n        'cursor', 'padding', 'pos', 'size', 'focus',\n        'scroll_x', 'scroll_y'))\n    '''Current position of the cursor, in (x, y).\n\n    :attr:`cursor_pos` is an :class:`~kivy.properties.AliasProperty`,\n    read-only.\n    '''\n\n    cursor_color = ListProperty([1, 0, 0, 1])\n    '''Current color of the cursor, in (r, g, b, a) format.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`cursor_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [1, 0, 0, 1].\n    '''\n\n    line_height = NumericProperty(1)\n    '''Height of a line. This property is automatically computed from the\n    :attr:`font_name`, :attr:`font_size`. Changing the line_height will have\n    no impact.\n\n    .. note::\n\n        :attr:`line_height` is the height of a single line of text.\n        Use :attr:`minimum_height`, which also includes padding, to\n        get the height required to display the text properly.\n\n    :attr:`line_height` is a :class:`~kivy.properties.NumericProperty`,\n    read-only.\n    '''\n\n    tab_width = NumericProperty(4)\n    '''By default, each tab will be replaced by four spaces on the text\n    input widget. You can set a lower or higher value.\n\n    :attr:`tab_width` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 4.\n    '''\n\n    padding_x = VariableListProperty([0, 0], length=2)\n    '''Horizontal padding of the text: [padding_left, padding_right].\n\n    padding_x also accepts a one argument form [padding_horizontal].\n\n    :attr:`padding_x` is a :class:`~kivy.properties.VariableListProperty` and\n    defaults to [0, 0]. This might be changed by the current theme.\n\n    .. deprecated:: 1.7.0\n        Use :attr:`padding` instead.\n    '''\n\n    def on_padding_x(self, instance, value):\n        self.padding[0] = value[0]\n        self.padding[2] = value[1]\n\n    padding_y = VariableListProperty([0, 0], length=2)\n    '''Vertical padding of the text: [padding_top, padding_bottom].\n\n    padding_y also accepts a one argument form [padding_vertical].\n\n    :attr:`padding_y` is a :class:`~kivy.properties.VariableListProperty` and\n    defaults to [0, 0]. This might be changed by the current theme.\n\n    .. deprecated:: 1.7.0\n        Use :attr:`padding` instead.\n    '''\n\n    def on_padding_y(self, instance, value):\n        self.padding[1] = value[0]\n        self.padding[3] = value[1]\n\n    padding = VariableListProperty([6, 6, 6, 6])\n    '''Padding of the text: [padding_left, padding_top, padding_right,\n    padding_bottom].\n\n    padding also accepts a two argument form [padding_horizontal,\n    padding_vertical] and a one argument form [padding].\n\n    .. versionchanged:: 1.7.0\n        Replaced AliasProperty with VariableListProperty.\n\n    :attr:`padding` is a :class:`~kivy.properties.VariableListProperty` and\n    defaults to [6, 6, 6, 6].\n    '''\n\n    scroll_x = NumericProperty(0)\n    '''X scrolling value of the viewport. The scrolling is automatically\n    updated when the cursor is moved or text changed. If there is no\n    user input, the scroll_x and scroll_y properties may be changed.\n\n    :attr:`scroll_x` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    scroll_y = NumericProperty(0)\n    '''Y scrolling value of the viewport. See :attr:`scroll_x` for more\n    information.\n\n    :attr:`scroll_y` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    selection_color = ListProperty([0.1843, 0.6549, 0.8313, .5])\n    '''Current color of the selection, in (r, g, b, a) format.\n\n    .. warning::\n\n        The color should always have an \"alpha\" component less than 1\n        since the selection is drawn after the text.\n\n    :attr:`selection_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [0.1843, 0.6549, 0.8313, .5].\n    '''\n\n    border = ListProperty([4, 4, 4, 4])\n    '''Border used for :class:`~kivy.graphics.vertex_instructions.BorderImage`\n    graphics instruction. Used with :attr:`background_normal` and\n    :attr:`background_active`. Can be used for a custom background.\n\n    .. versionadded:: 1.4.1\n\n    It must be a list of four values: (top, right, bottom, left). Read the\n    BorderImage instruction for more information about how to use it.\n\n    :attr:`border` is a :class:`~kivy.properties.ListProperty` and defaults\n    to (4, 4, 4, 4).\n    '''\n\n    background_normal = StringProperty(\n        'atlas://data/images/defaulttheme/textinput')\n    '''Background image of the TextInput when it's not in focus.\n\n    .. versionadded:: 1.4.1\n\n    :attr:`background_normal` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/textinput'.\n    '''\n\n    background_disabled_normal = StringProperty(\n        'atlas://data/images/defaulttheme/textinput_disabled')\n    '''Background image of the TextInput when disabled.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`background_disabled_normal` is a\n    :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/textinput_disabled'.\n    '''\n\n    background_active = StringProperty(\n        'atlas://data/images/defaulttheme/textinput_active')\n    '''Background image of the TextInput when it's in focus.\n\n    .. versionadded:: 1.4.1\n\n    :attr:`background_active` is a\n    :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/textinput_active'.\n    '''\n\n    background_disabled_active = StringProperty(\n        'atlas://data/images/defaulttheme/textinput_disabled_active')\n    '''Background image of the TextInput when it's in focus and disabled.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`background_disabled_active` is a\n    :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/textinput_disabled_active'.\n    '''\n\n    background_color = ListProperty([1, 1, 1, 1])\n    '''Current color of the background, in (r, g, b, a) format.\n\n    .. versionadded:: 1.2.0\n\n    :attr:`background_color` is a :class:`~kivy.properties.ListProperty`\n    and defaults to [1, 1, 1, 1] (white).\n    '''\n\n    foreground_color = ListProperty([0, 0, 0, 1])\n    '''Current color of the foreground, in (r, g, b, a) format.\n\n    .. versionadded:: 1.2.0\n\n    :attr:`foreground_color` is a :class:`~kivy.properties.ListProperty`\n    and defaults to [0, 0, 0, 1] (black).\n    '''\n\n    disabled_foreground_color = ListProperty([0, 0, 0, .5])\n    '''Current color of the foreground when disabled, in (r, g, b, a) format.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`disabled_foreground_color` is a\n    :class:`~kivy.properties.ListProperty` and\n    defaults to [0, 0, 0, 5] (50% transparent black).\n    '''\n\n    use_bubble = BooleanProperty(not _is_desktop)\n    '''Indicates whether the cut/copy/paste bubble is used.\n\n    .. versionadded:: 1.7.0\n\n    :attr:`use_bubble` is a :class:`~kivy.properties.BooleanProperty`\n    and defaults to True on mobile OS's, False on desktop OS's.\n    '''\n\n    use_handles = BooleanProperty(not _is_desktop)\n    '''Indicates whether the selection handles are displayed.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`use_handles` is a :class:`~kivy.properties.BooleanProperty`\n    and defaults to True on mobile OS's, False on desktop OS's.\n    '''\n\n    suggestion_text = StringProperty('')\n    '''Shows a suggestion text/word from currentcursor position onwards,\n    that can be used as a possible completion. Usefull for suggesting completion\n    text. This can also be used by the IME to setup the current word being\n    edited\n\n    ..versionadded:: 1.9.0\n\n    :attr:`suggestion_text` is a :class:`~kivy.properties.StringProperty`\n    defaults to `''`\n    '''\n\n    def on_suggestion_text(self, instance, value):\n        global MarkupLabel\n        if not MarkupLabel:\n            from kivy.core.text.markup import MarkupLabel\n\n        cursor_pos = self.cursor_pos\n        txt = self._lines[self.cursor_row]\n        cr = self.cursor_row\n        kw = self._get_line_options()\n        rct = self._lines_rects[cr]\n\n        lbl = text = None\n        if value:\n            lbl = MarkupLabel(\n                text=txt + \"[b]{}[/b]\".format(value), **kw)\n        else:\n            lbl = Label(**kw)\n            text = txt\n\n        lbl.refresh()\n\n        self._lines_labels[cr] = lbl.texture\n        rct.size = lbl.size\n        self._update_graphics()\n\n    def get_sel_from(self):\n        return self._selection_from\n\n    selection_from = AliasProperty(get_sel_from, None)\n    '''If a selection is in progress or complete, this property will represent\n    the cursor index where the selection started.\n\n    .. versionchanged:: 1.4.0\n        :attr:`selection_from` is an :class:`~kivy.properties.AliasProperty`\n        and defaults to None, readonly.\n    '''\n\n    def get_sel_to(self):\n        return self._selection_to\n\n    selection_to = AliasProperty(get_sel_to, None)\n    '''If a selection is in progress or complete, this property will represent\n    the cursor index where the selection started.\n\n    .. versionchanged:: 1.4.0\n        :attr:`selection_to` is an :class:`~kivy.properties.AliasProperty` and\n        defaults to None, readonly.\n    '''\n\n    selection_text = StringProperty(u'')\n    '''Current content selection.\n\n    :attr:`selection_text` is a :class:`~kivy.properties.StringProperty`\n    and defaults to '', readonly.\n    '''\n\n    def on_selection_text(self, instance, value):\n        if value and self.use_handles:\n            self._trigger_show_handles()\n\n    def _get_text(self, encode=True):\n        lf = self._lines_flags\n        l = self._lines\n        len_l = len(l)\n\n        if len(lf) < len_l:\n            lf.append(1)\n\n        text = u''.join([(u'\\n' if (lf[i] & FL_IS_NEWLINE) else u'') + l[i]\n                        for i in range(len_l)])\n\n        if PY2 and encode and type(text) is not str:\n            text = text.encode('utf-8')\n        return text\n\n    def _set_text(self, text):\n        if PY2 and type(text) is str:\n            text = text.decode('utf-8')\n\n        if self._get_text(encode=False) == text:\n            return\n\n        self._refresh_text(text)\n        self.cursor = self.get_cursor_from_index(len(text))\n\n    text = AliasProperty(_get_text, _set_text, bind=('_lines', ))\n    '''Text of the widget.\n\n    Creation of a simple hello world::\n\n        widget = TextInput(text='Hello world')\n\n    If you want to create the widget with an unicode string, use::\n\n        widget = TextInput(text=u'My unicode string')\n\n    :attr:`text` a :class:`~kivy.properties.StringProperty`.\n    '''\n\n    font_name = StringProperty('DroidSans')\n    '''Filename of the font to use. The path can be absolute or relative.\n    Relative paths are resolved by the :func:`~kivy.resources.resource_find`\n    function.\n\n    .. warning::\n\n        Depending on your text provider, the font file may be ignored. However,\n        you can mostly use this without problems.\n\n        If the font used lacks the glyphs for the particular language/symbols\n        you are using, you will see '[]' blank box characters instead of the\n        actual glyphs. The solution is to use a font that has the glyphs you\n        need to display. For example, to display |unicodechar|, use a font like\n        freesans.ttf that has the glyph.\n\n        .. |unicodechar| image:: images/unicode-char.png\n\n    :attr:`font_name` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'DroidSans'.\n    '''\n\n    font_size = NumericProperty('15sp')\n    '''Font size of the text in pixels.\n\n    :attr:`font_size` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 10.\n    '''\n\n    hint_text = StringProperty('')\n    '''Hint text of the widget.\n\n    Shown if text is '' and focus is False.\n\n    .. versionadded:: 1.6.0\n\n    :attr:`hint_text` a :class:`~kivy.properties.StringProperty` and defaults\n    to ''.\n    '''\n\n    hint_text_color = ListProperty([0.5, 0.5, 0.5, 1.0])\n    '''Current color of the hint_text text, in (r, g, b, a) format.\n\n    .. versionadded:: 1.6.0\n\n    :attr:`hint_text_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [0.5, 0.5, 0.5, 1.0] (grey).\n    '''\n\n    auto_indent = BooleanProperty(False)\n    '''Automatically indent multiline text.\n\n    .. versionadded:: 1.7.0\n\n    :attr:`auto_indent` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    allow_copy = BooleanProperty(True)\n    '''Decides whether to allow copying the text.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`allow_copy` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to True.\n    '''\n\n    def _get_min_height(self):\n        return (len(self._lines) * (self.line_height + self.line_spacing)\n                + self.padding[1] + self.padding[3])\n\n    minimum_height = AliasProperty(_get_min_height, None,\n                                   bind=('_lines', 'line_spacing', 'padding',\n                                         'font_size', 'font_name', 'password',\n                                         'hint_text', 'line_height'))\n    '''Minimum height of the content inside the TextInput.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`minimum_height` is a readonly\n    :class:`~kivy.properties.AliasProperty`.\n    '''\n\n    line_spacing = NumericProperty(0)\n    '''Space taken up between the lines.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`line_spacing` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    input_filter = ObjectProperty(None, allownone=True)\n    ''' Filters the input according to the specified mode, if not None. If\n    None, no filtering is applied.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`input_filter` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to `None`. Can be one of `None`, `'int'` (string), or `'float'`\n    (string), or a callable. If it is `'int'`, it will only accept numbers.\n    If it is `'float'` it will also accept a single period. Finally, if it is\n    a callable it will be called with two parameter; the string to be added\n    and a bool indicating whether the string is a result of undo (True). The\n    callable should return a new substring that will be used instead.\n    '''\n\n    handle_image_middle = StringProperty(\n        'atlas://data/images/defaulttheme/selector_middle')\n    '''Image used to display the middle handle on the TextInput for cursor\n    positioning.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`handle_image_middle` is a :class:`~kivy.properties.StringProperty`\n    and defaults to 'atlas://data/images/defaulttheme/selector_middle'.\n    '''\n\n    def on_handle_image_middle(self, instance, value):\n        if self._handle_middle:\n            self._handle_middle.source = value\n\n    handle_image_left = StringProperty(\n        'atlas://data/images/defaulttheme/selector_left')\n    '''Image used to display the Left handle on the TextInput for selection.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`handle_image_left` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/selector_left'.\n    '''\n\n    def on_handle_image_left(self, instance, value):\n        if self._handle_left:\n            self._handle_left.source = value\n\n    handle_image_right = StringProperty(\n        'atlas://data/images/defaulttheme/selector_right')\n    '''Image used to display the Right handle on the TextInput for selection.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`handle_image_right` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    'atlas://data/images/defaulttheme/selector_right'.\n    '''\n\n    def on_handle_image_right(self, instance, value):\n        if self._handle_right:\n            self._handle_right.source = value\n\n    write_tab = BooleanProperty(True)\n    '''Whether the tab key should move focus to the next widget or if it should\n    enter a tab in the :class:`TextInput`. If `True` a tab will be written,\n    otherwise, focus will move to the next widget.\n\n    .. versionadded:: 1.9.0\n\n    :attr:`write_tab` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to `True`.\n    '''\n\n\nif __name__ == '__main__':\n    from kivy.app import App\n    from kivy.uix.boxlayout import BoxLayout\n    from kivy.lang import Builder\n\n    class TextInputApp(App):\n\n        def build(self):\n\n            Builder.load_string('''\n<TextInput>\n    on_text:\n        self.suggestion_text = ''\n        self.suggestion_text = 'ion_text'\n\n''')\n            root = BoxLayout(orientation='vertical')\n            textinput = TextInput(multiline=True, use_bubble=True,\n                                  use_handles=True)\n            #textinput.text = __doc__\n            root.add_widget(textinput)\n            textinput2 = TextInput(multiline=False, text='monoline textinput',\n                                   size_hint=(1, None), height=30)\n            root.add_widget(textinput2)\n            return root\n\n    TextInputApp().run()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/togglebutton.py",
    "content": "'''\nToggle button\n=============\n\nThe :class:`ToggleButton` widget acts like a checkbox. When you touch/click it,\nthe state toggles between 'normal' and 'down' (as opposed to a :class:`Button`\nthat is only 'down' as long as it is pressed).\n\nToggle buttons can also be grouped to make radio buttons - only one button in\na group can be in a 'down' state. The group name can be a string or any other\nhashable Python object::\n\n    btn1 = ToggleButton(text='Male', group='sex',)\n    btn2 = ToggleButton(text='Female', group='sex', state='down')\n    btn3 = ToggleButton(text='Mixed', group='sex')\n\nOnly one of the buttons can be 'down'/checked at the same time.\n\nTo configure the ToggleButton, you can use the same properties that you can use\nfor a :class:`~kivy.uix.button.Button` class.\n\n'''\n\n__all__ = ('ToggleButton', )\n\nfrom kivy.uix.button import Button\nfrom kivy.uix.behaviors import ToggleButtonBehavior\n\n\nclass ToggleButton(ToggleButtonBehavior, Button):\n    '''Toggle button class, see module documentation for more information.\n    '''\n\n    pass\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/treeview.py",
    "content": "'''\nTree View\n=========\n\n.. versionadded:: 1.0.4\n\n\n:class:`TreeView` is a widget used to represent a tree structure. It is\ncurrently very basic, supporting a minimal feature set.\n\nIntroduction\n------------\n\nA :class:`TreeView` is populated with :class:`TreeViewNode` instances, but you\ncannot use a :class:`TreeViewNode` directly. You must combine it with another\nwidget, such as :class:`~kivy.uix.label.Label`,\n:class:`~kivy.uix.button.Button` or even your own widget. The TreeView\nalways creates a default root node, based on :class:`TreeViewLabel`.\n\n:class:`TreeViewNode` is a class object containing needed properties for\nserving as a tree node. Extend :class:`TreeViewNode` to create custom node\ntypes for use with a :class:`TreeView`.\n\nFor constructing your own subclass, follow the pattern of TreeViewLabel which\ncombines a Label and a TreeViewNode, producing a :class:`TreeViewLabel` for\ndirect use in a TreeView instance.\n\nTo use the TreeViewLabel class, you could create two nodes directly attached\nto root::\n\n    tv = TreeView()\n    tv.add_node(TreeViewLabel(text='My first item'))\n    tv.add_node(TreeViewLabel(text='My second item'))\n\nOr, create two nodes attached to a first::\n\n    tv = TreeView()\n    n1 = tv.add_node(TreeViewLabel(text='Item 1'))\n    tv.add_node(TreeViewLabel(text='SubItem 1'), n1)\n    tv.add_node(TreeViewLabel(text='SubItem 2'), n1)\n\nIf you have a large tree structure, perhaps you would need a utility function\nto populate the tree view::\n\n    def populate_tree_view(tree_view, parent, node):\n        if parent is None:\n            tree_node = tree_view.add_node(TreeViewLabel(text=node['node_id'],\n                                                         is_open=True))\n        else:\n            tree_node = tree_view.add_node(TreeViewLabel(text=node['node_id'],\n                                                         is_open=True), parent)\n\n        for child_node in node['children']:\n            populate_tree_view(tree_view, tree_node, child_node)\n\n\n    tree = {'node_id': '1',\n            'children': [{'node_id': '1.1',\n                          'children': [{'node_id': '1.1.1',\n                                        'children': [{'node_id': '1.1.1.1',\n                                                      'children': []}]},\n                                       {'node_id': '1.1.2',\n                                        'children': []},\n                                       {'node_id': '1.1.3',\n                                        'children': []}]},\n                          {'node_id': '1.2',\n                           'children': []}]}\n\n\n    class TreeWidget(FloatLayout):\n        def __init__(self, **kwargs):\n            super(TreeWidget, self).__init__(**kwargs)\n\n            tv = TreeView(root_options=dict(text='Tree One'),\n                          hide_root=False,\n                          indent_level=4)\n\n            populate_tree_view(tv, None, tree)\n\n            self.add_widget(tv)\n\nThe root widget in the tree view is opened by default and has text set as\n'Root'. If you want to change that, you can use the\n:attr:`TreeView.root_options`\nproperty. This will pass options to the root widget::\n\n    tv = TreeView(root_options=dict(text='My root label'))\n\n\nCreating Your Own Node Widget\n-----------------------------\n\nFor a button node type, combine a :class:`~kivy.uix.button.Button` and a\n:class:`TreeViewNode` as follows::\n\n    class TreeViewButton(Button, TreeViewNode):\n        pass\n\nYou must know that, for a given node, only the\n:attr:`~kivy.uix.widget.Widget.size_hint_x` will be honored. The allocated\nwidth for the node will depend of the current width of the TreeView and the\nlevel of the node. For example, if a node is at level 4, the width\nallocated will be:\n\n    treeview.width - treeview.indent_start - treeview.indent_level * node.level\n\nYou might have some trouble with that. It is the developer's responsibility to\ncorrectly handle adapting the graphical representation nodes, if needed.\n'''\n\nfrom kivy.clock import Clock\nfrom kivy.uix.label import Label\nfrom kivy.uix.widget import Widget\nfrom kivy.properties import BooleanProperty, ListProperty, ObjectProperty, \\\n    AliasProperty, NumericProperty, ReferenceListProperty\n\n\nclass TreeViewException(Exception):\n    '''Exception for errors in the :class:`TreeView`.\n    '''\n    pass\n\n\nclass TreeViewNode(object):\n    '''TreeViewNode class, used to build a node class for a TreeView object.\n    '''\n\n    def __init__(self, **kwargs):\n        if self.__class__ is TreeViewNode:\n            raise TreeViewException('You cannot use directly TreeViewNode.')\n        super(TreeViewNode, self).__init__(**kwargs)\n\n    is_leaf = BooleanProperty(True)\n    '''Boolean to indicate whether this node is a leaf or not. Used to adjust\n    the graphical representation.\n\n    :attr:`is_leaf` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to True. It is automatically set to False when child is added.\n    '''\n\n    is_open = BooleanProperty(False)\n    '''Boolean to indicate whether this node is opened or not, in case there\n    are child nodes. This is used to adjust the graphical representation.\n\n    .. warning::\n\n        This property is automatically set by the :class:`TreeView`. You can\n        read but not write it.\n\n    :attr:`is_open` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    is_loaded = BooleanProperty(False)\n    '''Boolean to indicate whether this node is already loaded or not. This\n    property is used only if the :class:`TreeView` uses asynchronous loading.\n\n    :attr:`is_loaded` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    is_selected = BooleanProperty(False)\n    '''Boolean to indicate whether this node is selected or not. This is used\n    adjust the graphical representation.\n\n    .. warning::\n\n        This property is automatically set by the :class:`TreeView`. You can\n        read but not write it.\n\n    :attr:`is_selected` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    no_selection = BooleanProperty(False)\n    '''Boolean used to indicate whether selection of the node is allowed or\n     not.\n\n    :attr:`no_selection` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    nodes = ListProperty([])\n    '''List of nodes. The nodes list is different than the children list. A\n    node in the nodes list represents a node on the tree. An item in the\n    children list represents the widget associated with the node.\n\n    .. warning::\n\n        This property is automatically set by the :class:`TreeView`. You can\n        read but not write it.\n\n    :attr:`nodes` is a :class:`~kivy.properties.ListProperty` and defaults to\n    [].\n    '''\n\n    parent_node = ObjectProperty(None, allownone=True)\n    '''Parent node. This attribute is needed because the :attr:`parent` can be\n    None when the node is not displayed.\n\n    .. versionadded:: 1.0.7\n\n    :attr:`parent_node` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n    level = NumericProperty(-1)\n    '''Level of the node.\n\n    :attr:`level` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to -1.\n    '''\n\n    color_selected = ListProperty([.3, .3, .3, 1.])\n    '''Background color of the node when the node is selected.\n\n    :attr:`color_selected` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [.1, .1, .1, 1].\n    '''\n\n    odd = BooleanProperty(False)\n    '''\n    This property is set by the TreeView widget automatically and is read-only.\n\n    :attr:`odd` is a :class:`~kivy.properties.BooleanProperty` and defaults to\n    False.\n    '''\n\n    odd_color = ListProperty([1., 1., 1., .0])\n    '''Background color of odd nodes when the node is not selected.\n\n    :attr:`odd_color` is a :class:`~kivy.properties.ListProperty` and defaults\n    to [1., 1., 1., 0.].\n    '''\n\n    even_color = ListProperty([0.5, 0.5, 0.5, 0.1])\n    '''Background color of even nodes when the node is not selected.\n\n    :attr:`bg_color` is a :class:`~kivy.properties.ListProperty` ans defaults\n    to [.5, .5, .5, .1].\n    '''\n\n\nclass TreeViewLabel(Label, TreeViewNode):\n    '''Combines a :class:`~kivy.uix.label.Label` and a :class:`TreeViewNode` to\n    create a :class:`TreeViewLabel` that can be used as a text node in the\n    tree.\n\n    See module documentation for more information.\n    '''\n\n\nclass TreeView(Widget):\n    '''TreeView class. See module documentation for more information.\n\n    :Events:\n        `on_node_expand`: (node, )\n            Fired when a node is being expanded\n        `on_node_collapse`: (node, )\n            Fired when a node is being collapsed\n    '''\n\n    __events__ = ('on_node_expand', 'on_node_collapse')\n\n    def __init__(self, **kwargs):\n        self._trigger_layout = Clock.create_trigger(self._do_layout, -1)\n        super(TreeView, self).__init__(**kwargs)\n        tvlabel = TreeViewLabel(text='Root', is_open=True, level=0)\n        for key, value in self.root_options.items():\n            setattr(tvlabel, key, value)\n        self._root = self.add_node(tvlabel, None)\n        self.bind(\n            pos=self._trigger_layout,\n            size=self._trigger_layout,\n            indent_level=self._trigger_layout,\n            indent_start=self._trigger_layout)\n        self._trigger_layout()\n\n    def add_node(self, node, parent=None):\n        '''Add a new node to the tree.\n\n        :Parameters:\n            `node`: instance of a :class:`TreeViewNode`\n                Node to add into the tree\n            `parent`: instance of a :class:`TreeViewNode`, defaults to None\n                Parent node to attach the new node. If `None`, it is added to\n                the :attr:`root` node.\n\n        :returns:\n            the node `node`.\n        '''\n        # check if the widget is \"ok\" for a node\n        if not isinstance(node, TreeViewNode):\n            raise TreeViewException(\n                'The node must be a subclass of TreeViewNode')\n        # create node\n        if parent is None and self._root:\n            parent = self._root\n        if parent:\n            parent.is_leaf = False\n            parent.nodes.append(node)\n            node.parent_node = parent\n            node.level = parent.level + 1\n        node.bind(size=self._trigger_layout)\n        self._trigger_layout()\n        return node\n\n    def remove_node(self, node):\n        '''Removes a node from the tree.\n\n        .. versionadded:: 1.0.7\n\n        :Parameters:\n            `node`: instance of a :class:`TreeViewNode`\n                Node to remove from the tree. If `node` is :attr:`root`, it is\n                not removed.\n        '''\n        # check if the widget is \"ok\" for a node\n        if not isinstance(node, TreeViewNode):\n            raise TreeViewException(\n                'The node must be a subclass of TreeViewNode')\n        parent = node.parent_node\n        if parent is not None:\n            nodes = parent.nodes\n            if node in nodes:\n                nodes.remove(node)\n                self._selected_node = None\n            parent.is_leaf = not bool(len(nodes))\n            node.parent_node = None\n            node.unbind(size=self._trigger_layout)\n            self._trigger_layout()\n\n    def on_node_expand(self, node):\n        pass\n\n    def on_node_collapse(self, node):\n        pass\n\n    def select_node(self, node):\n        '''Select a node in the tree.\n        '''\n        if node.no_selection:\n            return\n        if self._selected_node:\n            self._selected_node.is_selected = False\n        node.is_selected = True\n        self._selected_node = node\n\n    def toggle_node(self, node):\n        '''Toggle the state of the node (open/collapsed).\n        '''\n        node.is_open = not node.is_open\n        if node.is_open:\n            if self.load_func and not node.is_loaded:\n                self._do_node_load(node)\n            self.dispatch('on_node_expand', node)\n        else:\n            self.dispatch('on_node_collapse', node)\n        self._trigger_layout()\n\n    def get_node_at_pos(self, pos):\n        '''Get the node at the position (x, y).\n        '''\n        x, y = pos\n        for node in self.iterate_open_nodes(self.root):\n            if self.x <= x <= self.right and \\\n               node.y <= y <= node.top:\n                return node\n\n    def iterate_open_nodes(self, node=None):\n        '''Generator to iterate over all the expended nodes starting from\n        `node` and down. If `node` is `None`, the generator start with\n        :attr:`root`.\n\n        To get all the open nodes::\n\n            treeview = TreeView()\n            # ... add nodes ...\n            for node in treeview.iterate_open_nodes():\n                print(node)\n\n        '''\n        if not node:\n            node = self.root\n        if self.hide_root and node is self.root:\n            pass\n        else:\n            yield node\n        if not node.is_open:\n            return\n        f = self.iterate_open_nodes\n        for cnode in node.nodes:\n            for ynode in f(cnode):\n                yield ynode\n\n    def iterate_all_nodes(self, node=None):\n        '''Generator to iterate over all nodes from `node` and down whether\n        expanded or not. If `node` is `None`, the generator start with\n        :attr:`root`.\n        '''\n        if not node:\n            node = self.root\n        yield node\n        f = self.iterate_all_nodes\n        for cnode in node.nodes:\n            for ynode in f(cnode):\n                yield ynode\n\n    #\n    # Private\n    #\n    def on_load_func(self, instance, value):\n        if value:\n            Clock.schedule_once(self._do_initial_load)\n\n    def _do_initial_load(self, *largs):\n        if not self.load_func:\n            return\n        self._do_node_load(None)\n\n    def _do_node_load(self, node):\n        gen = self.load_func(self, node)\n        if node:\n            node.is_loaded = True\n        if not gen:\n            return\n        for cnode in gen:\n            self.add_node(cnode, node)\n\n    def on_root_options(self, instance, value):\n        if not self.root:\n            return\n        for key, value in value.items():\n            setattr(self.root, key, value)\n\n    def _do_layout(self, *largs):\n        self.clear_widgets()\n        # display only the one who are is_open\n        self._do_open_node(self.root)\n        # now do layout\n        self._do_layout_node(self.root, 0, self.top)\n        # now iterate for calculating minimum size\n        min_width = min_height = 0\n        count = 0\n        for node in self.iterate_open_nodes(self.root):\n            node.odd = False if count % 2 else True\n            count += 1\n            min_width = max(min_width, node.width + self.indent_level +\n                            node.level * self.indent_level)\n            min_height += node.height\n        self.minimum_size = (min_width, min_height)\n\n    def _do_open_node(self, node):\n        if self.hide_root and node is self.root:\n            height = 0\n        else:\n            self.add_widget(node)\n            height = node.height\n            if not node.is_open:\n                return height\n        for cnode in node.nodes:\n            height += self._do_open_node(cnode)\n        return height\n\n    def _do_layout_node(self, node, level, y):\n        if self.hide_root and node is self.root:\n            level -= 1\n        else:\n            node.x = self.x + self.indent_start + level * self.indent_level\n            node.top = y\n            if node.size_hint_x:\n                node.width = (self.width - (node.x - self.x)) \\\n                    * node.size_hint_x\n            y -= node.height\n            if not node.is_open:\n                return y\n        for cnode in node.nodes:\n            y = self._do_layout_node(cnode, level + 1, y)\n        return y\n\n    def on_touch_down(self, touch):\n        node = self.get_node_at_pos(touch.pos)\n        if not node:\n            return\n        if node.disabled:\n            return\n        # toggle node or selection ?\n        if node.x - self.indent_start <= touch.x < node.x:\n            self.toggle_node(node)\n        elif node.x <= touch.x:\n            self.select_node(node)\n            node.dispatch('on_touch_down', touch)\n        return True\n\n    #\n    # Private properties\n    #\n    _root = ObjectProperty(None)\n\n    _selected_node = ObjectProperty(None, allownone=True)\n\n    #\n    # Properties\n    #\n\n    minimum_width = NumericProperty(0)\n    '''Minimum width needed to contain all children.\n\n    .. versionadded:: 1.0.9\n\n    :attr:`minimum_width` is a :class:`kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    minimum_height = NumericProperty(0)\n    '''Minimum height needed to contain all children.\n\n    .. versionadded:: 1.0.9\n\n    :attr:`minimum_height` is a :class:`kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    minimum_size = ReferenceListProperty(minimum_width, minimum_height)\n    '''Minimum size needed to contain all children.\n\n    .. versionadded:: 1.0.9\n\n    :attr:`minimum_size` is a :class:`~kivy.properties.ReferenceListProperty`\n    of (:attr:`minimum_width`, :attr:`minimum_height`) properties.\n    '''\n\n    indent_level = NumericProperty('16dp')\n    '''Width used for the indentation of each level except the first level.\n\n    Computation of indent for each level of the tree is::\n\n        indent = indent_start + level * indent_level\n\n    :attr:`indent_level` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 16.\n    '''\n\n    indent_start = NumericProperty('24dp')\n    '''Indentation width of the level 0 / root node. This is mostly the initial\n    size to accommodate a tree icon (collapsed / expanded). See\n    :attr:`indent_level` for more information about the computation of level\n    indentation.\n\n    :attr:`indent_start` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 24.\n    '''\n\n    hide_root = BooleanProperty(False)\n    '''Use this property to show/hide the initial root node. If True, the root\n    node will be appear as a closed node.\n\n    :attr:`hide_root` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n\n    def get_selected_node(self):\n        return self._selected_node\n\n    selected_node = AliasProperty(get_selected_node, None,\n                                  bind=('_selected_node', ))\n    '''Node selected by :meth:`TreeView.select_node` or by touch.\n\n    :attr:`selected_node` is a :class:`~kivy.properties.AliasProperty` and\n    defaults to None. It is read-only.\n    '''\n\n    def get_root(self):\n        return self._root\n\n    root = AliasProperty(get_root, None, bind=('_root', ))\n    '''Root node.\n\n    By default, the root node widget is a :class:`TreeViewLabel` with text\n    'Root'. If you want to change the default options passed to the widget\n    creation, use the :attr:`root_options` property::\n\n        treeview = TreeView(root_options={\n            'text': 'Root directory',\n            'font_size': 15})\n\n    :attr:`root_options` will change the properties of the\n    :class:`TreeViewLabel` instance. However, you cannot change the class used\n    for root node yet.\n\n    :attr:`root` is an :class:`~kivy.properties.AliasProperty` and defaults to\n    None. It is read-only. However, the content of the widget can be changed.\n    '''\n\n    root_options = ObjectProperty({})\n    '''Default root options to pass for root widget. See :attr:`root` property\n    for more information about the usage of root_options.\n\n    :attr:`root_options` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to {}.\n    '''\n\n    load_func = ObjectProperty(None)\n    '''Callback to use for asynchronous loading. If set, asynchronous loading\n    will be automatically done. The callback must act as a Python generator\n    function, using yield to send data back to the treeview.\n\n    The callback should be in the format::\n\n        def callback(treeview, node):\n            for name in ('Item 1', 'Item 2'):\n                yield TreeViewLabel(text=name)\n\n    :attr:`load_func` is a :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n    '''\n\n\nif __name__ == '__main__':\n    from kivy.app import App\n\n    class TestApp(App):\n\n        def build(self):\n            tv = TreeView(hide_root=True)\n            add = tv.add_node\n            root = add(TreeViewLabel(text='Level 1, entry 1', is_open=True))\n            for x in range(5):\n                add(TreeViewLabel(text='Element %d' % x), root)\n            root2 = add(TreeViewLabel(text='Level 1, entry 2', is_open=False))\n            for x in range(24):\n                add(TreeViewLabel(text='Element %d' % x), root2)\n            for x in range(5):\n                add(TreeViewLabel(text='Element %d' % x), root)\n            root2 = add(TreeViewLabel(text='Element childs 2', is_open=False),\n                        root)\n            for x in range(24):\n                add(TreeViewLabel(text='Element %d' % x), root2)\n            return tv\n    TestApp().run()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/video.py",
    "content": "'''\nVideo\n=====\n\nThe :class:`Video` widget is used to display video files and streams.\nDepending on your Video core provider, platform, and plugins, you will\nbe able to play different formats. For example, the pygame video\nprovider only supports MPEG1 on Linux and OSX. GStreamer is more\nversatile, and can read many video containers and codecs such as MKV,\nOGV, AVI, MOV, FLV (if the correct gstreamer plugins are installed). Our\n:class:`~kivy.core.video.VideoBase` implementation is used under the\nhood.\n\nVideo loading is asynchronous - many properties are not available until\nthe video is loaded (when the texture is created)::\n\n    def on_position_change(instance, value):\n        print('The position in the video is', value)\n    def on_duration_change(instance, value):\n        print('The duration of the video is', video)\n    video = Video(source='PandaSneezes.avi')\n    video.bind(position=on_position_change,\n               duration=on_duration_change)\n\n'''\n\n__all__ = ('Video', )\n\nfrom kivy.clock import Clock\nfrom kivy.uix.image import Image\nfrom kivy.core.video import Video as CoreVideo\nfrom kivy.resources import resource_find\nfrom kivy.properties import (BooleanProperty, NumericProperty, ObjectProperty,\n                             OptionProperty)\n\n\nclass Video(Image):\n    '''Video class. See module documentation for more information.\n    '''\n\n    state = OptionProperty('stop', options=('play', 'pause', 'stop'))\n    '''String, indicates whether to play, pause, or stop the video::\n\n        # start playing the video at creation\n        video = Video(source='movie.mkv', state='play')\n\n        # create the video, and start later\n        video = Video(source='movie.mkv')\n        # and later\n        video.state = 'play'\n\n    :attr:`state` is an :class:`~kivy.properties.OptionProperty` and defaults\n    to 'stop'.\n    '''\n\n    play = BooleanProperty(False)\n    '''\n    .. deprecated:: 1.4.0\n        Use :attr:`state` instead.\n\n    Boolean, indicates whether the video is playing or not.\n    You can start/stop the video by setting this property::\n\n        # start playing the video at creation\n        video = Video(source='movie.mkv', play=True)\n\n        # create the video, and start later\n        video = Video(source='movie.mkv')\n        # and later\n        video.play = True\n\n    :attr:`play` is a :class:`~kivy.properties.BooleanProperty` and defaults to\n    False.\n\n    .. deprecated:: 1.4.0\n        Use :attr:`state` instead.\n    '''\n\n    eos = BooleanProperty(False)\n    '''Boolean, indicates whether the video has finished playing or not\n    (reached the end of the stream).\n\n    :attr:`eos` is a :class:`~kivy.properties.BooleanProperty` and defaults to\n    False.\n    '''\n\n    loaded = BooleanProperty(False)\n    '''Boolean, indicates whether the video is loaded and ready for playback\n    or not.\n\n    .. versionadded:: 1.6.0\n\n    :attr:`loaded` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    position = NumericProperty(-1)\n    '''Position of the video between 0 and :attr:`duration`. The position\n    defaults to -1 and is set to a real position when the video is loaded.\n\n    :attr:`position` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to -1.\n    '''\n\n    duration = NumericProperty(-1)\n    '''Duration of the video. The duration defaults to -1, and is set to a real\n    duration when the video is loaded.\n\n    :attr:`duration` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to -1.\n    '''\n\n    volume = NumericProperty(1.)\n    '''Volume of the video, in the range 0-1. 1 means full volume, 0\n    means mute.\n\n    :attr:`volume` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 1.\n    '''\n\n    options = ObjectProperty({})\n    '''Options to pass at Video core object creation.\n\n    .. versionadded:: 1.0.4\n\n    :attr:`options` is an :class:`kivy.properties.ObjectProperty` and defaults\n    to {}.\n    '''\n\n    def __init__(self, **kwargs):\n        self._video = None\n        super(Video, self).__init__(**kwargs)\n        self.bind(source=self._trigger_video_load)\n\n        if \"eos\" in kwargs:\n            self.options[\"eos\"] = kwargs[\"eos\"]\n        if self.source:\n            self._trigger_video_load()\n\n    def seek(self, percent):\n        '''Change the position to a percentage of duration. Percentage\n        must be a value between 0-1.\n\n        .. warning::\n\n            Calling seek() before the video is loaded has no impact.\n\n        .. versionadded:: 1.2.0\n        '''\n        if self._video is None:\n            raise Exception('Video not loaded.')\n        self._video.seek(percent)\n\n    def _trigger_video_load(self, *largs):\n        Clock.unschedule(self._do_video_load)\n        Clock.schedule_once(self._do_video_load, -1)\n\n    def _do_video_load(self, *largs):\n        if CoreVideo is None:\n            return\n        if self._video:\n            self._video.stop()\n        if not self.source:\n            self._video = None\n            self.texture = None\n        else:\n            filename = self.source\n            # Check if filename is not url\n            if not '://' in filename:\n                filename = resource_find(filename)\n            self._video = CoreVideo(filename=filename, **self.options)\n            self._video.volume = self.volume\n            self._video.bind(on_load=self._on_load,\n                             on_frame=self._on_video_frame,\n                             on_eos=self._on_eos)\n            if self.state == 'play' or self.play:\n                self._video.play()\n            self.duration = 1.\n            self.position = 0.\n\n    def on_play(self, instance, value):\n        value = 'play' if value else 'stop'\n        return self.on_state(instance, value)\n\n    def on_state(self, instance, value):\n        if not self._video:\n            return\n        if value == 'play':\n            if self.eos:\n                self._video.stop()\n                self._video.position = 0.\n                self._video.eos = False\n            self.eos = False\n            self._video.play()\n        elif value == 'pause':\n            self._video.pause()\n        else:\n            self._video.stop()\n            self._video.position = 0\n            self._video.eos = False\n\n    def _on_video_frame(self, *largs):\n        video = self._video\n        if not video:\n            return\n        self.duration = video.duration\n        self.position = video.position\n        self.texture = video.texture\n        self.canvas.ask_update()\n\n    def _on_eos(self, *largs):\n        if self._video.eos != 'loop':\n            self.state = 'stop'\n            self.eos = True\n\n    def _on_load(self, *largs):\n        self.loaded = True\n        self._on_video_frame(largs)\n\n    def on_volume(self, instance, value):\n        if self._video:\n            self._video.volume = value\n\n    def unload(self):\n        '''Unload the video. The playback will be stopped.\n\n        .. versionadded:: 1.8.0\n        '''\n        if self._video:\n            self._video.stop()\n            self._video.unload()\n            self._video = None\n\nif __name__ == '__main__':\n    from kivy.app import App\n    import sys\n\n    if len(sys.argv) != 2:\n        print(\"usage: %s file\" % sys.argv[0])\n        sys.exit(1)\n\n    class VideoApp(App):\n        def build(self):\n            self.v = Video(source=sys.argv[1], state='play')\n            self.v.bind(state=self.replay)\n            return self.v\n\n        def replay(self, *args):\n            if self.v.state == 'stop':\n                self.v.state = 'play'\n\n    VideoApp().run()\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/videoplayer.py",
    "content": "'''\nVideo player\n============\n\n.. versionadded:: 1.2.0\n\nThe video player widget can be used to play video and let the user control the\nplay/pausing, volume and position. The widget cannot be customized much because\nof the complex assembly of numerous base widgets.\n\n.. image:: images/videoplayer.jpg\n    :align: center\n\nAnnotations\n-----------\n\nIf you want to display text at a specific time and for a certain duration,\nconsider annotations. An annotation file has a \".jsa\" extension. The player\nwill automatically load the associated annotation file if it exists.\n\nAn annotation file is JSON-based, providing a list of label dictionary items.\nThe key and value must match one of the :class:`VideoPlayerAnnotation` items.\nFor example, here is a short version of a jsa file that you can find in\n`examples/widgets/softboy.jsa`::\n\n\n    [\n        {\"start\": 0, \"duration\": 2,\n        \"text\": \"This is an example of annotation\"},\n        {\"start\": 2, \"duration\": 2,\n        \"bgcolor\": [0.5, 0.2, 0.4, 0.5],\n        \"text\": \"You can change the background color\"}\n    ]\n\nFor our softboy.avi example, the result will be:\n\n.. image:: images/videoplayer-annotation.jpg\n    :align: center\n\nIf you want to experiment with annotation files, test with::\n\n    python -m kivy.uix.videoplayer examples/widgets/softboy.avi\n\nFullscreen\n----------\n\nThe video player can play the video in fullscreen, if\n:attr:`VideoPlayer.allow_fullscreen` is activated by a double-tap on\nthe video. By default, if the video is smaller than the Window, it will be not\nstretched.\n\nYou can allow stretching by passing custom options to a\n:class:`VideoPlayer` instance::\n\n    player = VideoPlayer(source='myvideo.avi', state='play',\n        options={'allow_stretch': True})\n\nEnd-of-stream behavior\n----------------------\n\nYou can specify what happens when the video has finished playing by passing an\n`eos` (end of stream) directive to the underlying\n:class:`~kivy.core.video.VideoBase` class. `eos` can be one of 'stop', 'pause'\nor 'loop' and defaults to 'stop'. For example, in order to loop the video::\n\n    player = VideoPlayer(source='myvideo.avi', state='play',\n        options={'eos': 'loop'})\n\n.. note::\n\n    The `eos` property of the VideoBase class is a string specifying the\n    end-of-stream behavior. This property differs from the `eos`\n    properties of the :class:`VideoPlayer` and\n    :class:`~kivy.uix.video.Video` classes, whose `eos`\n    property is simply a boolean indicating that the end of the file has\n    been reached.\n\n'''\n\n__all__ = ('VideoPlayer', 'VideoPlayerAnnotation')\n\nfrom json import load\nfrom os.path import exists\nfrom kivy.properties import ObjectProperty, StringProperty, BooleanProperty, \\\n    NumericProperty, DictProperty, OptionProperty\nfrom kivy.animation import Animation\nfrom kivy.uix.gridlayout import GridLayout\nfrom kivy.uix.floatlayout import FloatLayout\nfrom kivy.uix.progressbar import ProgressBar\nfrom kivy.uix.label import Label\nfrom kivy.uix.video import Video\nfrom kivy.uix.video import Image\nfrom kivy.factory import Factory\nfrom kivy.logger import Logger\nfrom kivy.clock import Clock\n\n\nclass VideoPlayerVolume(Image):\n    video = ObjectProperty(None)\n\n    def on_touch_down(self, touch):\n        if not self.collide_point(*touch.pos):\n            return False\n        touch.grab(self)\n        # save the current volume and delta to it\n        touch.ud[self.uid] = [self.video.volume, 0]\n        return True\n\n    def on_touch_move(self, touch):\n        if touch.grab_current is not self:\n            return\n        # calculate delta\n        dy = abs(touch.y - touch.oy)\n        if dy > 10:\n            dy = min(dy - 10, 100)\n            touch.ud[self.uid][1] = dy\n            self.video.volume = dy / 100.\n        return True\n\n    def on_touch_up(self, touch):\n        if touch.grab_current is not self:\n            return\n        touch.ungrab(self)\n        dy = abs(touch.y - touch.oy)\n        if dy < 10:\n            if self.video.volume > 0:\n                self.video.volume = 0\n            else:\n                self.video.volume = 1.\n\n\nclass VideoPlayerPlayPause(Image):\n    video = ObjectProperty(None)\n\n    def on_touch_down(self, touch):\n        '''.. versionchanged:: 1.4.0'''\n        if self.collide_point(*touch.pos):\n            if self.video.state == 'play':\n                self.video.state = 'pause'\n            else:\n                self.video.state = 'play'\n            return True\n\n\nclass VideoPlayerStop(Image):\n    video = ObjectProperty(None)\n\n    def on_touch_down(self, touch):\n        if self.collide_point(*touch.pos):\n            self.video.state = 'stop'\n            self.video.position = 0\n            return True\n\n\nclass VideoPlayerProgressBar(ProgressBar):\n    video = ObjectProperty(None)\n    seek = NumericProperty(None, allownone=True)\n    alpha = NumericProperty(1.)\n\n    def __init__(self, **kwargs):\n        super(VideoPlayerProgressBar, self).__init__(**kwargs)\n        self.bubble = Factory.Bubble(size=(50, 44))\n        self.bubble_label = Factory.Label(text='0:00')\n        self.bubble.add_widget(self.bubble_label)\n        self.add_widget(self.bubble)\n        self.bind(pos=self._update_bubble,\n                  size=self._update_bubble,\n                  seek=self._update_bubble)\n\n    def on_video(self, instance, value):\n        self.video.bind(position=self._update_bubble,\n                        state=self._showhide_bubble)\n\n    def on_touch_down(self, touch):\n        if not self.collide_point(*touch.pos):\n            return\n        self._show_bubble()\n        touch.grab(self)\n        self._update_seek(touch.x)\n        return True\n\n    def on_touch_move(self, touch):\n        if touch.grab_current is not self:\n            return\n        self._update_seek(touch.x)\n        return True\n\n    def on_touch_up(self, touch):\n        if touch.grab_current is not self:\n            return\n        touch.ungrab(self)\n        if self.seek:\n            self.video.seek(self.seek)\n        self.seek = None\n        self._hide_bubble()\n        return True\n\n    def _update_seek(self, x):\n        if self.width == 0:\n            return\n        x = max(self.x, min(self.right, x)) - self.x\n        self.seek = x / float(self.width)\n\n    def _show_bubble(self):\n        self.alpha = 1\n        Animation.stop_all(self, 'alpha')\n\n    def _hide_bubble(self):\n        self.alpha = 1.\n        Animation(alpha=0, d=4, t='in_out_expo').start(self)\n\n    def on_alpha(self, instance, value):\n        self.bubble.background_color = (1, 1, 1, value)\n        self.bubble_label.color = (1, 1, 1, value)\n\n    def _update_bubble(self, *l):\n        seek = self.seek\n        if self.seek is None:\n            if self.video.duration == 0:\n                seek = 0\n            else:\n                seek = self.video.position / self.video.duration\n        # convert to minutes:seconds\n        d = self.video.duration * seek\n        minutes = int(d / 60)\n        seconds = int(d - (minutes * 60))\n        # fix bubble label & position\n        self.bubble_label.text = '%d:%02d' % (minutes, seconds)\n        self.bubble.center_x = self.x + seek * self.width\n        self.bubble.y = self.top\n\n    def _showhide_bubble(self, instance, value):\n        if value == 'play':\n            self._hide_bubble()\n        else:\n            self._show_bubble()\n\n\nclass VideoPlayerPreview(FloatLayout):\n    source = ObjectProperty(None)\n    video = ObjectProperty(None)\n    click_done = BooleanProperty(False)\n\n    def on_touch_down(self, touch):\n        if self.collide_point(*touch.pos) and not self.click_done:\n            self.click_done = True\n            self.video.state = 'play'\n        return True\n\n\nclass VideoPlayerAnnotation(Label):\n    '''Annotation class used for creating annotation labels.\n\n    Additional keys are available:\n\n    * bgcolor: [r, g, b, a] - background color of the text box\n    * bgsource: 'filename' - background image used for the background text box\n    * border: (n, e, s, w) - border used for the background image\n\n    '''\n    start = NumericProperty(0)\n    '''Start time of the annotation.\n\n    :attr:`start` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 0.\n    '''\n\n    duration = NumericProperty(1)\n    '''Duration of the annotation.\n\n    :attr:`duration` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 1.\n    '''\n\n    annotation = DictProperty({})\n\n    def on_annotation(self, instance, ann):\n        for key, value in ann.items():\n            setattr(self, key, value)\n\n\nclass VideoPlayer(GridLayout):\n    '''VideoPlayer class. See module documentation for more information.\n    '''\n\n    source = StringProperty('')\n    '''Source of the video to read.\n\n    :attr:`source` is a :class:`~kivy.properties.StringProperty` and\n    defaults to ''.\n\n    .. versionchanged:: 1.4.0\n    '''\n\n    thumbnail = StringProperty('')\n    '''Thumbnail of the video to show. If None, VideoPlayer will try to find\n    the thumbnail from the :attr:`source` + '.png'.\n\n    :attr:`thumbnail` a :class:`~kivy.properties.StringProperty` and defaults\n    to ''.\n\n    .. versionchanged:: 1.4.0\n    '''\n\n    duration = NumericProperty(-1)\n    '''Duration of the video. The duration defaults to -1 and is set to the\n    real duration when the video is loaded.\n\n    :attr:`duration` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to -1.\n    '''\n\n    position = NumericProperty(0)\n    '''Position of the video between 0 and :attr:`duration`. The position\n    defaults to -1 and is set to the real position when the video is loaded.\n\n    :attr:`position` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to -1.\n    '''\n\n    volume = NumericProperty(1.0)\n    '''Volume of the video in the range 0-1. 1 means full volume and 0 means\n    mute.\n\n    :attr:`volume` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 1.\n    '''\n\n    state = OptionProperty('stop', options=('play', 'pause', 'stop'))\n    '''String, indicates whether to play, pause, or stop the video::\n\n        # start playing the video at creation\n        video = VideoPlayer(source='movie.mkv', state='play')\n\n        # create the video, and start later\n        video = VideoPlayer(source='movie.mkv')\n        # and later\n        video.state = 'play'\n\n    :attr:`state` is an :class:`~kivy.properties.OptionProperty` and defaults\n    to 'play'.\n    '''\n\n    play = BooleanProperty(False)\n    '''\n    .. deprecated:: 1.4.0\n        Use :attr:`state` instead.\n\n    Boolean, indicates whether the video is playing or not. You can start/stop\n    the video by setting this property::\n\n        # start playing the video at creation\n        video = VideoPlayer(source='movie.mkv', play=True)\n\n        # create the video, and start later\n        video = VideoPlayer(source='movie.mkv')\n        # and later\n        video.play = True\n\n    :attr:`play` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    image_overlay_play = StringProperty(\n        'atlas://data/images/defaulttheme/player-play-overlay')\n    '''Image filename used to show a \"play\" overlay when the video has not yet\n    started.\n\n    :attr:`image_overlay_play` is a\n    :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/player-play-overlay'.\n\n    '''\n\n    image_loading = StringProperty('data/images/image-loading.gif')\n    '''Image filename used when the video is loading.\n\n    :attr:`image_loading` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'data/images/image-loading.gif'.\n    '''\n\n    image_play = StringProperty(\n        'atlas://data/images/defaulttheme/media-playback-start')\n    '''Image filename used for the \"Play\" button.\n\n    :attr:`image_play` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/media-playback-start'.\n    '''\n\n    image_stop = StringProperty(\n        'atlas://data/images/defaulttheme/media-playback-stop')\n    '''Image filename used for the \"Stop\" button.\n\n    :attr:`image_stop` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/media-playback-stop'.\n    '''\n\n    image_pause = StringProperty(\n        'atlas://data/images/defaulttheme/media-playback-pause')\n    '''Image filename used for the \"Pause\" button.\n\n    :attr:`image_pause` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/media-playback-pause'.\n    '''\n\n    image_volumehigh = StringProperty(\n        'atlas://data/images/defaulttheme/audio-volume-high')\n    '''Image filename used for the volume icon when the volume is high.\n\n    :attr:`image_volumehigh` is a :class:`~kivy.properties.StringProperty` and\n    defaults to 'atlas://data/images/defaulttheme/audio-volume-high'.\n    '''\n\n    image_volumemedium = StringProperty(\n        'atlas://data/images/defaulttheme/audio-volume-medium')\n    '''Image filename used for the volume icon when the volume is medium.\n\n    :attr:`image_volumemedium` is a :class:`~kivy.properties.StringProperty`\n    and defaults to 'atlas://data/images/defaulttheme/audio-volume-medium'.\n    '''\n\n    image_volumelow = StringProperty(\n        'atlas://data/images/defaulttheme/audio-volume-low')\n    '''Image filename used for the volume icon when the volume is low.\n\n    :attr:`image_volumelow` is a :class:`~kivy.properties.StringProperty`\n    and defaults to 'atlas://data/images/defaulttheme/audio-volume-low'.\n    '''\n\n    image_volumemuted = StringProperty(\n        'atlas://data/images/defaulttheme/audio-volume-muted')\n    '''Image filename used for the volume icon when the volume is muted.\n\n    :attr:`image_volumemuted` is a :class:`~kivy.properties.StringProperty`\n    and defaults to 'atlas://data/images/defaulttheme/audio-volume-muted'.\n    '''\n\n    annotations = StringProperty('')\n    '''If set, it will be used for reading annotations box.\n\n    :attr:`annotations` is a :class:`~kivy.properties.StringProperty`\n    and defaults to ''.\n    '''\n\n    fullscreen = BooleanProperty(False)\n    '''Switch to fullscreen view. This should be used with care. When\n    activated, the widget will remove itself from its parent, remove all\n    children from the window and will add itself to it. When fullscreen is\n    unset, all the previous children are restored and the widget is restored to\n    its previous parent.\n\n    .. warning::\n\n        The re-add operation doesn't care about the index position of it's\n        children within the parent.\n\n    :attr:`fullscreen` is a :class:`~kivy.properties.BooleanProperty`\n    and defaults to False.\n    '''\n\n    allow_fullscreen = BooleanProperty(True)\n    '''By default, you can double-tap on the video to make it fullscreen. Set\n    this property to False to prevent this behavior.\n\n    :attr:`allow_fullscreen` is a :class:`~kivy.properties.BooleanProperty`\n    defaults to True.\n    '''\n\n    options = DictProperty({})\n    '''Optional parameters can be passed to a :class:`~kivy.uix.video.Video`\n    instance with this property.\n\n    :attr:`options` a :class:`~kivy.properties.DictProperty` and\n    defaults to {}.\n    '''\n\n    # internals\n    container = ObjectProperty(None)\n\n    def __init__(self, **kwargs):\n        self._video = None\n        self._image = None\n        self._annotations = ''\n        self._annotations_labels = []\n        super(VideoPlayer, self).__init__(**kwargs)\n        self._load_thumbnail()\n        self._load_annotations()\n\n        if self.source:\n            self._trigger_video_load()\n\n    def _trigger_video_load(self, *largs):\n        Clock.unschedule(self._do_video_load)\n        Clock.schedule_once(self._do_video_load, -1)\n\n    def on_source(self, instance, value):\n        # we got a value, try to see if we have an image for it\n        self._load_thumbnail()\n        self._load_annotations()\n        if self._video is not None:\n            self._video.unload()\n            self._video = None\n        if value:\n            self._trigger_video_load()\n\n    def on_image_overlay_play(self, instance, value):\n        self._image.image_overlay_play = value\n\n    def on_image_loading(self, instance, value):\n        self._image.image_loading = value\n\n    def _load_thumbnail(self):\n        if not self.container:\n            return\n        self.container.clear_widgets()\n        # get the source, remove extension, and use png\n        thumbnail = self.thumbnail\n        if not thumbnail:\n            filename = self.source.rsplit('.', 1)\n            thumbnail = filename[0] + '.png'\n        self._image = VideoPlayerPreview(source=thumbnail, video=self)\n        self.container.add_widget(self._image)\n\n    def _load_annotations(self):\n        if not self.container:\n            return\n        self._annotations_labels = []\n        annotations = self.annotations\n        if not annotations:\n            filename = self.source.rsplit('.', 1)\n            annotations = filename[0] + '.jsa'\n        if exists(annotations):\n            with open(annotations, 'r') as fd:\n                self._annotations = load(fd)\n        if self._annotations:\n            for ann in self._annotations:\n                self._annotations_labels.append(\n                    VideoPlayerAnnotation(annotation=ann))\n\n    def on_state(self, instance, value):\n        if self._video is not None:\n            self._video.state = value\n\n    def _set_state(self, instance, value):\n        self.state = value\n\n    def _do_video_load(self, *largs):\n        self._video = Video(source=self.source, state=self.state,\n                            volume=self.volume, pos_hint={'x': 0, 'y': 0},\n                            **self.options)\n        self._video.bind(texture=self._play_started,\n                         duration=self.setter('duration'),\n                         position=self.setter('position'),\n                         volume=self.setter('volume'),\n                         state=self._set_state)\n\n    def on_play(self, instance, value):\n        value = 'play' if value else 'stop'\n        return self.on_state(instance, value)\n\n    def on_volume(self, instance, value):\n        if not self._video:\n            return\n        self._video.volume = value\n\n    def on_position(self, instance, value):\n        labels = self._annotations_labels\n        if not labels:\n            return\n        for label in labels:\n            start = label.start\n            duration = label.duration\n            if start > value or (start + duration) < value:\n                if label.parent:\n                    label.parent.remove_widget(label)\n            elif label.parent is None:\n                self.container.add_widget(label)\n\n    def seek(self, percent):\n        '''Change the position to a percentage of the duration. Percentage must\n        be a value between 0-1.\n\n        .. warning::\n\n            Calling seek() before video is loaded has no effect.\n        '''\n        if not self._video:\n            return\n        self._video.seek(percent)\n\n    def _play_started(self, instance, value):\n        self.container.clear_widgets()\n        self.container.add_widget(self._video)\n\n    def on_touch_down(self, touch):\n        if not self.collide_point(*touch.pos):\n            return False\n        if touch.is_double_tap and self.allow_fullscreen:\n            self.fullscreen = not self.fullscreen\n            return True\n        return super(VideoPlayer, self).on_touch_down(touch)\n\n    def on_fullscreen(self, instance, value):\n        window = self.get_parent_window()\n        if not window:\n            Logger.warning('VideoPlayer: Cannot switch to fullscreen, '\n                           'window not found.')\n            if value:\n                self.fullscreen = False\n            return\n        if not self.parent:\n            Logger.warning('VideoPlayer: Cannot switch to fullscreen, '\n                           'no parent.')\n            if value:\n                self.fullscreen = False\n            return\n\n        if value:\n            self._fullscreen_state = state = {\n                'parent': self.parent,\n                'pos': self.pos,\n                'size': self.size,\n                'pos_hint': self.pos_hint,\n                'size_hint': self.size_hint,\n                'window_children': window.children[:]}\n\n            # remove all window children\n            for child in window.children[:]:\n                window.remove_widget(child)\n\n            # put the video in fullscreen\n            if state['parent'] is not window:\n                state['parent'].remove_widget(self)\n            window.add_widget(self)\n\n            # ensure the video widget is in 0, 0, and the size will be\n            # reajusted\n            self.pos = (0, 0)\n            self.size = (100, 100)\n            self.pos_hint = {}\n            self.size_hint = (1, 1)\n        else:\n            state = self._fullscreen_state\n            window.remove_widget(self)\n            for child in state['window_children']:\n                window.add_widget(child)\n            self.pos_hint = state['pos_hint']\n            self.size_hint = state['size_hint']\n            self.pos = state['pos']\n            self.size = state['size']\n            if state['parent'] is not window:\n                state['parent'].add_widget(self)\n\n\nif __name__ == '__main__':\n    import sys\n    from kivy.base import runTouchApp\n    player = VideoPlayer(source=sys.argv[1])\n    runTouchApp(player)\n    if player:\n        player.state = 'stop'\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/vkeyboard.py",
    "content": "'''\nVKeyboard\n=========\n\n.. image:: images/vkeyboard.jpg\n    :align: right\n\n.. versionadded:: 1.0.8\n\n\nVKeyboard is an onscreen keyboard for Kivy. Its operation is intended to be\ntransparent to the user. Using the widget directly is NOT recommended. Read the\nsection `Request keyboard`_ first.\n\nModes\n-----\n\nThis virtual keyboard has a docked and free mode:\n\n* docked mode (:attr:`VKeyboard.docked` = True)\n  Generally used when only one person is using the computer, like a tablet or\n  personal computer etc.\n* free mode: (:attr:`VKeyboard.docked` = False)\n  Mostly for multitouch surfaces. This mode allows multiple virtual\n  keyboards to be used on the screen.\n\nIf the docked mode changes, you need to manually call\n:meth:`VKeyboard.setup_mode` otherwise the change will have no impact.\nDuring that call, the VKeyboard, implemented on top of a\n:class:`~kivy.uix.scatter.Scatter`, will change the\nbehavior of the scatter and position the keyboard near the target (if target\nand docked mode is set).\n\n\nLayouts\n-------\n\nThe virtual keyboard is able to load a custom layout. If you create a new\nlayout and put the JSON in :file:`<kivy_data_dir>/keyboards/<layoutid>.json`,\nyou can load it by setting :attr:`VKeyboard.layout` to your layoutid.\n\nThe JSON must be structured like this::\n\n    {\n        \"title\": \"Title of your layout\",\n        \"description\": \"Description of your layout\",\n        \"cols\": 15,\n        \"rows\": 5,\n\n        ...\n    }\n\nThen, you need to describe the keys in each row, for either a \"normal\",\n\"shift\" or a \"special\" (added in version 1.9.0) mode. Keys for this row\ndata must be named `normal_<row>`, `shift_<row>` and `special_<row>`.\nReplace `row` with the row number.\nInside each row, you will describe the key. A key is a 4 element list in\nthe format::\n\n    [ <text displayed on the keyboard>, <text to put when the key is pressed>,\n      <text that represents the keycode>, <size of cols> ]\n\nHere are example keys::\n\n    # f key\n    [\"f\", \"f\", \"f\", 1]\n    # capslock\n    [\"\\u21B9\", \"\\t\", \"tab\", 1.5]\n\nFinally, complete the JSON::\n\n    {\n        ...\n        \"normal_1\": [\n            [\"`\", \"`\", \"`\", 1],    [\"1\", \"1\", \"1\", 1],    [\"2\", \"2\", \"2\", 1],\n            [\"3\", \"3\", \"3\", 1],    [\"4\", \"4\", \"4\", 1],    [\"5\", \"5\", \"5\", 1],\n            [\"6\", \"6\", \"6\", 1],    [\"7\", \"7\", \"7\", 1],    [\"8\", \"8\", \"8\", 1],\n            [\"9\", \"9\", \"9\", 1],    [\"0\", \"0\", \"0\", 1],    [\"+\", \"+\", \"+\", 1],\n            [\"=\", \"=\", \"=\", 1],    [\"\\u232b\", null, \"backspace\", 2]\n        ],\n\n        \"shift_1\": [ ... ],\n        \"normal_2\": [ ... ],\n        \"special_2\": [ ... ],\n        ...\n    }\n\n\nRequest Keyboard\n----------------\n\nThe instantiation of the virtual keyboard is controlled by the configuration.\nCheck `keyboard_mode` and `keyboard_layout` in the :doc:`api-kivy.config`.\n\nIf you intend to create a widget that requires a keyboard, do not use the\nvirtual keyboard directly, but prefer to use the best method available on\nthe platform. Check the :meth:`~kivy.core.window.WindowBase.request_keyboard`\nmethod in the :doc:`api-kivy.core.window`.\n\nIf you want a specific layout when you request the keyboard, you should write\nsomething like this (from 1.8.0, numeric.json can be in the same directory as\nyour main.py)::\n\n    keyboard = Window.request_keyboard(\n        self._keyboard_close, self)\n    if keyboard.widget:\n        vkeyboard = self._keyboard.widget\n        vkeyboard.layout = 'numeric.json'\n\n'''\n\n__all__ = ('VKeyboard', )\n\nfrom kivy import kivy_data_dir\nfrom kivy.vector import Vector\nfrom kivy.config import Config\nfrom kivy.uix.scatter import Scatter\nfrom kivy.uix.label import Label\nfrom kivy.properties import ObjectProperty, NumericProperty, StringProperty, \\\n    BooleanProperty, DictProperty, OptionProperty, ListProperty\nfrom kivy.logger import Logger\nfrom kivy.graphics import Color, BorderImage, Canvas\nfrom kivy.core.image import Image\nfrom kivy.resources import resource_find\nfrom kivy.clock import Clock\n\nfrom os.path import join, splitext, basename\nfrom os import listdir\nfrom json import loads\n\n\ndefault_layout_path = join(kivy_data_dir, 'keyboards')\n\n\nclass VKeyboard(Scatter):\n    '''\n    VKeyboard is an onscreen keyboard with multitouch support.\n    Its layout is entirely customizable and you can switch between available\n    layouts using a button in the bottom right of the widget.\n\n    :Events:\n        `on_key_down`: keycode, internal, modifiers\n            Fired when the keyboard received a key down event (key press).\n        `on_key_up`: keycode, internal, modifiers\n            Fired when the keyboard received a key up event (key release).\n    '''\n\n    target = ObjectProperty(None, allownone=True)\n    '''Target widget associated with the VKeyboard. If set, it will be used to\n    send keyboard events. If the VKeyboard mode is \"free\", it will also be used\n    to set the initial position.\n\n    :attr:`target` is an :class:`~kivy.properties.ObjectProperty` instance and\n    defaults to None.\n    '''\n\n    callback = ObjectProperty(None, allownone=True)\n    '''Callback can be set to a function that will be called if the\n    VKeyboard is closed by the user.\n\n    :attr:`target` is an :class:`~kivy.properties.ObjectProperty` instance and\n    defaults to None.\n    '''\n\n    layout = StringProperty(None)\n    '''Layout to use for the VKeyboard. By default, it will be the\n    layout set in the configuration, according to the `keyboard_layout`\n    in `[kivy]` section.\n\n    .. versionchanged:: 1.8.0\n        If layout is a .json filename, it will loaded and added to the\n        available_layouts.\n\n    :attr:`layout` is a :class:`~kivy.properties.StringProperty` and defaults\n    to None.\n    '''\n\n    layout_path = StringProperty(default_layout_path)\n    '''Path from which layouts are read.\n\n    :attr:`layout` is a :class:`~kivy.properties.StringProperty` and\n    defaults to :file:`<kivy_data_dir>/keyboards/`\n    '''\n\n    available_layouts = DictProperty({})\n    '''Dictionary of all available layouts. Keys are the layout ID, and the\n    value is the JSON (translated into a Python object).\n\n    :attr:`available_layouts` is a :class:`~kivy.properties.DictProperty` and\n    defaults to {}.\n    '''\n\n    docked = BooleanProperty(False)\n    '''Indicate whether the VKeyboard is docked on the screen or not. If you\n    change it, you must manually call :meth:`setup_mode` otherwise it will have\n    no impact. If the VKeyboard is created by the Window, the docked mode will\n    be automatically set by the configuration, using the `keyboard_mode` token\n    in `[kivy]` section.\n\n    :attr:`docked` is a :class:`~kivy.properties.BooleanProperty` and defaults\n    to False.\n    '''\n\n    margin_hint = ListProperty([.05, .06, .05, .06])\n    '''Margin hint, used as spacing between keyboard background and keys\n    content. The margin is composed of four values, between 0 and 1::\n\n        margin_hint = [top, right, bottom, left]\n\n    The margin hints will be multiplied by width and height, according to their\n    position.\n\n    :attr:`margin_hint` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [.05, .06, .05, .06]\n    '''\n\n    key_margin = ListProperty([2, 2, 2, 2])\n    '''Key margin, used to create space between keys. The margin is composed of\n    four values, in pixels::\n\n        key_margin = [top, right, bottom, left]\n\n    :attr:`key_margin` is a :class:`~kivy.properties.ListProperty` and defaults\n    to [2, 2, 2, 2]\n    '''\n\n    background_color = ListProperty([1, 1, 1, 1])\n    '''Background color, in the format (r, g, b, a). If a background is\n    set, the color will be combined with the background texture.\n\n    :attr:`background_color` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [1, 1, 1, 1].\n    '''\n\n    background = StringProperty(\n        'atlas://data/images/defaulttheme/vkeyboard_background')\n    '''Filename of the background image.\n\n    :attr:`background` a :class:`~kivy.properties.StringProperty` and defaults\n    to :file:`atlas://data/images/defaulttheme/vkeyboard_background`.\n    '''\n\n    background_disabled = StringProperty(\n        'atlas://data/images/defaulttheme/vkeyboard_disabled_background')\n    '''Filename of the background image when vkeyboard is disabled.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`background_disabled` is a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    :file:`atlas://data/images/defaulttheme/vkeyboard__disabled_background`.\n\n    '''\n\n    key_background_color = ListProperty([1, 1, 1, 1])\n    '''Key background color, in the format (r, g, b, a). If a key background is\n    set, the color will be combined with the key background texture.\n\n    :attr:`key_background_color` is a :class:`~kivy.properties.ListProperty`\n    and defaults to [1, 1, 1, 1].\n    '''\n\n    key_background_normal = StringProperty(\n        'atlas://data/images/defaulttheme/vkeyboard_key_normal')\n    '''Filename of the key background image for use when no touches are active\n    on the widget.\n\n    :attr:`key_background_normal` a :class:`~kivy.properties.StringProperty`\n    and defaults to\n    :file:`atlas://data/images/defaulttheme/vkeyboard_key_normal`.\n    '''\n\n    key_disabled_background_normal = StringProperty(\n        'atlas://data/images/defaulttheme/vkeyboard_key_normal')\n    '''Filename of the key background image for use when no touches are active\n    on the widget and vkeyboard is disabled.\n\n    ..versionadded:: 1.8.0\n\n    :attr:`key_disabled_background_normal` a\n    :class:`~kivy.properties.StringProperty` and defaults to\n    :file:`atlas://data/images/defaulttheme/vkeyboard_disabled_key_normal`.\n\n    '''\n\n    key_background_down = StringProperty(\n        'atlas://data/images/defaulttheme/vkeyboard_key_down')\n    '''Filename of the key background image for use when a touch is active\n    on the widget.\n\n    :attr:`key_background_down` a :class:`~kivy.properties.StringProperty`\n    and defaults to\n    :file:`atlas://data/images/defaulttheme/vkeyboard_key_down`.\n    '''\n\n    background_border = ListProperty([16, 16, 16, 16])\n    '''Background image border. Used for controlling the\n    :attr:`~kivy.graphics.vertex_instructions.BorderImage.border` property of\n    the background.\n\n    :attr:`background_border` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [16, 16, 16, 16]\n    '''\n\n    key_border = ListProperty([8, 8, 8, 8])\n    '''Key image border. Used for controlling the\n    :attr:`~kivy.graphics.vertex_instructions.BorderImage.border` property of\n    the key.\n\n    :attr:`key_border` is a :class:`~kivy.properties.ListProperty` and\n    defaults to [16, 16, 16, 16]\n    '''\n\n    # XXX internal variables\n    layout_mode = OptionProperty('normal',\n        options=('normal', 'shift', 'special'))\n    layout_geometry = DictProperty({})\n    have_capslock = BooleanProperty(False)\n    have_shift = BooleanProperty(False)\n    have_special = BooleanProperty(False)\n    active_keys = DictProperty({})\n    font_size = NumericProperty('20dp')\n    font_name = StringProperty('data/fonts/DroidSans.ttf')\n    repeat_touch = ObjectProperty(allownone=True)\n\n    __events__ = ('on_key_down', 'on_key_up', 'on_textinput')\n\n    def __init__(self, **kwargs):\n        # XXX move to style.kv\n        kwargs.setdefault('size_hint', (None, None))\n        kwargs.setdefault('scale_min', .4)\n        kwargs.setdefault('scale_max', 1.6)\n        kwargs.setdefault('size', (700, 200))\n        kwargs.setdefault('docked', False)\n        self._trigger_update_layout_mode = Clock.create_trigger(\n            self._update_layout_mode)\n        self._trigger_load_layouts = Clock.create_trigger(\n            self._load_layouts)\n        self._trigger_load_layout = Clock.create_trigger(\n            self._load_layout)\n        self.bind(\n            docked=self.setup_mode,\n            have_shift=self._trigger_update_layout_mode,\n            have_capslock=self._trigger_update_layout_mode,\n            have_special=self._trigger_update_layout_mode,\n            layout_path=self._trigger_load_layouts,\n            layout=self._trigger_load_layout)\n        super(VKeyboard, self).__init__(**kwargs)\n\n        # load all the layouts found in the layout_path directory\n        self._load_layouts()\n\n        # ensure we have default layouts\n        available_layouts = self.available_layouts\n        if not available_layouts:\n            Logger.critical('VKeyboard: unable to load default layouts')\n\n        # load the default layout from configuration\n        if self.layout is None:\n            self.layout = Config.get('kivy', 'keyboard_layout')\n        else:\n            # ensure the current layout is found on the available layout\n            self._trigger_load_layout()\n\n        # update layout mode (shift or normal)\n        self._trigger_update_layout_mode()\n\n        # create a top layer to draw active keys on\n        with self.canvas:\n            self.background_key_layer = Canvas()\n            self.active_keys_layer = Canvas()\n\n    def on_disabled(self, intance, value):\n        self.refresh_keys()\n\n    def _update_layout_mode(self, *l):\n        # update mode according to capslock and shift key\n        mode = self.have_capslock != self.have_shift\n        mode = 'shift' if mode else 'normal'\n        if self.have_special:\n            mode = \"special\"\n        if mode != self.layout_mode:\n            self.layout_mode = mode\n            self.refresh(False)\n\n    def _load_layout(self, *largs):\n        # ensure new layouts are loaded first\n        if self._trigger_load_layouts.is_triggered:\n            self._load_layouts()\n            self._trigger_load_layouts.cancel()\n\n        value = self.layout\n        available_layouts = self.available_layouts\n\n        # it's a filename, try to load it directly\n        if self.layout[-5:] == '.json':\n            if value not in available_layouts:\n                fn = resource_find(self.layout)\n                self._load_layout_fn(fn, self.layout)\n\n        if not available_layouts:\n            return\n        if value not in available_layouts and value != 'qwerty':\n            Logger.error(\n                'Vkeyboard: <%s> keyboard layout mentioned in '\n                'conf file was not found, fallback on qwerty' %\n                value)\n            self.layout = 'qwerty'\n        self.refresh(True)\n\n    def _load_layouts(self, *largs):\n        # first load available layouts from json files\n        # XXX fix to be able to reload layout when path is changing\n        value = self.layout_path\n        for fn in listdir(value):\n            self._load_layout_fn(join(value, fn),\n                                 basename(splitext(fn)[0]))\n\n    def _load_layout_fn(self, fn, name):\n        available_layouts = self.available_layouts\n        if fn[-5:] != '.json':\n            return\n        with open(fn, 'r') as fd:\n            json_content = fd.read()\n            layout = loads(json_content)\n        available_layouts[name] = layout\n\n    def setup_mode(self, *largs):\n        '''Call this method when you want to readjust the keyboard according to\n        options: :attr:`docked` or not, with attached :attr:`target` or not:\n\n        * If :attr:`docked` is True, it will call :meth:`setup_mode_dock`\n        * If :attr:`docked` is False, it will call :meth:`setup_mode_free`\n\n        Feel free to overload these methods to create new\n        positioning behavior.\n        '''\n        if self.docked:\n            self.setup_mode_dock()\n        else:\n            self.setup_mode_free()\n\n    def setup_mode_dock(self, *largs):\n        '''Setup the keyboard in docked mode.\n\n        Dock mode will reset the rotation, disable translation, rotation and\n        scale. Scale and position will be automatically adjusted to attach the\n        keyboard to the bottom of the screen.\n\n        .. note::\n            Don't call this method directly, use :meth:`setup_mode` instead.\n        '''\n        self.do_translation = False\n        self.do_rotation = False\n        self.do_scale = False\n        self.rotation = 0\n        win = self.get_parent_window()\n        scale = win.width / float(self.width)\n        self.scale = scale\n        self.pos = 0, 0\n        win.bind(on_resize=self._update_dock_mode)\n\n    def _update_dock_mode(self, win, *largs):\n        scale = win.width / float(self.width)\n        self.scale = scale\n        self.pos = 0, 0\n\n    def setup_mode_free(self):\n        '''Setup the keyboard in free mode.\n\n        Free mode is designed to let the user control the position and\n        orientation of the keyboard. The only real usage is for a multiuser\n        environment, but you might found other ways to use it.\n        If a :attr:`target` is set, it will place the vkeyboard under the\n        target.\n\n        .. note::\n            Don't call this method directly, use :meth:`setup_mode` instead.\n        '''\n        self.do_translation = True\n        self.do_rotation = True\n        self.do_scale = True\n        target = self.target\n        if not target:\n            return\n\n        # NOTE all math will be done in window point of view\n        # determine rotation of the target\n        a = Vector(1, 0)\n        b = Vector(target.to_window(0, 0))\n        c = Vector(target.to_window(1, 0)) - b\n        self.rotation = -a.angle(c)\n\n        # determine the position of center/top of the keyboard\n        dpos = Vector(self.to_window(self.width / 2., self.height))\n\n        # determine the position of center/bottom of the target\n        cpos = Vector(target.to_window(target.center_x, target.y))\n\n        # the goal now is to map both point, calculate the diff between them\n        diff = dpos - cpos\n\n        # we still have an issue, self.pos represent the bounding box,\n        # not the 0,0 coordinate of the scatter. we need to apply also\n        # the diff between them (inside and outside coordinate matrix).\n        # It's hard to explain, but do a scheme on a paper, write all\n        # the vector i'm calculating, and you'll understand. :)\n        diff2 = Vector(self.x + self.width / 2., self.y + self.height) - \\\n            Vector(self.to_parent(self.width / 2., self.height))\n        diff -= diff2\n\n        # now we have a good \"diff\", set it as a pos.\n        self.pos = -diff\n\n    def change_layout(self):\n        # XXX implement popup with all available layouts\n        pass\n\n    def refresh(self, force=False):\n        '''(internal) Recreate the entire widget and graphics according to the\n        selected layout.\n        '''\n        self.clear_widgets()\n        if force:\n            self.refresh_keys_hint()\n        self.refresh_keys()\n        self.refresh_active_keys_layer()\n\n    def refresh_active_keys_layer(self):\n        self.active_keys_layer.clear()\n\n        active_keys = self.active_keys\n        layout_geometry = self.layout_geometry\n        background = resource_find(self.key_background_down)\n        texture = Image(background, mipmap=True).texture\n\n        with self.active_keys_layer:\n            Color(1, 1, 1)\n            for line_nb, index in active_keys.values():\n                pos, size = layout_geometry['LINE_%d' % line_nb][index]\n                BorderImage(texture=texture, pos=pos, size=size,\n                            border=self.key_border)\n\n    def refresh_keys_hint(self):\n        layout = self.available_layouts[self.layout]\n        layout_cols = layout['cols']\n        layout_rows = layout['rows']\n        layout_geometry = self.layout_geometry\n        mtop, mright, mbottom, mleft = self.margin_hint\n\n        # get relative EFFICIENT surface of the layout without external margins\n        el_hint = 1. - mleft - mright\n        eh_hint = 1. - mtop - mbottom\n        ex_hint = 0 + mleft\n        ey_hint = 0 + mbottom\n\n        # get relative unit surface\n        uw_hint = (1. / layout_cols) * el_hint\n        uh_hint = (1. / layout_rows) * eh_hint\n        layout_geometry['U_HINT'] = (uw_hint, uh_hint)\n\n        # calculate individual key RELATIVE surface and pos (without key\n        # margin)\n        current_y_hint = ey_hint + eh_hint\n        for line_nb in range(1, layout_rows + 1):\n            current_y_hint -= uh_hint\n            # get line_name\n            line_name = '%s_%d' % (self.layout_mode, line_nb)\n            line_hint = 'LINE_HINT_%d' % line_nb\n            layout_geometry[line_hint] = []\n            current_x_hint = ex_hint\n            # go through the list of keys (tuples of 4)\n            for key in layout[line_name]:\n                # calculate relative pos, size\n                layout_geometry[line_hint].append([\n                    (current_x_hint, current_y_hint),\n                    (key[3] * uw_hint, uh_hint)])\n                current_x_hint += key[3] * uw_hint\n\n        self.layout_geometry = layout_geometry\n\n    def refresh_keys(self):\n        layout = self.available_layouts[self.layout]\n        layout_rows = layout['rows']\n        layout_geometry = self.layout_geometry\n        w, h = self.size\n        kmtop, kmright, kmbottom, kmleft = self.key_margin\n        uw_hint, uh_hint = layout_geometry['U_HINT']\n\n        for line_nb in range(1, layout_rows + 1):\n            llg = layout_geometry['LINE_%d' % line_nb] = []\n            llg_append = llg.append\n            for key in layout_geometry['LINE_HINT_%d' % line_nb]:\n                x_hint, y_hint = key[0]\n                w_hint, h_hint = key[1]\n                kx = x_hint * w\n                ky = y_hint * h\n                kw = w_hint * w\n                kh = h_hint * h\n\n                # now adjust, considering the key margin\n                kx = int(kx + kmleft)\n                ky = int(ky + kmbottom)\n                kw = int(kw - kmleft - kmright)\n                kh = int(kh - kmbottom - kmtop)\n\n                pos = (kx, ky)\n                size = (kw, kh)\n                llg_append((pos, size))\n\n        self.layout_geometry = layout_geometry\n        self.draw_keys()\n\n    def draw_keys(self):\n        layout = self.available_layouts[self.layout]\n        layout_rows = layout['rows']\n        layout_geometry = self.layout_geometry\n        layout_mode = self.layout_mode\n\n        # draw background\n        w, h = self.size\n\n        background = resource_find(self.background_disabled\n                                   if self.disabled else\n                                   self.background)\n        texture = Image(background, mipmap=True).texture\n        self.background_key_layer.clear()\n        with self.background_key_layer:\n            Color(*self.background_color)\n            BorderImage(texture=texture, size=self.size,\n                        border=self.background_border)\n\n        # XXX seperate drawing the keys and the fonts to avoid\n        # XXX reloading the texture each time\n\n        # first draw keys without the font\n        key_normal = resource_find(self.key_background_disabled_normal\n                                   if self.disabled else\n                                   self.key_background_normal)\n        texture = Image(key_normal, mipmap=True).texture\n        with self.background_key_layer:\n            for line_nb in range(1, layout_rows + 1):\n                for pos, size in layout_geometry['LINE_%d' % line_nb]:\n                        BorderImage(texture=texture, pos=pos, size=size,\n                                    border=self.key_border)\n\n        # then draw the text\n        # calculate font_size\n        font_size = int(w) / 46\n        # draw\n        for line_nb in range(1, layout_rows + 1):\n            key_nb = 0\n            for pos, size in layout_geometry['LINE_%d' % line_nb]:\n                # retrieve the relative text\n                text = layout[layout_mode + '_' + str(line_nb)][key_nb][0]\n                l = Label(text=text, font_size=font_size, pos=pos, size=size,\n                          font_name=self.font_name)\n                self.add_widget(l)\n                key_nb += 1\n\n    def on_key_down(self, *largs):\n        pass\n\n    def on_key_up(self, *largs):\n        pass\n\n    def on_textinput(self, *largs):\n        pass\n\n    def get_key_at_pos(self, x, y):\n        w, h = self.size\n        x_hint = x / w\n        # focus on the surface without margins\n        layout_geometry = self.layout_geometry\n        layout = self.available_layouts[self.layout]\n        layout_rows = layout['rows']\n        mtop, mright, mbottom, mleft = self.margin_hint\n\n        # get the line of the layout\n        e_height = h - (mbottom + mtop) * h  # efficient height in pixels\n        line_height = e_height / layout_rows  # line height in px\n        y = y - mbottom * h\n        line_nb = layout_rows - int(y / line_height)\n\n        if line_nb > layout_rows:\n            line_nb = layout_rows\n        if line_nb < 1:\n            line_nb = 1\n\n        # get the key within the line\n        key_index = ''\n        current_key_index = 0\n        for key in layout_geometry['LINE_HINT_%d' % line_nb]:\n            if x_hint >= key[0][0] and x_hint < key[0][0] + key[1][0]:\n                key_index = current_key_index\n                break\n            else:\n                current_key_index += 1\n        if key_index == '':\n            return None\n\n        # get the full character\n        key = layout['%s_%d' % (self.layout_mode, line_nb)][key_index]\n\n        return [key, (line_nb, key_index)]\n\n    def collide_margin(self, x, y):\n        '''Do a collision test, and return True if the (x, y) is inside the\n        vkeyboard margin.\n        '''\n        mtop, mright, mbottom, mleft = self.margin_hint\n        x_hint = x / self.width\n        y_hint = y / self.height\n        if x_hint > mleft and x_hint < 1. - mright \\\n                and y_hint > mbottom and y_hint < 1. - mtop:\n            return False\n        return True\n\n    def process_key_on(self, touch):\n        x, y = self.to_local(*touch.pos)\n        key = self.get_key_at_pos(x, y)\n        if not key:\n            return\n\n        key_data = key[0]\n        displayed_char, internal, special_char, size = key_data\n        line_nb, key_index = key[1]\n\n        # save pressed key on the touch\n        ud = touch.ud[self.uid] = {}\n        ud['key'] = key\n\n        # for caps lock or shift only:\n        uid = touch.uid\n        if special_char is not None:\n            # Do not repeat special keys\n            if special_char in ('capslock', 'shift', 'layout', 'special'):\n                Clock.unschedule(self._start_repeat_key)\n                self.repeat_touch = None\n            if special_char == 'capslock':\n                self.have_capslock = not self.have_capslock\n                uid = -1\n            elif special_char == 'shift':\n                self.have_shift = True\n            elif special_char == 'special':\n                self.have_special = True\n            elif special_char == 'layout':\n                self.change_layout()\n\n        # send info to the bus\n        b_keycode = special_char\n        b_modifiers = self._get_modifiers()\n        if self.get_parent_window().__class__.__module__ == \\\n            'kivy.core.window.window_sdl2' and internal:\n            self.dispatch('on_textinput', internal)\n        else:\n            self.dispatch('on_key_down', b_keycode, internal, b_modifiers)\n\n        # save key as an active key for drawing\n        self.active_keys[uid] = key[1]\n        self.refresh_active_keys_layer()\n\n    def process_key_up(self, touch):\n        uid = touch.uid\n        if self.uid not in touch.ud:\n            return\n\n        # save pressed key on the touch\n        key_data, key = touch.ud[self.uid]['key']\n        displayed_char, internal, special_char, size = key_data\n\n        # send info to the bus\n        b_keycode = special_char\n        b_modifiers = self._get_modifiers()\n        self.dispatch('on_key_up', b_keycode, internal, b_modifiers)\n\n        if special_char == 'capslock':\n            uid = -1\n\n        if uid in self.active_keys:\n            self.active_keys.pop(uid, None)\n            if special_char == 'shift':\n                self.have_shift = False\n            elif special_char == 'special':\n                self.have_special = False\n            if special_char == 'capslock' and self.have_capslock:\n                self.active_keys[-1] = key\n            self.refresh_active_keys_layer()\n\n    def _get_modifiers(self):\n        ret = []\n        if self.have_shift:\n            ret.append('shift')\n        if self.have_capslock:\n            ret.append('capslock')\n        return ret\n\n    def _start_repeat_key(self, *kwargs):\n        Clock.schedule_interval(self._repeat_key, 0.05)\n\n    def _repeat_key(self, *kwargs):\n        self.process_key_on(self.repeat_touch)\n\n    def on_touch_down(self, touch):\n        x, y = touch.pos\n        if not self.collide_point(x, y):\n            return\n        if self.disabled:\n            return True\n\n        x, y = self.to_local(x, y)\n        if not self.collide_margin(x, y):\n            if self.repeat_touch is None:\n                Clock.schedule_once(self._start_repeat_key, 0.5)\n            self.repeat_touch = touch\n\n            self.process_key_on(touch)\n            touch.grab(self, exclusive=True)\n\n        else:\n            super(VKeyboard, self).on_touch_down(touch)\n        return True\n\n    def on_touch_up(self, touch):\n        if touch.grab_current is self:\n            self.process_key_up(touch)\n\n            Clock.unschedule(self._start_repeat_key)\n            if touch == self.repeat_touch:\n                Clock.unschedule(self._repeat_key)\n                self.repeat_touch = None\n\n        return super(VKeyboard, self).on_touch_up(touch)\n\n\nif __name__ == '__main__':\n    from kivy.base import runTouchApp\n    vk = VKeyboard(layout='azerty')\n    runTouchApp(vk)\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/uix/widget.py",
    "content": "'''\nWidget class\n============\n\nThe :class:`Widget` class is the base class required to create a Widget.\nThis widget class is designed with a couple of principles in mind:\n\n    Event Driven\n        Widget interaction is built on top of events that occur. If a property\n        changes, the widget can respond to the change in the 'on_<propname>'\n        callback. If nothing changes, nothing will be done. That's the main\n        goal of the :class:`~kivy.properties.Property` class.\n\n    Separate the widget and its graphical representation\n        Widgets don't have a `draw()` method. This is done on purpose: The idea\n        is to allow you to create your own graphical representation outside the\n        widget class.\n        Obviously you can still use all the available properties to do that, so\n        that your representation properly reflects the widget's current state.\n        Every widget has its own :class:`~kivy.graphics.Canvas` that you\n        can use to draw. This separation allows Kivy to run your\n        application in a very efficient manner.\n\n    Bounding Box / Collision\n        Often you want to know if a certain point is within the bounds of your\n        widget. An example would be a button widget where you want to only\n        trigger an action when the button itself is actually touched.\n        For this, you can use the :meth:`Widget.collide_point` method, which\n        will return True if the point you pass to it is inside the axis-aligned\n        bounding box defined by the widget's position and size.\n        If a simple AABB is not sufficient, you can override the method to\n        perform the collision checks with more complex shapes, e.g. a polygon.\n        You can also check if a widget collides with another widget with\n        :meth:`Widget.collide_widget`.\n\n\nWe also have some default values and behaviors that you should be aware of:\n\n* A :class:`Widget` is not a :class:`~kivy.uix.layout.Layout`: it will not\n  change the position or the size of its children. If you want control over\n  positioning or sizing, use a :class:`~kivy.uix.layout.Layout`.\n\n* The default size of a widget is (100, 100). This is only changed if the\n  parent is a :class:`~kivy.uix.layout.Layout`.\n  For example, if you add a :class:`Label` inside a\n  :class:`Button`, the label will not inherit the button's size or position\n  because the button is not a *Layout*: it's just another *Widget*.\n\n* The default size_hint is (1, 1). If the parent is a :class:`Layout`, then the\n  widget size will be the parent layout's size.\n\n* :meth:`Widget.on_touch_down`, :meth:`Widget.on_touch_move`,\n  :meth:`Widget.on_touch_up` don't do any sort of collisions. If you want to\n  know if the touch is inside your widget, use :meth:`Widget.collide_point`.\n\nUsing Properties\n----------------\n\nWhen you read the documentation, all properties are described in the format::\n\n    <name> is a <property class> and defaults to <default value>.\n\ne.g.\n\n    :attr:`~kivy.uix.label.Label.text` is a\n    :class:`~kivy.properties.StringProperty` and defaults to ''.\n\nIf you want to be notified when the pos attribute changes, i.e. when the\nwidget moves, you can bind your own callback function like this::\n\n    def callback_pos(instance, value):\n        print('The widget', instance, 'moved to', value)\n\n    wid = Widget()\n    wid.bind(pos=callback_pos)\n\nRead more about :doc:`/api-kivy.properties`.\n\nBasic drawing\n-------------\n\nWidgets support a range of drawing instructions that you can use to customize\nthe look of your widgets and layouts. For example, to draw a background image\nfor your widget, you can do the following:\n\n.. code-block:: python\n\n    def redraw(self, args):\n        self.bg_rect.size = self.size\n        self.bg_rect.pos = self.pos\n\n    widget = Widget()\n    with widget.canvas:\n        widget.bg_rect = Rectangle(source=\"cover.jpg\", pos=self.pos, \\\nsize=self.size)\n    widget.bind(pos=redraw, size=redraw)\n\nTo draw a background in kv::\n\n    Widget:\n        canvas:\n            Rectangle:\n                source: \"cover.jpg\"\n                size: self.size\n                pos: self.pos\n\nThese examples only scratch the surface. Please see the :mod:`kivy.graphics`\ndocumentation for more information.\n\n.. _widget-event-bubbling:\n\nWidget touch event bubbling\n---------------------------\n\nWhen you catch touch events between multiple widgets, you often\nneed to be aware of the order in which these events are propogated. In Kivy,\nevents bubble up from the most recently added widget and then backwards through\nits children (from the most recently added back to the first child). This order\nis the same for the `on_touch_move` and `on_touch_up` events.\n\nIf you want to reverse this order, you can raise events in the children before\nthe parent by using the `super` command. For example:\n\n.. code-block:: python\n\n    class MyWidget(Widget):\n        def on_touch_down(self, touch):\n            super(MyWidget, self).on_touch_down(touch)\n            # Do stuff here\n\nIn general, this would seldom be the best approach as every event bubbles all\nthe way through event time and there is no way of determining if it has been\nhandled. In order to stop this event bubbling, one of these methods must\nreturn `True`. At this point, Kivy assumes the event has been handled and the\npropogation stops.\n\nThis means that the recommended approach is to let the event bubble naturally\nbut swallow the event if it has been handled. For example:\n\n.. code-block:: python\n\n    class MyWidget(Widget):\n        def on_touch_down(self, touch):\n            If <some_condition>:\n                # Do stuff here and kill the event\n                return True\n            else:\n                # Continue normal event bubbling\n                return super(MyWidget, self).on_touch_down(touch)\n\nThis approach gives you good control over exactly how events are dispatched\nand managed. Sometimes, however, you may wish to let the event be completely\npropogated before taking action. You can use the\n:class:`~kivy.clock.Clock` to help you here:\n\n.. code-block:: python\n\n    class MyLabel(Label):\n        def on_touch_down(self, touch, after=False):\n            if after:\n                print \"Fired after the event has been dispatched!\"\n            else:\n                Clock.schedule_once(lambda dt: self.on_touch_down(touch, True))\n                return super(MyLabel, self).on_touch_down(touch)\n\n'''\nfrom kivy.graphics.transformation import Matrix\n\n__all__ = ('Widget', 'WidgetException')\n\nfrom kivy.event import EventDispatcher\nfrom kivy.factory import Factory\nfrom kivy.properties import (NumericProperty, StringProperty, AliasProperty,\n                             ReferenceListProperty, ObjectProperty,\n                             ListProperty, DictProperty, BooleanProperty)\nfrom kivy.graphics import (Canvas, Translate, Fbo, ClearColor, ClearBuffers,\n                            Scale)\nfrom kivy.base import EventLoop\nfrom kivy.lang import Builder\nfrom kivy.context import get_current_context\nfrom kivy.weakproxy import WeakProxy\nfrom functools import partial\nfrom itertools import islice\n\n\n# References to all the widget destructors (partial method with widget uid as\n# key).\n_widget_destructors = {}\n\n\ndef _widget_destructor(uid, r):\n    # Internal method called when a widget is deleted from memory. the only\n    # thing we remember about it is its uid. Clear all the associated callbacks\n    # created in kv language.\n    del _widget_destructors[uid]\n    Builder.unbind_widget(uid)\n\n\nclass WidgetException(Exception):\n    '''Fired when the widget gets an exception.\n    '''\n    pass\n\n\nclass WidgetMetaclass(type):\n    '''Metaclass to automatically register new widgets for the\n    :class:`~kivy.factory.Factory`.\n\n    .. warning::\n        This metaclass is used by the Widget. Do not use it directly!\n    '''\n    def __init__(mcs, name, bases, attrs):\n        super(WidgetMetaclass, mcs).__init__(name, bases, attrs)\n        Factory.register(name, cls=mcs)\n\n\n#: Base class used for Widget, that inherits from :class:`EventDispatcher`\nWidgetBase = WidgetMetaclass('WidgetBase', (EventDispatcher, ), {})\n\n\nclass Widget(WidgetBase):\n    '''Widget class. See module documentation for more information.\n\n    :Events:\n        `on_touch_down`:\n            Fired when a new touch event occurs\n        `on_touch_move`:\n            Fired when an existing touch moves\n        `on_touch_up`:\n            Fired when an existing touch disappears\n\n    .. warning::\n        Adding a `__del__` method to a class derived from Widget with Python\n        prior to 3.4 will disable automatic garbage collection for instances\n        of that class. This is because the Widget class creates reference\n        cycles, thereby `preventing garbage collection\n        <https://docs.python.org/2/library/gc.html#gc.garbage>`_.\n\n    .. versionchanged:: 1.0.9\n        Everything related to event properties has been moved to the\n        :class:`~kivy.event.EventDispatcher`. Event properties can now be used\n        when contructing a simple class without subclassing :class:`Widget`.\n\n    .. versionchanged:: 1.5.0\n        The constructor now accepts on_* arguments to automatically bind\n        callbacks to properties or events, as in the Kv language.\n    '''\n\n    __metaclass__ = WidgetMetaclass\n    __events__ = ('on_touch_down', 'on_touch_move', 'on_touch_up')\n    _proxy_ref = None\n\n    def __init__(self, **kwargs):\n        # Before doing anything, ensure the windows exist.\n        EventLoop.ensure_window()\n\n        # Assign the default context of the widget creation.\n        if not hasattr(self, '_context'):\n            self._context = get_current_context()\n\n        super(Widget, self).__init__(**kwargs)\n\n        # Create the default canvas if it does not exist.\n        if self.canvas is None:\n            self.canvas = Canvas(opacity=self.opacity)\n\n        # Apply all the styles.\n        if '__no_builder' not in kwargs:\n            #current_root = Builder.idmap.get('root')\n            #Builder.idmap['root'] = self\n            Builder.apply(self)\n            #if current_root is not None:\n            #    Builder.idmap['root'] = current_root\n            #else:\n            #    Builder.idmap.pop('root')\n\n        # Bind all the events.\n        for argument in kwargs:\n            if argument[:3] == 'on_':\n                self.bind(**{argument: kwargs[argument]})\n\n    @property\n    def proxy_ref(self):\n        '''Return a proxy reference to the widget, i.e. without creating a\n        reference to the widget. See `weakref.proxy\n        <http://docs.python.org/2/library/weakref.html?highlight\\\n        =proxy#weakref.proxy>`_ for more information.\n\n        .. versionadded:: 1.7.2\n        '''\n        _proxy_ref = self._proxy_ref\n        if _proxy_ref is not None:\n            return _proxy_ref\n\n        f = partial(_widget_destructor, self.uid)\n        self._proxy_ref = _proxy_ref = WeakProxy(self, f)\n        # Only f should be enough here, but it appears that is a very\n        # specific case, the proxy destructor is not called if both f and\n        # _proxy_ref are not together in a tuple.\n        _widget_destructors[self.uid] = (f, _proxy_ref)\n        return _proxy_ref\n\n    def __hash__(self):\n        return id(self)\n\n    @property\n    def __self__(self):\n        return self\n\n    #\n    # Collision\n    #\n    def collide_point(self, x, y):\n        '''Check if a point (x, y) is inside the widget's axis aligned bounding\n        box.\n\n        :Parameters:\n            `x`: numeric\n                X position of the point (in window coordinates)\n            `y`: numeric\n                Y position of the point (in window coordinates)\n\n        :Returns:\n            bool, True if the point is inside the bounding box.\n\n    .. code-block:: python\n\n        >>> Widget(pos=(10, 10), size=(50, 50)).collide_point(40, 40)\n        True\n        '''\n        return self.x <= x <= self.right and self.y <= y <= self.top\n\n    def collide_widget(self, wid):\n        '''Check if the other widget collides with this widget.\n        Performs an axis-aligned bounding box intersection test by default.\n\n        :Parameters:\n            `wid`: :class:`Widget` class\n                Widget to collide with.\n\n        :Returns:\n            bool, True if the other widget collides with this widget.\n\n    .. code-block:: python\n\n        >>> wid = Widget(size=(50, 50))\n        >>> wid2 = Widget(size=(50, 50), pos=(25, 25))\n        >>> wid.collide_widget(wid2)\n        True\n        >>> wid2.pos = (55, 55)\n        >>> wid.collide_widget(wid2)\n        False\n        '''\n        if self.right < wid.x:\n            return False\n        if self.x > wid.right:\n            return False\n        if self.top < wid.y:\n            return False\n        if self.y > wid.top:\n            return False\n        return True\n\n    #\n    # Default event handlers\n    #\n    def on_touch_down(self, touch):\n        '''Receive a touch down event.\n\n        :Parameters:\n            `touch`: :class:`~kivy.input.motionevent.MotionEvent` class\n                Touch received. The touch is in parent coordinates. See\n                :mod:`~kivy.uix.relativelayout` for a discussion on\n                coordinate systems.\n\n        :Returns:\n            bool. If True, the dispatching of the touch event will stop.\n        '''\n        if self.disabled and self.collide_point(*touch.pos):\n            return True\n        for child in self.children[:]:\n            if child.dispatch('on_touch_down', touch):\n                return True\n\n    def on_touch_move(self, touch):\n        '''Receive a touch move event. The touch is in parent coordinates.\n\n        See :meth:`on_touch_down` for more information.\n        '''\n        if self.disabled:\n            return\n        for child in self.children[:]:\n            if child.dispatch('on_touch_move', touch):\n                return True\n\n    def on_touch_up(self, touch):\n        '''Receive a touch up event. The touch is in parent coordinates.\n\n        See :meth:`on_touch_down` for more information.\n        '''\n        if self.disabled:\n            return\n        for child in self.children[:]:\n            if child.dispatch('on_touch_up', touch):\n                return True\n\n    def on_disabled(self, instance, value):\n        for child in self.children:\n            child.disabled = value\n\n    #\n    # Tree management\n    #\n    def add_widget(self, widget, index=0, canvas=None):\n        '''Add a new widget as a child of this widget.\n\n        :Parameters:\n            `widget`: :class:`Widget`\n                Widget to add to our list of children.\n            `index`: int, defaults to 0\n                Index to insert the widget in the list.\n\n                .. versionadded:: 1.0.5\n            `canvas`: str, defaults to None\n                Canvas to add widget's canvas to. Can be 'before', 'after' or\n                None for the default canvas.\n\n                .. versionadded:: 1.9.0\n\n    .. code-block:: python\n\n        >>> from kivy.uix.button import Button\n        >>> from kivy.uix.slider import Slider\n        >>> root = Widget()\n        >>> root.add_widget(Button())\n        >>> slider = Slider()\n        >>> root.add_widget(slider)\n\n        '''\n        if not isinstance(widget, Widget):\n            raise WidgetException(\n                'add_widget() can be used only with instances'\n                ' of the Widget class.')\n\n        widget = widget.__self__\n        if widget is self:\n            raise WidgetException(\n                'Widget instances cannot be added to themselves.')\n        parent = widget.parent\n        # Check if the widget is already a child of another widget.\n        if parent:\n            raise WidgetException('Cannot add %r, it already has a parent %r'\n                                  % (widget, parent))\n        widget.parent = parent = self\n        # Child will be disabled if added to a disabled parent.\n        if parent.disabled:\n            widget.disabled = True\n\n        canvas = self.canvas.before if canvas == 'before' else \\\n            self.canvas.after if canvas == 'after' else self.canvas\n\n        if index == 0 or len(self.children) == 0:\n            self.children.insert(0, widget)\n            canvas.add(widget.canvas)\n        else:\n            canvas = self.canvas\n            children = self.children\n            if index >= len(children):\n                index = len(children)\n                next_index = 0\n            else:\n                next_child = children[index]\n                next_index = canvas.indexof(next_child.canvas)\n                if next_index == -1:\n                    next_index = canvas.length()\n                else:\n                    next_index += 1\n\n            children.insert(index, widget)\n            # We never want to insert widget _before_ canvas.before.\n            if next_index == 0 and canvas.has_before:\n                next_index = 1\n            canvas.insert(next_index, widget.canvas)\n\n    def remove_widget(self, widget):\n        '''Remove a widget from the children of this widget.\n\n        :Parameters:\n            `widget`: :class:`Widget`\n                Widget to remove from our children list.\n\n    .. code-block:: python\n\n        >>> from kivy.uix.button import Button\n        >>> root = Widget()\n        >>> button = Button()\n        >>> root.add_widget(button)\n        >>> root.remove_widget(button)\n        '''\n        if widget not in self.children:\n            return\n        self.children.remove(widget)\n        if widget.canvas in self.canvas.children:\n            self.canvas.remove(widget.canvas)\n        elif widget.canvas in self.canvas.after.children:\n            self.canvas.after.remove(widget.canvas)\n        elif widget.canvas in self.canvas.before.children:\n            self.canvas.before.remove(widget.canvas)\n        widget.parent = None\n\n    def clear_widgets(self, children=None):\n        '''Remove all widgets added to this widget.\n\n        .. versionchanged:: 1.8.0\n            `children` argument can be used to select the children we want to\n            remove. It should be a list of children (or filtered list) of the\n            current widget.\n        '''\n\n        if not children:\n            children = self.children\n        remove_widget = self.remove_widget\n        for child in children[:]:\n            remove_widget(child)\n\n    def export_to_png(self, filename, *args):\n        '''Saves an image of the widget and its children in png format at the\n        specified filename. Works by removing the widget canvas from its\n        parent, rendering to an :class:`~kivy.graphics.fbo.Fbo`, and calling\n        :meth:`~kivy.graphics.texture.Texture.save`.\n\n        .. note::\n\n            The image includes only this widget and its children. If you want\n            to include widgets elsewhere in the tree, you must call\n            :meth:`~Widget.export_to_png` from their common parent, or use\n            :meth:`~kivy.core.window.Window.screenshot` to capture the whole\n            window.\n\n        .. note::\n\n            The image will be saved in png format, you should include the\n            extension in your filename.\n\n        .. versionadded:: 1.9.0\n        '''\n\n        if self.parent is not None:\n            canvas_parent_index = self.parent.canvas.indexof(self.canvas)\n            self.parent.canvas.remove(self.canvas)\n\n        fbo = Fbo(size=self.size, with_stencilbuffer=True)\n\n        with fbo:\n            ClearColor(0, 0, 0, 1)\n            ClearBuffers()\n            Scale(1, -1, 1)\n            Translate(-self.x, -self.y - self.height, 0)\n\n        fbo.add(self.canvas)\n        fbo.draw()\n        fbo.texture.save(filename, flipped=False)\n        fbo.remove(self.canvas)\n\n        if self.parent is not None:\n            self.parent.canvas.insert(canvas_parent_index, self.canvas)\n\n        return True\n\n    def get_root_window(self):\n        '''Return the root window.\n\n        :Returns:\n            Instance of the root window. Can be a\n            :class:`~kivy.core.window.WindowBase` or\n            :class:`Widget`.\n        '''\n        if self.parent:\n            return self.parent.get_root_window()\n\n    def get_parent_window(self):\n        '''Return the parent window.\n\n        :Returns:\n            Instance of the parent window. Can be a\n            :class:`~kivy.core.window.WindowBase` or\n            :class:`Widget`.\n        '''\n        if self.parent:\n            return self.parent.get_parent_window()\n\n    def _walk(self, restrict=False, loopback=False, index=None):\n        # We pass index only when we are going on the parent\n        # so don't yield the parent as well.\n        if index is None:\n            index = len(self.children)\n            yield self\n\n        for child in reversed(self.children[:index]):\n            for walk_child in child._walk(restrict=True):\n                yield walk_child\n\n        # If we want to continue with our parent, just do it.\n        if not restrict:\n            parent = self.parent\n            try:\n                if parent is None or not isinstance(parent, Widget):\n                    raise ValueError\n                index = parent.children.index(self)\n            except ValueError:\n                # Self is root, if we want to loopback from the first element:\n                if not loopback:\n                    return\n                # If we started with root (i.e. index==None), then we have to\n                # start from root again, so we return self again. Otherwise, we\n                # never returned it, so return it now starting with it.\n                parent = self\n                index = None\n            for walk_child in parent._walk(loopback=loopback, index=index):\n                yield walk_child\n\n    def walk(self, restrict=False, loopback=False):\n        ''' Iterator that walks the widget tree starting with this widget and\n        goes forward returning widgets in the order in which layouts display\n        them.\n\n        :Parameters:\n            `restrict`: bool, defaults to False\n                If True, it will only iterate through the widget and its\n                children (or children of its children etc.). Defaults to False.\n            `loopback`: bool, defaults to False\n                If True, when the last widget in the tree is reached,\n                it'll loop back to the uppermost root and start walking until\n                we hit this widget again. Naturally, it can only loop back when\n                `restrict` is False. Defaults to False.\n\n        :return:\n            A generator that walks the tree, returning widgets in the\n            forward layout order.\n\n        For example, given a tree with the following structure::\n\n            GridLayout:\n                Button\n                BoxLayout:\n                    id: box\n                    Widget\n                    Button\n                Widget\n\n        walking this tree:\n\n        .. code-block:: python\n\n            >>> # Call walk on box with loopback True, and restrict False\n            >>> [type(widget) for widget in box.walk(loopback=True)]\n            [<class 'BoxLayout'>, <class 'Widget'>, <class 'Button'>,\n                <class 'Widget'>, <class 'GridLayout'>, <class 'Button'>]\n            >>> # Now with loopback False, and restrict False\n            >>> [type(widget) for widget in box.walk()]\n            [<class 'BoxLayout'>, <class 'Widget'>, <class 'Button'>,\n                <class 'Widget'>]\n            >>> # Now with restrict True\n            >>> [type(widget) for widget in box.walk(restrict=True)]\n            [<class 'BoxLayout'>, <class 'Widget'>, <class 'Button'>]\n\n        .. versionadded:: 1.9.0\n        '''\n        gen = self._walk(restrict, loopback)\n        yield next(gen)\n        for node in gen:\n            if node is self:\n                return\n            yield node\n\n    def _walk_reverse(self, loopback=False, go_up=False):\n        # process is walk up level, walk down its children tree, then walk up\n        # next level etc.\n        # default just walk down the children tree\n        root = self\n        index = 0\n        # we need to go up a level before walking tree\n        if go_up:\n            root = self.parent\n            try:\n                if root is None or not isinstance(root, Widget):\n                    raise ValueError\n                index = root.children.index(self) + 1\n            except ValueError:\n                if not loopback:\n                    return\n                index = 0\n                go_up = False\n                root = self\n\n        # now walk children tree starting with last-most child\n        for child in islice(root.children, index, None):\n            for walk_child in child._walk_reverse(loopback=loopback):\n                yield walk_child\n        # we need to return ourself last, in all cases\n        yield root\n\n        # if going up, continue walking up the parent tree\n        if go_up:\n            for walk_child in root._walk_reverse(loopback=loopback,\n                                                 go_up=go_up):\n                yield walk_child\n\n    def walk_reverse(self, loopback=False):\n        ''' Iterator that walks the widget tree backwards starting with the\n        widget before this, and going backwards returning widgets in the\n        reverse order in which layouts display them.\n\n        This walks in the opposite direction of :meth:`walk`, so a list of the\n        tree generated with :meth:`walk` will be in reverse order compared\n        to the list generated with this, provided `loopback` is True.\n\n        :Parameters:\n            `loopback`: bool, defaults to False\n                If True, when the uppermost root in the tree is\n                reached, it'll loop back to the last widget and start walking\n                back until after we hit widget again. Defaults to False.\n\n        :return:\n            A generator that walks the tree, returning widgets in the\n            reverse layout order.\n\n        For example, given a tree with the following structure::\n\n            GridLayout:\n                Button\n                BoxLayout:\n                    id: box\n                    Widget\n                    Button\n                Widget\n\n        walking this tree:\n\n        .. code-block:: python\n\n            >>> # Call walk on box with loopback True\n            >>> [type(widget) for widget in box.walk_reverse(loopback=True)]\n            [<class 'Button'>, <class 'GridLayout'>, <class 'Widget'>,\n                <class 'Button'>, <class 'Widget'>, <class 'BoxLayout'>]\n            >>> # Now with loopback False\n            >>> [type(widget) for widget in box.walk_reverse()]\n            [<class 'Button'>, <class 'GridLayout'>]\n            >>> forward = [w for w in box.walk(loopback=True)]\n            >>> backward = [w for w in box.walk_reverse(loopback=True)]\n            >>> forward == backward[::-1]\n            True\n\n        .. versionadded:: 1.9.0\n\n        '''\n        for node in self._walk_reverse(loopback=loopback, go_up=True):\n            yield node\n            if node is self:\n                return\n\n    def to_widget(self, x, y, relative=False):\n        '''Convert the given coordinate from window to local widget\n        coordinates. See :mod:`~kivy.uix.relativelayout` for details on the\n        coordinate systems.\n        '''\n        if self.parent:\n            x, y = self.parent.to_widget(x, y)\n        return self.to_local(x, y, relative=relative)\n\n    def to_window(self, x, y, initial=True, relative=False):\n        '''Transform local coordinates to window coordinates. See\n        :mod:`~kivy.uix.relativelayout` for details on the coordinate systems.\n        '''\n        if not initial:\n            x, y = self.to_parent(x, y, relative=relative)\n        if self.parent:\n            return self.parent.to_window(x, y, initial=False,\n                                         relative=relative)\n        return (x, y)\n\n    def to_parent(self, x, y, relative=False):\n        '''Transform local coordinates to parent coordinates. See\n        :mod:`~kivy.uix.relativelayout` for details on the coordinate systems.\n\n        :Parameters:\n            `relative`: bool, defaults to False\n                Change to True if you want to translate relative positions from\n                a widget to its parent coordinates.\n        '''\n        if relative:\n            return (x + self.x, y + self.y)\n        return (x, y)\n\n    def to_local(self, x, y, relative=False):\n        '''Transform parent coordinates to local coordinates. See\n        :mod:`~kivy.uix.relativelayout` for details on the coordinate systems.\n\n        :Parameters:\n            `relative`: bool, defaults to False\n                Change to True if you want to translate coordinates to\n                relative widget coordinates.\n        '''\n        if relative:\n            return (x - self.x, y - self.y)\n        return (x, y)\n\n    def _apply_transform(self, m):\n        return self.parent._apply_transform(m) if self.parent else m\n\n    def get_window_matrix(self, x=0, y=0):\n        '''Calculate the transformation matrix to convert between window and\n        widget coordinates.\n\n        :Parameters:\n            `x`: float, defaults to 0\n                Translates the matrix on the x axis.\n            `y`: float, defaults to 0\n                Translates the matrix on the y axis.\n        '''\n        m = Matrix()\n        m.translate(self.x + x, self.y + y, 0)\n        m = self._apply_transform(m)\n        return m\n\n    x = NumericProperty(0)\n    '''X position of the widget.\n\n    :attr:`x` is a :class:`~kivy.properties.NumericProperty` and defaults to 0.\n    '''\n\n    y = NumericProperty(0)\n    '''Y position of the widget.\n\n    :attr:`y` is a :class:`~kivy.properties.NumericProperty` and defaults to 0.\n    '''\n\n    width = NumericProperty(100)\n    '''Width of the widget.\n\n    :attr:`width` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 100.\n\n    .. warning::\n        Keep in mind that the `width` property is subject to layout logic and\n        that this has not yet happened at the time of the widget's `__init__`\n        method.\n    '''\n\n    height = NumericProperty(100)\n    '''Height of the widget.\n\n    :attr:`height` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 100.\n\n    .. warning::\n        Keep in mind that the `height` property is subject to layout logic and\n        that this has not yet happened at the time of the widget's `__init__`\n        method.\n    '''\n\n    pos = ReferenceListProperty(x, y)\n    '''Position of the widget.\n\n    :attr:`pos` is a :class:`~kivy.properties.ReferenceListProperty` of\n    (:attr:`x`, :attr:`y`) properties.\n    '''\n\n    size = ReferenceListProperty(width, height)\n    '''Size of the widget.\n\n    :attr:`size` is a :class:`~kivy.properties.ReferenceListProperty` of\n    (:attr:`width`, :attr:`height`) properties.\n    '''\n\n    def get_right(self):\n        return self.x + self.width\n\n    def set_right(self, value):\n        self.x = value - self.width\n\n    right = AliasProperty(get_right, set_right, bind=('x', 'width'))\n    '''Right position of the widget.\n\n    :attr:`right` is an :class:`~kivy.properties.AliasProperty` of\n    (:attr:`x` + :attr:`width`).\n    '''\n\n    def get_top(self):\n        return self.y + self.height\n\n    def set_top(self, value):\n        self.y = value - self.height\n\n    top = AliasProperty(get_top, set_top, bind=('y', 'height'))\n    '''Top position of the widget.\n\n    :attr:`top` is an :class:`~kivy.properties.AliasProperty` of\n    (:attr:`y` + :attr:`height`).\n    '''\n\n    def get_center_x(self):\n        return self.x + self.width / 2.\n\n    def set_center_x(self, value):\n        self.x = value - self.width / 2.\n\n    center_x = AliasProperty(get_center_x, set_center_x, bind=('x', 'width'))\n    '''X center position of the widget.\n\n    :attr:`center_x` is an :class:`~kivy.properties.AliasProperty` of\n    (:attr:`x` + :attr:`width` / 2.).\n    '''\n\n    def get_center_y(self):\n        return self.y + self.height / 2.\n\n    def set_center_y(self, value):\n        self.y = value - self.height / 2.\n\n    center_y = AliasProperty(get_center_y, set_center_y, bind=('y', 'height'))\n    '''Y center position of the widget.\n\n    :attr:`center_y` is an :class:`~kivy.properties.AliasProperty` of\n    (:attr:`y` + :attr:`height` / 2.).\n    '''\n\n    center = ReferenceListProperty(center_x, center_y)\n    '''Center position of the widget.\n\n    :attr:`center` is a :class:`~kivy.properties.ReferenceListProperty` of\n    (:attr:`center_x`, :attr:`center_y`) properties.\n    '''\n\n    cls = ListProperty([])\n    '''Class of the widget, used for styling.\n    '''\n\n    id = StringProperty(None, allownone=True)\n    '''Unique identifier of the widget in the tree.\n\n    :attr:`id` is a :class:`~kivy.properties.StringProperty` and defaults to\n    None.\n\n    .. warning::\n\n        If the :attr:`id` is already used in the tree, an exception will\n        be raised.\n    '''\n\n    children = ListProperty([])\n    '''List of children of this widget.\n\n    :attr:`children` is a :class:`~kivy.properties.ListProperty` and\n    defaults to an empty list.\n\n    Use :meth:`add_widget` and :meth:`remove_widget` for manipulating the\n    children list. Don't manipulate the children list directly unless you know\n    what you are doing.\n    '''\n\n    parent = ObjectProperty(None, allownone=True)\n    '''Parent of this widget.\n\n    :attr:`parent` is an :class:`~kivy.properties.ObjectProperty` and\n    defaults to None.\n\n    The parent of a widget is set when the widget is added to another widget\n    and unset when the widget is removed from its parent.\n    '''\n\n    size_hint_x = NumericProperty(1, allownone=True)\n    '''X size hint. Represents how much space the widget should use in the\n    direction of the X axis relative to its parent's width.\n    Only the :class:`~kivy.uix.layout.Layout` and\n    :class:`~kivy.core.window.Window` classes make use of the hint.\n\n    The size_hint is used by layouts for two purposes:\n\n    - When the layout considers widgets on their own rather than in\n      relation to its other children, the size_hint_x is a direct proportion\n      of the parent width, normally between 0.0 and 1.0. For instance, a\n      widget with ``size_hint_x=0.5`` in\n      a vertical BoxLayout will take up half the BoxLayout's width, or\n      a widget in a FloatLayout with ``size_hint_x=0.2`` will take up 20%\n      of the FloatLayout width. If the size_hint is greater than 1, the\n      widget will be wider than the parent.\n    - When multiple widgets can share a row of a layout, such as in a\n      horizontal BoxLayout, their widths will be their size_hint_x as a\n      fraction of the sum of widget size_hints. For instance, if the\n      size_hint_xs are (0.5, 1.0, 0.5), the first widget will have a\n      width of 25% of the parent width.\n\n    :attr:`size_hint_x` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 1.\n    '''\n\n    size_hint_y = NumericProperty(1, allownone=True)\n    '''Y size hint.\n\n    :attr:`size_hint_y` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 1.\n\n    See :attr:`size_hint_x` for more information, but with widths and heights\n    swapped.\n    '''\n\n    size_hint = ReferenceListProperty(size_hint_x, size_hint_y)\n    '''Size hint.\n\n    :attr:`size_hint` is a :class:`~kivy.properties.ReferenceListProperty` of\n    (:attr:`size_hint_x`, :attr:`size_hint_y`) properties.\n\n    See :attr:`size_hint_x` for more information.\n    '''\n\n    pos_hint = ObjectProperty({})\n    '''Position hint. This property allows you to set the position of\n    the widget inside its parent layout, in percent (similar to\n    size_hint).\n\n    For example, if you want to set the top of the widget to be at 90%\n    height of its parent layout, you can write::\n\n        widget = Widget(pos_hint={'top': 0.9})\n\n    The keys 'x', 'right' and 'center_x' will use the parent width.\n    The keys 'y', 'top' and 'center_y' will use the parent height.\n\n    See :doc:`api-kivy.uix.floatlayout` for further reference.\n\n    .. note::\n        :attr:`pos_hint` is not used by all layouts. Check the documentation\n        of the layout in question to see if it supports pos_hint.\n\n    :attr:`pos_hint` is an :class:`~kivy.properties.ObjectProperty`\n    containing a dict.\n    '''\n\n    ids = DictProperty({})\n    '''This is a dictionary of ids defined in your kv language. This will only\n    be populated if you use ids in your kv language code.\n\n    .. versionadded:: 1.7.0\n\n    :attr:`ids` is a :class:`~kivy.properties.DictProperty` and defaults to an\n    empty dict {}.\n\n    The :attr:`ids` are populated for each root level widget definition. For\n    example::\n\n        # in kv\n        <MyWidget@Widget>:\n            id: my_widget\n            Label:\n                id: label_widget\n                Widget:\n                    id: inner_widget\n                    Label:\n                        id: inner_label\n            TextInput:\n                id: text_input\n            OtherWidget:\n                id: other_widget\n\n\n        <OtherWidget@Widget>\n            id: other_widget\n            Label:\n                id: other_label\n                TextInput:\n                    id: other_textinput\n\n    Then, in python:\n\n    .. code-block:: python\n\n        >>> widget = MyWidget()\n        >>> print(widget.ids)\n        {'other_widget': <weakproxy at 041CFED0 to OtherWidget at 041BEC38>,\n        'inner_widget': <weakproxy at 04137EA0 to Widget at 04138228>,\n        'inner_label': <weakproxy at 04143540 to Label at 04138260>,\n        'label_widget': <weakproxy at 04137B70 to Label at 040F97A0>,\n        'text_input': <weakproxy at 041BB5D0 to TextInput at 041BEC00>}\n        >>> print(widget.ids['other_widget'].ids)\n        {'other_textinput': <weakproxy at 041DBB40 to TextInput at 041BEF48>,\n        'other_label': <weakproxy at 041DB570 to Label at 041BEEA0>}\n        >>> print(widget.ids['label_widget'].ids)\n        {}\n    '''\n\n    opacity = NumericProperty(1.0)\n    '''Opacity of the widget and all its children.\n\n    .. versionadded:: 1.4.1\n\n    The opacity attribute controls the opacity of the widget and its children.\n    Be careful, it's a cumulative attribute: the value is multiplied by the\n    current global opacity and the result is applied to the current context\n    color.\n\n    For example, if the parent has an opacity of 0.5 and a child has an\n    opacity of 0.2, the real opacity of the child will be 0.5 * 0.2 = 0.1.\n\n    Then, the opacity is applied by the shader as:\n\n    .. code-block:: python\n\n        frag_color = color * vec4(1.0, 1.0, 1.0, opacity);\n\n    :attr:`opacity` is a :class:`~kivy.properties.NumericProperty` and defaults\n    to 1.0.\n    '''\n\n    def on_opacity(self, instance, value):\n        canvas = self.canvas\n        if canvas is not None:\n            canvas.opacity = value\n\n    canvas = None\n    '''Canvas of the widget.\n\n    The canvas is a graphics object that contains all the drawing instructions\n    for the graphical representation of the widget.\n\n    There are no general properties for the Widget class, such as background\n    color, to keep the design simple and lean. Some derived classes, such as\n    Button, do add such convenience properties but generally the developer is\n    responsible for implementing the graphics representation for a custom\n    widget from the ground up. See the derived widget classes for patterns to\n    follow and extend.\n\n    See :class:`~kivy.graphics.Canvas` for more information about the usage.\n    '''\n\n    disabled = BooleanProperty(False)\n    '''Indicates whether this widget can interact with input or not.\n\n    .. note::\n\n      1. Child Widgets, when added to a disabled widget, will be disabled\n         automatically.\n      2. Disabling/enabling a parent disables/enables all\n         of its children.\n\n    .. versionadded:: 1.8.0\n\n    :attr:`disabled` is a :class:`~kivy.properties.BooleanProperty` and\n    defaults to False.\n    '''\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/utils.py",
    "content": "# pylint: disable=W0611\n'''\nUtils\n=====\n\nThe Utils module provides a selection of general utility functions and classes\nthat may be useful for various applications. These include maths, color,\nalgebraic and platform functions.\n\n.. versionchanged:: 1.6.0\n    The OrderedDict class has been removed. Use collections.OrderedDict\n    instead.\n\n'''\n\n__all__ = ('intersection', 'difference', 'strtotuple',\n           'get_color_from_hex', 'get_hex_from_color', 'get_random_color',\n           'is_color_transparent', 'boundary',\n           'deprecated', 'SafeList',\n           'interpolate', 'QueryDict',\n           'platform', 'escape_markup', 'reify')\n\nfrom os import environ\nfrom sys import platform as _sys_platform\nfrom re import match, split\n\n\ndef boundary(value, minvalue, maxvalue):\n    '''Limit a value between a minvalue and maxvalue.'''\n    return min(max(value, minvalue), maxvalue)\n\n\ndef intersection(set1, set2):\n    '''Return the intersection of 2 lists.'''\n    return [s for s in set1 if s in set2]\n\n\ndef difference(set1, set2):\n    '''Return the difference between 2 lists.'''\n    return [s for s in set1 if s not in set2]\n\n\ndef interpolate(value_from, value_to, step=10):\n    '''Interpolate between two values. This can be useful for smoothing some\n    transitions. For example::\n\n        # instead of setting directly\n        self.pos = pos\n\n        # use interpolate, and you'll have a nicer transition\n        self.pos = interpolate(self.pos, new_pos)\n\n    .. warning::\n        These interpolations work only on lists/tuples/doubles with the same\n        dimensions. No test is done to check the dimensions are the same.\n    '''\n    if type(value_from) in (list, tuple):\n        out = []\n        for x, y in zip(value_from, value_to):\n            out.append(interpolate(x, y, step))\n        return out\n    else:\n        return value_from + (value_to - value_from) / float(step)\n\n\ndef strtotuple(s):\n    '''Convert a tuple string into a tuple\n    with some security checks. Designed to be used\n    with the eval() function::\n\n        a = (12, 54, 68)\n        b = str(a)         # return '(12, 54, 68)'\n        c = strtotuple(b)  # return (12, 54, 68)\n\n    '''\n    # security\n    if not match('^[,.0-9 ()\\[\\]]*$', s):\n        raise Exception('Invalid characters in string for tuple conversion')\n    # fast syntax check\n    if s.count('(') != s.count(')'):\n        raise Exception('Invalid count of ( and )')\n    if s.count('[') != s.count(']'):\n        raise Exception('Invalid count of [ and ]')\n    r = eval(s)\n    if type(r) not in (list, tuple):\n        raise Exception('Conversion failed')\n    return r\n\n\ndef get_color_from_hex(s):\n    '''Transform a hex string color to a kivy\n    :class:`~kivy.graphics.Color`.\n    '''\n    if s.startswith('#'):\n        return get_color_from_hex(s[1:])\n\n    value = [int(x, 16) / 255.\n             for x in split('([0-9a-f]{2})', s.lower()) if x != '']\n    if len(value) == 3:\n        value.append(1)\n    return value\n\n\ndef get_hex_from_color(color):\n    '''Transform a kivy :class:`~kivy.graphics.Color` to a hex value::\n\n        >>> get_hex_from_color((0, 1, 0))\n        '#00ff00'\n        >>> get_hex_from_color((.25, .77, .90, .5))\n        '#3fc4e57f'\n\n    .. versionadded:: 1.5.0\n    '''\n    return '#' + ''.join(['{0:02x}'.format(int(x * 255)) for x in color])\n\n\ndef get_random_color(alpha=1.0):\n    '''Returns a random color (4 tuple).\n\n    :Parameters:\n        `alpha` : float, defaults to 1.0\n            If alpha == 'random', a random alpha value is generated.\n    '''\n    from random import random\n    if alpha == 'random':\n        return [random(), random(), random(), random()]\n    else:\n        return [random(), random(), random(), alpha]\n\n\ndef is_color_transparent(c):\n    '''Return True if the alpha channel is 0.'''\n    if len(c) < 4:\n        return False\n    if float(c[3]) == 0.:\n        return True\n    return False\n\n\nDEPRECATED_CALLERS = []\n\n\ndef deprecated(func):\n    '''This is a decorator which can be used to mark functions\n    as deprecated. It will result in a warning being emitted the first time\n    the function is used.'''\n\n    import inspect\n    import functools\n\n    @functools.wraps(func)\n    def new_func(*args, **kwargs):\n        file, line, caller = inspect.stack()[1][1:4]\n        caller_id = \"%s:%s:%s\" % (file, line, caller)\n        # We want to print deprecated warnings only once:\n        if caller_id not in DEPRECATED_CALLERS:\n            DEPRECATED_CALLERS.append(caller_id)\n            warning = (\n                'Call to deprecated function %s in %s line %d.'\n                'Called from %s line %d'\n                ' by %s().' % (\n                    func.__name__,\n                    func.__code__.co_filename,\n                    func.__code__.co_firstlineno + 1,\n                    file, line, caller))\n            from kivy.logger import Logger\n            Logger.warn(warning)\n            if func.__doc__:\n                Logger.warn(func.__doc__)\n        return func(*args, **kwargs)\n    return new_func\n\n\nclass SafeList(list):\n    '''List with a clear() method.\n\n    .. warning::\n        Usage of the iterate() function will decrease your performance.\n    '''\n\n    def clear(self):\n        del self[:]\n\n    @deprecated\n    def iterate(self, reverse=False):\n        if reverse:\n            return iter(reversed(self))\n        return iter(self)\n\n\nclass QueryDict(dict):\n    '''QueryDict is a dict() that can be queried with dot.\n\n    .. versionadded:: 1.0.4\n\n  ::\n\n        d = QueryDict()\n        # create a key named toto, with the value 1\n        d.toto = 1\n        # it's the same as\n        d['toto'] = 1\n    '''\n\n    def __getattr__(self, attr):\n        try:\n            return self.__getitem__(attr)\n        except KeyError:\n            return super(QueryDict, self).__getattr__(attr)\n\n    def __setattr__(self, attr, value):\n        self.__setitem__(attr, value)\n\n\ndef format_bytes_to_human(size, precision=2):\n    '''Format a byte value to a human readable representation (B, KB, MB...).\n\n    .. versionadded:: 1.0.8\n\n    :Parameters:\n        `size`: int\n            Number that represents the bytes value\n        `precision`: int, defaults to 2\n            Precision after the comma\n\n    Examples::\n\n        >>> format_bytes_to_human(6463)\n        '6.31 KB'\n        >>> format_bytes_to_human(646368746541)\n        '601.98 GB'\n\n    '''\n    size = int(size)\n    fmt = '%%1.%df %%s' % precision\n    for unit in ['B', 'KB', 'MB', 'GB', 'TB']:\n        if size < 1024.0:\n            return fmt % (size, unit)\n        size /= 1024.0\n\n\nclass Platform(object):\n    # refactored to class to allow module function to be replaced\n    # with module variable\n\n    def __init__(self):\n        self._platform_ios = None\n        self._platform_android = None\n\n    @deprecated\n    def __call__(self):\n        return self._get_platform()\n\n    def __eq__(self, other):\n        return other == self._get_platform()\n\n    def __ne__(self, other):\n        return other != self._get_platform()\n\n    def __str__(self):\n        return self._get_platform()\n\n    def __repr__(self):\n        return 'platform name: \\'{platform}\\' from: \\n{instance}'.format(\n            platform=self._get_platform(),\n            instance=super(Platform, self).__repr__()\n        )\n\n    def __hash__(self):\n        return self._get_platform().__hash__()\n\n    def _get_platform(self):\n        if self._platform_android is None:\n            # ANDROID_ARGUMENT and ANDROID_PRIVATE are 2 environment variables\n            # from python-for-android project\n            self._platform_android = 'ANDROID_ARGUMENT' in environ\n\n        if self._platform_ios is None:\n            self._platform_ios = (environ.get('KIVY_BUILD', '') == 'ios')\n\n        # On android, _sys_platform return 'linux2', so prefer to check the\n        # import of Android module than trying to rely on _sys_platform.\n        if self._platform_android is True:\n            return 'android'\n        elif self._platform_ios is True:\n            return 'ios'\n        elif _sys_platform in ('win32', 'cygwin'):\n            return 'win'\n        elif _sys_platform == 'darwin':\n            return 'macosx'\n        elif _sys_platform[:5] == 'linux':\n            return 'linux'\n        return 'unknown'\n\n\nplatform = Platform()\n'''\nplatform is a string describing the current Operating System. It is one\nof: *win*, *linux*, *android*, *macosx*, *ios* or *unknown*.\nYou can use it as follows::\n\n    from kivy import platform\n    if platform == 'linux':\n        do_linux_things()\n    if platform() == 'linux': # triggers deprecation warning\n        do_more_linux_things()\n\n.. versionadded:: 1.3.0\n\n.. versionchanged:: 1.8.0\n\n    platform is now a variable instead of a  function.\n\n'''\n\n\ndef escape_markup(text):\n    '''\n    Escape markup characters found in the text. Intended to be used when markup\n    text is activated on the Label::\n\n        untrusted_text = escape_markup('Look at the example [1]')\n        text = '[color=ff0000]' + untrusted_text + '[/color]'\n        w = Label(text=text, markup=True)\n\n    .. versionadded:: 1.3.0\n    '''\n    return text.replace('&', '&amp;').replace('[', '&bl;').replace(']', '&br;')\n\n\nclass reify(object):\n    '''\n    Put the result of a method which uses this (non-data) descriptor decorator\n    in the instance dict after the first call, effectively replacing the\n    decorator with an instance variable.\n\n    It acts like @property, except that the function is only ever called once;\n    after that, the value is cached as a regular attribute. This gives you lazy\n    attribute creation on objects that are meant to be immutable.\n\n    Taken from the `Pyramid project <https://pypi.python.org/pypi/pyramid/>`_.\n\n    To use this as a decorator::\n\n         @reify\n         def lazy(self):\n              ...\n              return hard_to_compute_int\n         first_time = self.lazy   # lazy is reify obj, reify.__get__() runs\n         second_time = self.lazy  # lazy is hard_to_compute_int\n    '''\n\n    def __init__(self, func):\n        self.func = func\n        self.__doc__ = func.__doc__\n\n    def __get__(self, inst, cls):\n        if inst is None:\n            return self\n        retval = self.func(inst)\n        setattr(inst, self.func.__name__, retval)\n        return retval\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/vector.py",
    "content": "'''Vector\n======\n\nThe :class:`Vector` represents a 2D vector (x, y).\nOur implementation is built on top of a Python list.\n\n An example of constructing a Vector::\n\n    >>> # Construct a point at 82,34\n    >>> v = Vector(82, 34)\n    >>> v[0]\n    82\n    >>> v.x\n    82\n    >>> v[1]\n    34\n    >>> v.y\n    34\n\n    >>> # Construct by giving a list of 2 values\n    >>> pos = (93, 45)\n    >>> v = Vector(pos)\n    >>> v[0]\n    93\n    >>> v.x\n    93\n    >>> v[1]\n    45\n    >>> v.y\n    45\n\n\nOptimized usage\n---------------\n\nMost of the time, you can use a list for arguments instead of using a\nVector. For example, if you want to calculate the distance between 2\npoints::\n\n    a = (10, 10)\n    b = (87, 34)\n\n    # optimized method\n    print('distance between a and b:', Vector(a).distance(b))\n\n    # non-optimized method\n    va = Vector(a)\n    vb = Vector(b)\n    print('distance between a and b:', va.distance(vb))\n\n\nVector operators\n----------------\n\nThe :class:`Vector` supports some numeric operators such as +, -, /::\n\n    >>> Vector(1, 1) + Vector(9, 5)\n    [10, 6]\n\n    >>> Vector(9, 5) - Vector(5, 5)\n    [4, 0]\n\n    >>> Vector(10, 10) / Vector(2., 4.)\n    [5.0, 2.5]\n\n    >>> Vector(10, 10) / 5.\n    [2.0, 2.0]\n\n\nYou can also use in-place operators::\n\n    >>> v = Vector(1, 1)\n    >>> v += 2\n    >>> v\n    [3, 3]\n    >>> v *= 5\n    [15, 15]\n    >>> v /= 2.\n    [7.5, 7.5]\n\n'''\n\n__all__ = ('Vector', )\n\nimport math\n\n\nclass Vector(list):\n    '''Vector class. See module documentation for more information.\n    '''\n\n    def __init__(self, *largs):\n        if len(largs) == 1:\n            super(Vector, self).__init__(largs[0])\n        elif len(largs) == 2:\n            super(Vector, self).__init__(largs)\n        else:\n            raise Exception('Invalid vector')\n\n    def _get_x(self):\n        return self[0]\n\n    def _set_x(self, x):\n        self[0] = x\n\n    x = property(_get_x, _set_x)\n    ''':attr:`x` represents the first element in the list.\n\n    >>> v = Vector(12, 23)\n    >>> v[0]\n    12\n    >>> v.x\n    12\n    '''\n\n    def _get_y(self):\n        return self[1]\n\n    def _set_y(self, y):\n        self[1] = y\n\n    y = property(_get_y, _set_y)\n    ''':attr:`y` represents the second element in the list.\n\n    >>> v = Vector(12, 23)\n    >>> v[1]\n    23\n    >>> v.y\n    23\n\n    '''\n\n    def __getslice__(self, i, j):\n        try:\n            # use the list __getslice__ method and convert\n            # result to vector\n            return Vector(super(Vector, self).__getslice__(i, j))\n        except Exception:\n            raise TypeError('vector::FAILURE in __getslice__')\n\n    def __add__(self, val):\n        return Vector(list(map(lambda x, y: x + y, self, val)))\n\n    def __iadd__(self, val):\n        if type(val) in (int, float):\n            self.x += val\n            self.y += val\n        else:\n            self.x += val.x\n            self.y += val.y\n        return self\n\n    def __neg__(self):\n        return Vector([-x for x in self])\n\n    def __sub__(self, val):\n        return Vector(list(map(lambda x, y: x - y, self, val)))\n\n    def __isub__(self, val):\n        if type(val) in (int, float):\n            self.x -= val\n            self.y -= val\n        else:\n            self.x -= val.x\n            self.y -= val.y\n        return self\n\n    def __mul__(self, val):\n        try:\n            return Vector(list(map(lambda x, y: x * y, self, val)))\n        except Exception:\n            return Vector([x * val for x in self])\n\n    def __imul__(self, val):\n        if type(val) in (int, float):\n            self.x *= val\n            self.y *= val\n        else:\n            self.x *= val.x\n            self.y *= val.y\n        return self\n\n    def __rmul__(self, val):\n        return (self * val)\n\n    def __truediv__(self, val):\n        try:\n            return Vector(list(map(lambda x, y: x / y, self, val)))\n        except Exception:\n            return Vector([x / val for x in self])\n\n    def __div__(self, val):\n        try:\n            return Vector(list(map(lambda x, y: x / y, self, val)))\n        except Exception:\n            return Vector([x / val for x in self])\n\n    def __rtruediv__(self, val):\n        try:\n            return Vector(*val) / self\n        except Exception:\n            return Vector(val, val) / self\n\n    def __rdiv__(self, val):\n        try:\n            return Vector(*val) / self\n        except Exception:\n            return Vector(val, val) / self\n\n    def __idiv__(self, val):\n        if type(val) in (int, float):\n            self.x /= val\n            self.y /= val\n        else:\n            self.x /= val.x\n            self.y /= val.y\n        return self\n\n    def length(self):\n        '''Returns the length of a vector.\n\n        >>> Vector(10, 10).length()\n        14.142135623730951\n        >>> pos = (10, 10)\n        >>> Vector(pos).length()\n        14.142135623730951\n\n        '''\n        return math.sqrt(self[0] ** 2 + self[1] ** 2)\n\n    def length2(self):\n        '''Returns the length of a vector squared.\n\n        >>> Vector(10, 10).length2()\n        200\n        >>> pos = (10, 10)\n        >>> Vector(pos).length2()\n        200\n\n        '''\n        return self[0] ** 2 + self[1] ** 2\n\n    def distance(self, to):\n        '''Returns the distance between two points.\n\n        >>> Vector(10, 10).distance((5, 10))\n        5.\n        >>> a = (90, 33)\n        >>> b = (76, 34)\n        >>> Vector(a).distance(b)\n        14.035668847618199\n\n        '''\n        return math.sqrt((self[0] - to[0]) ** 2 + (self[1] - to[1]) ** 2)\n\n    def distance2(self, to):\n        '''Returns the distance between two points squared.\n\n        >>> Vector(10, 10).distance2((5, 10))\n        25\n\n        '''\n        return (self[0] - to[0]) ** 2 + (self[1] - to[1]) ** 2\n\n    def normalize(self):\n        '''Returns a new vector that has the same direction as vec,\n        but has a length of one.\n\n        >>> v = Vector(88, 33).normalize()\n        >>> v\n        [0.93632917756904444, 0.3511234415883917]\n        >>> v.length()\n        1.0\n\n        '''\n        if self[0] == 0. and self[1] == 0.:\n            return Vector(0., 0.)\n        return self / self.length()\n\n    def dot(self, a):\n        '''Computes the dot product of a and b.\n\n        >>> Vector(2, 4).dot((2, 2))\n        12\n\n        '''\n        return self[0] * a[0] + self[1] * a[1]\n\n    def angle(self, a):\n        '''Computes the angle between a and b, and returns the angle in\n        degrees.\n\n        >>> Vector(100, 0).angle((0, 100))\n        -90.0\n        >>> Vector(87, 23).angle((-77, 10))\n        -157.7920283010705\n\n        '''\n        angle = -(180 / math.pi) * math.atan2(\n            self[0] * a[1] - self[1] * a[0],\n            self[0] * a[0] + self[1] * a[1])\n        return angle\n\n    def rotate(self, angle):\n        '''Rotate the vector with an angle in degrees.\n\n        >>> v = Vector(100, 0)\n        >>> v.rotate(45)\n        >>> v\n        [70.710678118654755, 70.710678118654741]\n\n        '''\n        angle = math.radians(angle)\n        return Vector(\n            (self[0] * math.cos(angle)) - (self[1] * math.sin(angle)),\n            (self[1] * math.cos(angle)) + (self[0] * math.sin(angle)))\n\n    @staticmethod\n    def line_intersection(v1, v2, v3, v4):\n        '''\n        Finds the intersection point between the lines (1)v1->v2 and (2)v3->v4\n        and returns it as a vector object.\n\n        >>> a = (98, 28)\n        >>> b = (72, 33)\n        >>> c = (10, -5)\n        >>> d = (20, 88)\n        >>> Vector.line_intersection(a, b, c, d)\n        [15.25931928687196, 43.911669367909241]\n\n        .. warning::\n\n            This is a line intersection method, not a segment intersection.\n\n        For math see: http://en.wikipedia.org/wiki/Line-line_intersection\n        '''\n        #linear algebar sucks...seriously!!\n        x1, x2, x3, x4 = float(v1[0]), float(v2[0]), float(v3[0]), float(v4[0])\n        y1, y2, y3, y4 = float(v1[1]), float(v2[1]), float(v3[1]), float(v4[1])\n\n        u = (x1 * y2 - y1 * x2)\n        v = (x3 * y4 - y3 * x4)\n        denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)\n        if denom == 0:\n            return None\n\n        px = (u * (x3 - x4) - (x1 - x2) * v) / denom\n        py = (u * (y3 - y4) - (y1 - y2) * v) / denom\n\n        return Vector(px, py)\n\n    @staticmethod\n    def segment_intersection(v1, v2, v3, v4):\n        '''\n        Finds the intersection point between segments (1)v1->v2 and (2)v3->v4\n        and returns it as a vector object.\n\n        >>> a = (98, 28)\n        >>> b = (72, 33)\n        >>> c = (10, -5)\n        >>> d = (20, 88)\n        >>> Vector.segment_intersection(a, b, c, d)\n        None\n\n        >>> a = (0, 0)\n        >>> b = (10, 10)\n        >>> c = (0, 10)\n        >>> d = (10, 0)\n        >>> Vector.segment_intersection(a, b, c, d)\n        [5, 5]\n        '''\n        #Yaaay! I love linear algebra applied within the realms of geometry.\n        x1, x2, x3, x4 = float(v1[0]), float(v2[0]), float(v3[0]), float(v4[0])\n        y1, y2, y3, y4 = float(v1[1]), float(v2[1]), float(v3[1]), float(v4[1])\n        #This is mostly the same as the line_intersection\n        u = (x1 * y2 - y1 * x2)\n        v = (x3 * y4 - y3 * x4)\n        denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)\n        if denom == 0:\n            return None\n\n        px = (u * (x3 - x4) - (x1 - x2) * v) / denom\n        py = (u * (y3 - y4) - (y1 - y2) * v) / denom\n        #Here are the new bits\n        c1 = (x1 <= px <= x2) or (x2 <= px <= x1)\n        c2 = (y1 <= py <= y2) or (y2 <= py <= y1)\n        c3 = (x3 <= px <= x4) or (x4 <= px <= x3)\n        c4 = (y3 <= py <= y4) or (y4 <= py <= y3)\n\n        if (c1 and c2) and (c3 and c4):\n            return Vector(px, py)\n        else:\n            return None\n\n    @staticmethod\n    def in_bbox(point, a, b):\n        '''Return True if `point` is in the bounding box defined by `a`\n        and `b`.\n\n        >>> bmin = (0, 0)\n        >>> bmax = (100, 100)\n        >>> Vector.in_bbox((50, 50), bmin, bmax)\n        True\n        >>> Vector.in_bbox((647, -10), bmin, bmax)\n        False\n\n        '''\n        return ((point[0] <= a[0] and point[0] >= b[0] or\n                 point[0] <= b[0] and point[0] >= a[0]) and\n                (point[1] <= a[1] and point[1] >= b[1] or\n                 point[1] <= b[1] and point[1] >= a[1]))\n"
  },
  {
    "path": "tickeys/kivy_32/kivy/weakmethod.py",
    "content": "'''\nWeak Method\n===========\n\nThe :class:`WeakMethod` is used by the :class:`~kivy.clock.Clock` class to\nallow references to a bound method that permits the associated object to\nbe garbage collected. Please refer to\n`examples/core/clock_method.py` for more information.\n\nThis WeakMethod class is taken from the recipe\nhttp://code.activestate.com/recipes/81253/, based on the nicodemus version.\nMany thanks nicodemus!\n'''\n\nimport weakref\nimport sys\n\nif sys.version > '3':\n\n    class WeakMethod:\n        '''Implementation of a\n        `weakref <http://en.wikipedia.org/wiki/Weak_reference>`_\n        for functions and bound methods.\n        '''\n        def __init__(self, method):\n            self.method = None\n            self.method_name = None\n            try:\n                if method.__self__ is not None:\n                    self.method_name = method.__func__.__name__\n                    self.proxy = weakref.proxy(method.__self__)\n                else:\n                    self.method = method\n                    self.proxy = None\n            except AttributeError:\n                self.method = method\n                self.proxy = None\n\n        def __call__(self):\n            '''Return a new bound-method like the original, or the\n            original function if it was just a function or unbound\n            method.\n            Returns None if the original object doesn't exist.\n            '''\n            try:\n                if self.proxy:\n                    return getattr(self.proxy, self.method_name)\n            except ReferenceError:\n                pass\n            return self.method\n\n        def is_dead(self):\n            '''Returns True if the referenced callable was a bound method and\n            the instance no longer exists. Otherwise, return False.\n            '''\n            return self.proxy is not None and not bool(dir(self.proxy))\n\n        def __repr__(self):\n            return '<WeakMethod proxy={} method={} method_name={}>'.format(\n                   self.proxy, self.method, self.method_name)\n\nelse:\n\n    import new\n\n    class WeakMethod(object):\n        '''Implementation of a\n        `weakref <http://en.wikipedia.org/wiki/Weak_reference>`_\n        for functions and bound methods.\n        '''\n\n        def __init__(self, method):\n            try:\n                if method.__self__ is not None:\n                    # bound method\n                    self._obj = weakref.ref(method.im_self)\n                else:\n                    # unbound method\n                    self._obj = None\n                self._func = method.im_func\n                self._class = method.im_class\n            except AttributeError:\n                # not a method\n                self._obj = None\n                self._func = method\n                self._class = None\n\n        def __call__(self):\n            '''Return a new bound-method like the original, or the\n            original function if it was just a function or unbound\n            method.\n            Returns None if the original object doesn't exist.\n            '''\n            if self.is_dead():\n                return None\n            if self._obj is not None:\n                return new.instancemethod(self._func, self._obj(), self._class)\n            else:\n                # we don't have an instance: return just the function\n                return self._func\n\n        def is_dead(self):\n            '''Returns True if the referenced callable was a bound method and\n            the instance no longer exists. Otherwise, return False.\n            '''\n            return self._obj is not None and self._obj() is None\n\n        def __eq__(self, other):\n            try:\n                return type(self) is type(other) and self() == other()\n            except:\n                return False\n\n        def __ne__(self, other):\n            return not self == other\n"
  },
  {
    "path": "tickeys/locale/en_US/LC_MESSAGES/tickeys.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the PACKAGE package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"Report-Msgid-Bugs-To: Xiongbiao Huang<billo@qq.com>\\n\"\n\"POT-Creation-Date: 2016-08-02 14:39+0800\\n\"\n\"PO-Revision-Date: 2016-08-02 14:39+0800\\n\"\n\"Last-Translator: Xiongbiao Huang<billo@qq.com>\\n\"\n\"Language-Team: US English Huang<billo@qq.com>\\n\"\n\"Language: en_US\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\nmsgid \"Sound Style Items\"\nmsgstr \"['Bubble', 'Typewriter', 'Mechanical', 'Sword', 'Cherry G80-3000', 'Cherry G80-3494', 'Drum']\"\n\nmsgid \"Startup Notify\"\nmsgstr \"<span style='color: #00B8CB; font-size:15px'>Tickeys</span> is running now.\\nPress <span style='color: #00B8CB'>QAZ123</span> to show the window!\"\n\nmsgid \"Update Notify\"\nmsgstr \"<span style='color: #00B8CB; font-size:15px'>Tickeys</span> has available <span style='color: #FF4500'>update now：</span>\\n latest version：%s \\n latest content：%s\"\n"
  },
  {
    "path": "tickeys/locale/gen_mo.sh",
    "content": "msgfmt -o zh_CN/LC_MESSAGES/tickeys.mo zh_CN/LC_MESSAGES/tickeys.po\nmsgfmt -o en_US/LC_MESSAGES/tickeys.mo en_US/LC_MESSAGES/tickeys.po"
  },
  {
    "path": "tickeys/locale/zh_CN/LC_MESSAGES/tickeys.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the PACKAGE package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"Report-Msgid-Bugs-To: Xiongbiao Huang<billo@qq.com>\\n\"\n\"POT-Creation-Date: 2016-08-02 14:39+0800\\n\"\n\"PO-Revision-Date: 2016-08-02 14:39+0800\\n\"\n\"Last-Translator: Xiongbiao Huang<billo@qq.com>\\n\"\n\"Language-Team: CN Chinese Huang<billo@qq.com>\\n\"\n\"Language: zh_CN\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: GUI.py:180\nmsgid \"Volume\"\nmsgstr \"音量\"\n\nmsgid \"Pitch\"\nmsgstr \"音调\"\n\nmsgid \"Sound Style\"\nmsgstr \"声音方案\"\n\nmsgid \"Sound Style Items\"\nmsgstr \"['冒泡', '打字机', '机械键盘', '剑气', 'Cherry G80-3000', 'Cherry G80-3494', '爆裂鼓手']\"\n\nmsgid \"Start at startup\"\nmsgstr \"开机时自启动\"\n\nmsgid \"Quit\"\nmsgstr \"退出\"\n\nmsgid \"Hide\"\nmsgstr \"隐藏\"\n\nmsgid \"Author\"\nmsgstr \"作者\"\n\nmsgid \"Project Website\"\nmsgstr \"项目主页\"\n\nmsgid \"Startup Notify\"\nmsgstr \"<span style='color: #00B8CB; font-size:15px'>Tickeys</span>正在运行\\n随时按<span style='color: #00B8CB'>QAZ123</span>唤出设置窗口\"\n\nmsgid \"Update Notify\"\nmsgstr \"<span style='color: #00B8CB; font-size:15px'>Tickeys</span>有可用的<span style='color: #FF4500'>更新：</span>\\n 版本：%s \\n 内容：%s\"\n\nmsgid \"This will take effect next time you start\"\nmsgstr \"这将会在下次启动时生效\""
  },
  {
    "path": "tickeys/logger.py",
    "content": "#!/usr/bin/env python\n# coding: utf-8\nimport logging\nimport os\n\n# 创建一个logger\nlogger = logging.getLogger(\"logger\")\nlogger.setLevel(logging.DEBUG)\n\n# 创建一个handler，用于输出到控制台\nsh = logging.StreamHandler()\nsh.setLevel(logging.INFO)\n\n# 创建一个handler，用于写入日志文件\nfh = logging.FileHandler(os.environ[\"HOME\"] + \"/.tickeys/tickeys.log\")\nfh.setLevel(logging.DEBUG)\n\n# 定义handler的输出格式\n# fhfmt = logging.Formatter(\n#     '[%(levelname)s] %(asctime)s %(filename)s[line:%(lineno)d] %(message)s')\nfhfmt = logging.Formatter(\n    '%(message)s  -%(filename)s[line:%(lineno)d]')\nshfmt = logging.Formatter(\n    '%(message)s')\nfh.setFormatter(fhfmt)\nsh.setFormatter(shfmt)\n\nlogger.addHandler(sh)\nlogger.addHandler(fh)\nlogger.debug('test')\n"
  },
  {
    "path": "tickeys/pyxhook.py",
    "content": "#!/usr/bin/python\n#\n# pyxhook -- an extension to emulate some of the PyHook library on linux.\n#\n#    Copyright (C) 2008 Tim Alexander <dragonfyre13@gmail.com>\n#\n#    This program is free software; you can redistribute it and/or modify\n#    it under the terms of the GNU General Public License as published by\n#    the Free Software Foundation; either version 2 of the License, or\n#    (at your option) any later version.\n#\n#    This program is distributed in the hope that it will be useful,\n#    but WITHOUT ANY WARRANTY; without even the implied warranty of\n#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n#    GNU General Public License for more details.\n#\n#    You should have received a copy of the GNU General Public License\n#    along with this program; if not, write to the Free Software\n#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n#\n#    Thanks to Alex Badea <vamposdecampos@gmail.com> for writing the Record\n#    demo for the xlib libraries. It helped me immensely working with these\n#    in this library.\n#\n#    Thanks to the python-xlib team. This wouldn't have been possible without\n#    your code.\n#\n#    This requires:\n#    at least python-xlib 1.4\n#    xwindows must have the \"record\" extension present, and active.\n#\n#    This file has now been somewhat extensively modified by\n#    Daniel Folkinshteyn <nanotube@users.sf.net>\n#    So if there are any bugs, they are probably my fault. :)\n\nimport sys\nimport os\nimport re\nimport time\nimport threading\n\nfrom Xlib import X, XK, display, error\nfrom Xlib.ext import record\nfrom Xlib.protocol import rq\n\n#######################################################################\n########################START CLASS DEF################################\n#######################################################################\n\nclass HookManager(threading.Thread):\n    \"\"\"This is the main class. Instantiate it, and you can hand it KeyDown and KeyUp (functions in your own code) which execute to parse the pyxhookkeyevent class that is returned.\n    This simply takes these two values for now:\n    KeyDown = The function to execute when a key is pressed, if it returns anything. It hands the function an argument that is the pyxhookkeyevent class.\n    KeyUp = The function to execute when a key is released, if it returns anything. It hands the function an argument that is the pyxhookkeyevent class.\n    \"\"\"\n\n    def __init__(self):\n        threading.Thread.__init__(self)\n        self.finished = threading.Event()\n\n        # Give these some initial values\n        self.mouse_position_x = 0\n        self.mouse_position_y = 0\n        self.ison = {\"shift\":False, \"caps\":False}\n\n        # Compile our regex statements.\n        self.isshift = re.compile('^Shift')\n        self.iscaps = re.compile('^Caps_Lock')\n        self.shiftablechar = re.compile('^[a-z0-9]$|^minus$|^equal$|^bracketleft$|^bracketright$|^semicolon$|^backslash$|^apostrophe$|^comma$|^period$|^slash$|^grave$')\n        self.logrelease = re.compile('.*')\n        self.isspace = re.compile('^space$')\n\n        # Assign default function actions (do nothing).\n        self.KeyDown = lambda x: True\n        self.KeyUp = lambda x: True\n        self.MouseAllButtonsDown = lambda x: True\n        self.MouseAllButtonsUp = lambda x: True\n        self.MouseMovement = lambda x: True\n\n        self.contextEventMask = [X.KeyPress,X.MotionNotify]\n\n        # Hook to our display.\n        self.local_dpy = display.Display()\n        self.record_dpy = display.Display()\n\n    def run(self):\n        # Check if the extension is present\n        if not self.record_dpy.has_extension(\"RECORD\"):\n            print(\"RECORD extension not found\")\n            sys.exit(1)\n        r = self.record_dpy.record_get_version(0, 0)\n        print(\"RECORD extension version %d.%d\" % (r.major_version, r.minor_version))\n\n        # Create a recording context; we only want key and mouse events\n        self.ctx = self.record_dpy.record_create_context(\n                0,\n                [record.AllClients],\n                [{\n                        'core_requests': (0, 0),\n                        'core_replies': (0, 0),\n                        'ext_requests': (0, 0, 0, 0),\n                        'ext_replies': (0, 0, 0, 0),\n                        'delivered_events': (0, 0),\n                        'device_events': tuple(self.contextEventMask), #(X.KeyPress, X.ButtonPress),\n                        'errors': (0, 0),\n                        'client_started': False,\n                        'client_died': False,\n                }])\n\n        # Enable the context; this only returns after a call to record_disable_context,\n        # while calling the callback function in the meantime\n        self.record_dpy.record_enable_context(self.ctx, self.processevents)\n        # Finally free the context\n        self.record_dpy.record_free_context(self.ctx)\n\n    def cancel(self):\n        self.finished.set()\n        self.local_dpy.record_disable_context(self.ctx)\n        self.local_dpy.flush()\n\n    def printevent(self, event):\n        print(event)\n\n    def HookKeyboard(self):\n        pass\n        # We don't need to do anything here anymore, since the default mask\n        # is now set to contain X.KeyPress\n        #self.contextEventMask[0] = X.KeyPress\n\n    def HookMouse(self):\n        pass\n        # We don't need to do anything here anymore, since the default mask\n        # is now set to contain X.MotionNotify\n\n        # need mouse motion to track pointer position, since ButtonPress events\n        # don't carry that info.\n        #self.contextEventMask[1] = X.MotionNotify\n\n    def processevents(self, reply):\n        if reply.category != record.FromServer:\n            return\n        if reply.client_swapped:\n            print(\"* received swapped protocol data, cowardly ignored\")\n            return\n        if not len(reply.data) or ord(reply.data[0]) < 2:\n            # not an event\n            return\n        data = reply.data\n        while len(data):\n            event, data = rq.EventField(None).parse_binary_value(data, self.record_dpy.display, None, None)\n            if event.type == X.KeyPress:\n                hookevent = self.keypressevent(event)\n                self.KeyDown(hookevent)\n            elif event.type == X.KeyRelease:\n                hookevent = self.keyreleaseevent(event)\n                self.KeyUp(hookevent)\n            elif event.type == X.ButtonPress:\n                hookevent = self.buttonpressevent(event)\n                self.MouseAllButtonsDown(hookevent)\n            elif event.type == X.ButtonRelease:\n                hookevent = self.buttonreleaseevent(event)\n                self.MouseAllButtonsUp(hookevent)\n            elif event.type == X.MotionNotify:\n                # use mouse moves to record mouse position, since press and release events\n                # do not give mouse position info (event.root_x and event.root_y have\n                # bogus info).\n                hookevent = self.mousemoveevent(event)\n                self.MouseMovement(hookevent)\n\n        #print \"processing events...\", event.type\n\n    def keypressevent(self, event):\n        matchto = self.lookup_keysym(self.local_dpy.keycode_to_keysym(event.detail, 0))\n        if self.shiftablechar.match(self.lookup_keysym(self.local_dpy.keycode_to_keysym(event.detail, 0))): ## This is a character that can be typed.\n            if self.ison[\"shift\"] == False:\n                keysym = self.local_dpy.keycode_to_keysym(event.detail, 0)\n                return self.makekeyhookevent(keysym, event)\n            else:\n                keysym = self.local_dpy.keycode_to_keysym(event.detail, 1)\n                return self.makekeyhookevent(keysym, event)\n        else: ## Not a typable character.\n            keysym = self.local_dpy.keycode_to_keysym(event.detail, 0)\n            if self.isshift.match(matchto):\n                self.ison[\"shift\"] = self.ison[\"shift\"] + 1\n            elif self.iscaps.match(matchto):\n                if self.ison[\"caps\"] == False:\n                    self.ison[\"shift\"] = self.ison[\"shift\"] + 1\n                    self.ison[\"caps\"] = True\n                if self.ison[\"caps\"] == True:\n                    self.ison[\"shift\"] = self.ison[\"shift\"] - 1\n                    self.ison[\"caps\"] = False\n            return self.makekeyhookevent(keysym, event)\n\n    def keyreleaseevent(self, event):\n        if self.shiftablechar.match(self.lookup_keysym(self.local_dpy.keycode_to_keysym(event.detail, 0))):\n            if self.ison[\"shift\"] == False:\n                keysym = self.local_dpy.keycode_to_keysym(event.detail, 0)\n            else:\n                keysym = self.local_dpy.keycode_to_keysym(event.detail, 1)\n        else:\n            keysym = self.local_dpy.keycode_to_keysym(event.detail, 0)\n        matchto = self.lookup_keysym(keysym)\n        if self.isshift.match(matchto):\n            self.ison[\"shift\"] = self.ison[\"shift\"] - 1\n        return self.makekeyhookevent(keysym, event)\n\n    def buttonpressevent(self, event):\n        #self.clickx = self.rootx\n        #self.clicky = self.rooty\n        return self.makemousehookevent(event)\n\n    def buttonreleaseevent(self, event):\n        #if (self.clickx == self.rootx) and (self.clicky == self.rooty):\n            ##print \"ButtonClick \" + str(event.detail) + \" x=\" + str(self.rootx) + \" y=\" + str(self.rooty)\n            #if (event.detail == 1) or (event.detail == 2) or (event.detail == 3):\n                #self.captureclick()\n        #else:\n            #pass\n\n        return self.makemousehookevent(event)\n\n        #    sys.stdout.write(\"ButtonDown \" + str(event.detail) + \" x=\" + str(self.clickx) + \" y=\" + str(self.clicky) + \"\\n\")\n        #    sys.stdout.write(\"ButtonUp \" + str(event.detail) + \" x=\" + str(self.rootx) + \" y=\" + str(self.rooty) + \"\\n\")\n        #sys.stdout.flush()\n\n    def mousemoveevent(self, event):\n        self.mouse_position_x = event.root_x\n        self.mouse_position_y = event.root_y\n        return self.makemousehookevent(event)\n\n    # need the following because XK.keysym_to_string() only does printable chars\n    # rather than being the correct inverse of XK.string_to_keysym()\n    def lookup_keysym(self, keysym):\n        for name in dir(XK):\n            if name.startswith(\"XK_\") and getattr(XK, name) == keysym:\n                return name.lstrip(\"XK_\")\n        return \"[%d]\" % keysym\n\n    def asciivalue(self, keysym):\n        asciinum = XK.string_to_keysym(self.lookup_keysym(keysym))\n        if asciinum < 256:\n            return asciinum\n        else:\n            return 0\n\n    def makekeyhookevent(self, keysym, event):\n        storewm = self.xwindowinfo()\n        if event.type == X.KeyPress:\n            MessageName = \"key down\"\n        elif event.type == X.KeyRelease:\n            MessageName = \"key up\"\n        return pyxhookkeyevent(storewm[\"handle\"], storewm[\"name\"], storewm[\"class\"], self.lookup_keysym(keysym), self.asciivalue(keysym), False, event.detail, MessageName)\n\n    def makemousehookevent(self, event):\n        storewm = self.xwindowinfo()\n        if event.detail == 1:\n            MessageName = \"mouse left \"\n        elif event.detail == 3:\n            MessageName = \"mouse right \"\n        elif event.detail == 2:\n            MessageName = \"mouse middle \"\n        elif event.detail == 5:\n            MessageName = \"mouse wheel down \"\n        elif event.detail == 4:\n            MessageName = \"mouse wheel up \"\n        else:\n            MessageName = \"mouse \" + str(event.detail) + \" \"\n\n        if event.type == X.ButtonPress:\n            MessageName = MessageName + \"down\"\n        elif event.type == X.ButtonRelease:\n            MessageName = MessageName + \"up\"\n        else:\n            MessageName = \"mouse moved\"\n        return pyxhookmouseevent(storewm[\"handle\"], storewm[\"name\"], storewm[\"class\"], (self.mouse_position_x, self.mouse_position_y), MessageName)\n\n    def xwindowinfo(self):\n        try:\n            windowvar = self.local_dpy.get_input_focus().focus\n            wmname = windowvar.get_wm_name()\n            wmclass = windowvar.get_wm_class()\n            wmhandle = str(windowvar)[20:30]\n        except:\n            ## This is to keep things running smoothly. It almost never happens, but still...\n            return {\"name\":None, \"class\":None, \"handle\":None}\n        if (wmname == None) and (wmclass == None):\n            try:\n                windowvar = windowvar.query_tree().parent\n                wmname = windowvar.get_wm_name()\n                wmclass = windowvar.get_wm_class()\n                wmhandle = str(windowvar)[20:30]\n            except:\n                ## This is to keep things running smoothly. It almost never happens, but still...\n                return {\"name\":None, \"class\":None, \"handle\":None}\n        if wmclass == None:\n            return {\"name\":wmname, \"class\":wmclass, \"handle\":wmhandle}\n        else:\n            return {\"name\":wmname, \"class\":wmclass[0], \"handle\":wmhandle}\n\nclass pyxhookkeyevent:\n    \"\"\"This is the class that is returned with each key event.f\n    It simply creates the variables below in the class.\n\n    Window = The handle of the window.\n    WindowName = The name of the window.\n    WindowProcName = The backend process for the window.\n    Key = The key pressed, shifted to the correct caps value.\n    Ascii = An ascii representation of the key. It returns 0 if the ascii value is not between 31 and 256.\n    KeyID = This is just False for now. Under windows, it is the Virtual Key Code, but that's a windows-only thing.\n    ScanCode = Please don't use this. It differs for pretty much every type of keyboard. X11 abstracts this information anyway.\n    MessageName = \"key down\", \"key up\".\n    \"\"\"\n\n    def __init__(self, Window, WindowName, WindowProcName, Key, Ascii, KeyID, ScanCode, MessageName):\n        self.Window = Window\n        self.WindowName = WindowName\n        self.WindowProcName = WindowProcName\n        self.Key = Key\n        self.Ascii = Ascii\n        self.KeyID = KeyID\n        self.ScanCode = ScanCode\n        self.MessageName = MessageName\n\n    def __str__(self):\n        return \"Window Handle: \" + str(self.Window) + \"\\nWindow Name: \" + str(self.WindowName) + \"\\nWindow's Process Name: \" + str(self.WindowProcName) + \"\\nKey Pressed: \" + str(self.Key) + \"\\nAscii Value: \" + str(self.Ascii) + \"\\nKeyID: \" + str(self.KeyID) + \"\\nScanCode: \" + str(self.ScanCode) + \"\\nMessageName: \" + str(self.MessageName) + \"\\n\"\n\nclass pyxhookmouseevent:\n    \"\"\"This is the class that is returned with each key event.f\n    It simply creates the variables below in the class.\n\n    Window = The handle of the window.\n    WindowName = The name of the window.\n    WindowProcName = The backend process for the window.\n    Position = 2-tuple (x,y) coordinates of the mouse click\n    MessageName = \"mouse left|right|middle down\", \"mouse left|right|middle up\".\n    \"\"\"\n\n    def __init__(self, Window, WindowName, WindowProcName, Position, MessageName):\n        self.Window = Window\n        self.WindowName = WindowName\n        self.WindowProcName = WindowProcName\n        self.Position = Position\n        self.MessageName = MessageName\n\n    def __str__(self):\n        return \"Window Handle: \" + str(self.Window) + \"\\nWindow Name: \" + str(self.WindowName) + \"\\nWindow's Process Name: \" + str(self.WindowProcName) + \"\\nPosition: \" + str(self.Position) + \"\\nMessageName: \" + str(self.MessageName) + \"\\n\"\n\n#######################################################################\n#########################END CLASS DEF#################################\n#######################################################################\n\nif __name__ == '__main__':\n    hm = HookManager()\n    hm.HookKeyboard()\n    hm.KeyDown = hm.printevent\n    hm.KeyUp = hm.printevent\n    hm.start()\n\n"
  },
  {
    "path": "tickeys/requirements.txt",
    "content": "cython==0.20.2\nkivy==1.9.0\nsetuptools==19.2\npyinstaller==3.0\nsounddevice\nsoundfile\nnotify2"
  },
  {
    "path": "tickeys/run.py",
    "content": "#!/usr/bin/env python\n# coding: utf-8\nfrom logger import logger\nimport sys\nimport os\nfrom windowManager import check_tickeys_running_status\n\n__author__ = 'Huang xiongbiao(billo@qq.com)'\n\n\ndef run_GUI():\n    check_system()\n    try:\n        from GUI import TickeysApp\n        TickeysApp().run()\n    except Exception, e:\n        logger.exception(e)\n        logger.error(\"Run GUI Fail, reason:\")\n        os._exit(0)\n\n\ndef check_root():\n    logger.info(\"Root checking...\")\n    if os.getegid() != 0:\n        logger.info(\"This program must be run as root..\")\n        sys.exit(0)\n    logger.info(\"Root checking success. You have the root permission\")\n    logger.debug(\"File path:\" + os.path.dirname(__file__))\n\n\ndef check_system():\n    systems = ['Linux', 'SunOS', 'FreeBSD', 'Unix', 'OpenBSD', 'NetBSD']\n    try:\n        logger.info(\"System checking...\")\n        import platform\n        system_name = platform.system()\n        if system_name not in systems:\n            logger.error(\"System %s is not supported.\" % system_name)\n            sys.exit(0)\n        else:\n            logger.info(\"System checking success. Your system is supported\")\n    except Exception, e:\n        logger.error(\"System checking fail:\")\n        logger.exception(e)\n        sys.exit(0)\n\n\ndef main():\n    logger.debug(\"Tickeys start........\")\n    if not os.path.isdir(os.environ[\"HOME\"] + \"/.tickeys\"):\n        os.mkdir(os.environ[\"HOME\"] + \"/.tickeys\")\n    is_running = check_tickeys_running_status()\n    if is_running:\n        return\n    run_GUI()\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "tickeys/run_with_CLI.py",
    "content": "#!/usr/bin/env python\n# coding: utf-8\nfrom logger import logger\nimport sys\nimport os\n\nfrom windowManager import check_tickeys_running_status\n\n__author__ = 'Huang xiongbiao(billo@qq.com)'\n\n\ndef run_GUI():\n    check_root()\n    check_system()\n    try:\n        from GUI import TickeysApp\n        TickeysApp().run()\n    except Exception, e:\n        logger.info(\"Run GUI Fail, use CLI instead..Fail msg:%s\" % str(e))\n        run_CLI()\n\n\ndef run_CLI():\n    check_root()\n    check_system()\n    from CLI import CLI\n    CLI().cmdloop()\n\n\ndef check_root():\n    logger.info(\"Root checking...\")\n    if os.getegid() != 0:\n        logger.info(\"This program must be run as root..\")\n        sys.exit(0)\n    logger.info(\"Root checking success. You have the root permission\")\n    logger.debug(\"File path:\" + os.path.dirname(__file__))\n\n\ndef check_system():\n    systems = ['Linux', 'SunOS', 'FreeBSD', 'Unix', 'OpenBSD', 'NetBSD']\n    try:\n        logger.info(\"System checking...\")\n        import platform\n        system_name = platform.system()\n        if system_name not in systems:\n            logger.error(\"System %s is not supported.\" % system_name)\n            sys.exit(0)\n        else:\n            logger.info(\"System checking success. Your system is supported\")\n    except Exception, e:\n        logger.error(\"System checking fail:\" + str(e))\n        sys.exit(0)\n\n\ndef print_help_msg():\n    print \"Tickeys will run GUI by default\"\n    print \"Usage: -c     ---CLI mode\"\n    print \"       -g     ---GUI mode\"\n\n\ndef main():\n    logger.debug(\"Tickeys start........\")\n    is_running = check_tickeys_running_status()\n    if is_running:\n        return\n    if len(sys.argv) == 1:\n        run_GUI()\n    elif len(sys.argv) == 2:\n        if sys.argv[1] == '-g':\n            del sys.argv[1]  # otherwise kivy would regard it as option\n            run_GUI()\n        elif sys.argv[1] == '-c':\n            run_CLI()\n        else:\n            print_help_msg()\n    else:\n        print_help_msg()\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "tickeys/soundPlayer.py",
    "content": "#!/usr/bin/env python\n# coding: utf-8\nimport soundfile as sf\nimport sounddevice as sd\nimport threading\nfrom logger import logger\nfrom config import configer\nimport json\nimport os\n\n\n__author__ = 'Huang xiongbiao(billo@qq.com)'\n\n\nclass SoundPlayer():\n\n    def __init__(self):\n        try:\n            os.chdir(os.path.dirname(__file__))\n        except Exception:\n            pass\n        self.schemes = dict(\n            (i['name'], i)\n            for i in json.load(file('./Resources/data/schemes.json')))\n        self.configer = configer\n        self.sound_file_list = self.schemes[self.configer.style]['files']\n        self.key_audio_map = self.schemes[self.configer.style]['key_audio_map']\n        self.non_unique_count = self.schemes[self.configer.style]['non_unique_count']\n        self.sound_effect_cache = []\n        self.channel = 1\n        self.cache_sound_effect()\n\n    # preload sound effect\n    def cache_sound_effect(self):\n        try:\n            new_sound_effect_cache = []\n            for effect_file in self.sound_file_list:\n                sound_file = './Resources/data/%s/%s' % \\\n                    (self.configer.style, effect_file)\n                logger.debug('Load sound file:' + sound_file)\n                data, fs = sf.read(sound_file)\n                new_sound_effect_cache.append((data, fs))\n            self.sound_effect_cache = new_sound_effect_cache\n\n        except Exception, e:\n            logger.error('Load sound files fail:' + str(e))\n\n    def save_config(func):\n        def _deco(*arg):\n            ret = func(*arg)\n            arg[0].configer.save_config()\n            return ret\n        return _deco\n\n    @save_config\n    def set_style(self, style):\n        try:\n            if self.configer.style == style:\n                return\n            self.configer.style = style\n            self.sound_file_list = self.schemes[style]['files']\n            self.key_audio_map = self.schemes[style]['key_audio_map']\n            self.non_unique_count = self.schemes[style]['non_unique_count']\n            self.cache_sound_effect()\n        except Exception, e:\n            logger.error(e)\n\n    @save_config\n    def set_volume(self, volume):\n        self.configer.volume = volume\n\n    @save_config\n    def set_pitch(self, pitch):\n        self.configer.pitch = pitch\n\n    def get_infor(self):\n        return {\n            'style': self.configer.style,\n            'volume': self.configer.volume,\n            'pitch': self.configer.pitch,\n        }\n\n    def play(self, key):\n        if not self.key_audio_map.get(str(key)):\n            self.key_audio_map[str(key)] = key % self.non_unique_count\n        data, fs = self.sound_effect_cache[self.key_audio_map[str(key)]]\n        data = data * self.configer.volume\n        fs = fs * self.configer.pitch\n        threading.Thread(target=sd.play, args=(data, fs)).start()\n"
  },
  {
    "path": "tickeys/startupHandler.py",
    "content": "#!/usr/bin/env python\n# coding:utf-8\n\nfrom __future__ import with_statement\nfrom logger import logger\nimport os\nimport commands\nfrom config import configer\n\n\nexecutable_filename = \"tickeys\"\npython2 = os.popen('python2 -V 2>&1').read().startswith('Python 2.') and 'python2' or 'python'\nDesktopEntryName = 'Tickeys.desktop'\nStartupPath = ['/etc/xdg/autostart', '~/.config/autostart', '~/.config/openbox/autostart']\n\n\ndef check_startup_file():\n    return bool(configer.autostart)\n\n\ndef delete_startup_linux():\n    try:\n        command_list = []\n        for dirname in map(os.path.expanduser, StartupPath):\n            command_list.append(\"rm %s/%s\" % (dirname, DesktopEntryName))\n        command_str = \" | \".join(command_list)\n        command = \"gksudo --message password \" + command_str\n        commands.getstatusoutput(command)\n        configer.autostart = False\n        configer.save_config()\n    except Exception, e:\n        logger.debug(\"Delete startup fail:\" + str(e))\n        return False\n    return True\n\n\ndef command_exist(command='gksu'):\n    command += ' --help'\n    try:\n        if commands.getstatusoutput(command)[0] != 32512:\n            logger.debug(command + \" exist\")\n            return True\n        else:\n            logger.debug(command + \" dosen't exist\")\n            return False\n    except Exception:\n        logger.debug(command + \" dosen't exist\")\n        return False\n\n\ndef add_startup_linux():\n    filename = os.path.abspath(__file__)\n    dirname = os.path.dirname(filename)\n\n    if os.path.exists(\"/usr/share/applications/Tickeys.desktop\"):\n        # install by deb\n        with open(\"/usr/share/applications/Tickeys.desktop\") as f:\n            DESKTOP_FILE = f.read()\n    elif command_exist('tickeys'):\n        # used pip installed\n        DESKTOP_FILE = '''\\\n[Desktop Entry]\nType=Application\nCategories=Application;\nExec=tickeys\nIcon=%s/tickeys.png\nTerminal=true\nHidden=false\nNoDisplay=false\nStartupNotify=true\nX-GNOME-Autostart-enabled=true\nName=Tickeys\nComment=Instant audio feedback when typing. For Linux.\n''' % dirname\n    else:\n        # not install yet(run in py)\n        DESKTOP_FILE = '''\\\n[Desktop Entry]\nType=Application\nCategories=Application;\nPath=%s\nExec=python run.py\nTerminal=true\nIcon=%s/tickeys.png\nHidden=false\nNoDisplay=false\nStartupNotify=true\nX-GNOME-Autostart-enabled=true\nName=Tickeys\nComment=Instant audio feedback when typing. For Linux.\n''' % (dirname, dirname)\n    try:\n        # it is stupid\n        command_list = []\n        for dirname in map(os.path.expanduser, StartupPath):\n            filename = os.path.join(dirname, DesktopEntryName)\n            command_list.append('\"mkdir -p %s\"' % dirname)\n            command_list.append('echo \"%s\" >> %s' % (DESKTOP_FILE, filename))\n            command_list.append('chmod 777 %s' % filename)\n        command_str = \" | \".join(command_list)\n        command = \"gksudo --message password \" + command_str\n        commands.getstatusoutput(command)\n        configer.autostart = True\n        configer.save_config()\n    except Exception, e:\n        print e\n        logger.debug(\"Add to startup fail:\" + str(e))\n        return False\n    return True\n"
  },
  {
    "path": "tickeys/tickeys",
    "content": "#!/bin/bash\nif [ $# -eq 1 ]; then\n    if [ $1 = \"-g\" ]; then\n        sudo ./run\n    else\n        sudo ./run -c\n    fi\nelse\n    sudo ./run\nfi\n"
  },
  {
    "path": "tickeys/tickeys_tray.py",
    "content": "#!/usr/bin/env python\n# coding:utf-8\n\nimport os\nimport webbrowser\nfrom windowManager import show_GUI\nimport pygtk\nimport gtk\npygtk.require('2.0')\ngtk.gdk.threads_init()\n\n\ntry:\n    import platform\n    import appindicator\nexcept:\n    platform = None\n    appindicator = None\n\n\nclass GtkTray():\n    def __init__(self):\n        logo_filename = 'tickeys.png'\n\n        if platform and appindicator and platform.dist()[0].lower() == 'ubuntu':\n            self.trayicon = self.ubuntu_trayicon(logo_filename)\n        else:\n            self.trayicon = self.gtk_trayicon(logo_filename)\n\n    def ubuntu_trayicon(self, logo_filename):\n        trayicon = appindicator.Indicator('Tickeys', 'indicator-messages', appindicator.CATEGORY_APPLICATION_STATUS)\n        trayicon.set_status(appindicator.STATUS_ACTIVE)\n        trayicon.set_attention_icon('indicator-messages-new')\n        trayicon.set_icon(logo_filename)\n        trayicon.set_menu(self.make_menu())\n\n        return trayicon\n\n    def gtk_trayicon(self, logo_filename):\n        trayicon = gtk.StatusIcon()\n        trayicon.set_from_file(logo_filename)\n\n        trayicon.connect(\n            'popup-menu',\n            lambda i, b, t: self.make_menu().popup(\n                None,\n                None,\n                gtk.status_icon_position_menu,\n                b,\n                t,\n                self.trayicon\n            )\n        )\n        trayicon.connect('activate', self.on_show)\n        trayicon.set_tooltip('Tickeys')\n        trayicon.set_visible(True)\n\n        return trayicon\n\n    def make_menu(self):\n        menu = gtk.Menu()\n        itemlist = [(u'显示界面', self.on_show),\n                    (u'项目Github页', self.show_github_page),\n                    (u'退出', self.on_quit)]\n        for text, callback in itemlist:\n            item = gtk.MenuItem(text)\n            item.connect('activate', callback)\n            item.show()\n            menu.append(item)\n        menu.show()\n        return menu\n\n    def on_show(self, widget=None, data=None):\n        print \"show the UI\"\n        show_GUI()\n\n    def on_quit(self, widget, data=None):\n        # module_init.stop_all()\n        os._exit(0)\n        gtk.main_quit()\n\n    def show_github_page(self, widget=None, data=None):\n        webbrowser.open_new(\"https://github.com/BillBillBillBill/Tickeys-linux\")\n\n    def serve_forever(self):\n        gtk.gdk.threads_enter()\n        gtk.main()\n        gtk.gdk.threads_leave()\n\n\ndef main():\n    sys_tray = GtkTray()\n    sys_tray.serve_forever()\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "tickeys/tickeysui.kv",
    "content": "#:kivy 1.0\n# rename this to Tickeys if using this to instead using load_string method\n\n<Main>:\n    pos: 0,0\n    padding: 50\n    rows: 6\n    row_force_default: True\n    row_default_height: 50\n    spacing: 50\n    orientation: 'vertical'\n\n    canvas:\n        Color:\n            rgb: 0.42, 0.42, 0.42, 1\n        Rectangle:\n            pos: 0,0\n            size: self.size\n    Label:\n        bold: True\n        text: 'Tickeys'\n        font_size: 42\n        size_hint_y: None\n\n    SpinnerRow\n    AdjustVol\n    AdjustPitch\n    ExitAndSwitchRow\n\n    InforRow\n\n\n<AdjustVol>\n    Label:\n        bold: True\n        color: 1, 1, 1, 1\n        font_size: 25\n        size_hint_x: None\n        width: 250\n        text: 'Vol:'\n    Slider:\n        min: 0.0\n        max: 1.0\n        value: 1.0\n        width: 300\n        on_value: root.setVolume(self.value)\n\n<AdjustPitch>\n    Label:\n        bold: True\n        color: 1, 1, 1, 1\n        font_size: 25\n        size_hint_x: None\n        width: 250\n        text: 'Pitch:'\n    Slider:\n        min: 0.0\n        max: 3.0\n        value: 1.0\n        width: 300\n        on_value: root.setPitch(self.value)\n\n\n<SpinnerRow>:\n    Label:\n        bold: True\n        color: 1, 1, 1, 1\n        font_size: 25\n        size_hint_x: None\n        text: \"Sound Effect:\"\n        width: 250\n    EffectSpinner:\n        on_text: root.change_style()\n\n\n<EffectSpinner>:\n    bold: True\n    font_size: 25\n    text: 'bubble'\n    background_color: 2, 2, 2, 1\n    color: 1, 1, 1, 1\n    values:['bubble', 'mechanical', 'sword', 'typewriter',]\n\n<ExitAndSwitchRow>:\n    Label:\n        size_hint_x: None\n        width: root.width/6.0 - 120\n    Label:\n        size_hint_x: None\n        color: 1, 1, 1, 1\n        font_size: 17\n        width: root.width/6.0 + 60\n        text: 'Open at startup:'\n    Switch:\n        size_hint_x: None\n        width: 40\n        id: switcher\n        active: root.have_added\n        on_active: root.add_delete_startup_file(self.active)\n    Label:\n        size_hint_x: None\n        width: root.width/6.0 - 35\n    Button:\n        size_hint_x: None\n        width: 150\n        background_color: 2, 2, 2, 1\n        bold: True\n        text: \"EXIT\"\n        color: 0,0,0,1\n        on_press: root.Exit()\n\n\n\n<InforRow>:\n    Label:\n        color: 0.7, 0.7, 0.7, 1\n        font_size: 23\n        size_hint_x: None\n        text: root.getVersion()\n        width: root.width/3.0\n    Label:\n        color: 0.8, 0.8, 0.8, 1\n        font_size: 20\n        size_hint_x: None\n        markup: True\n        text: \"[ref=->website]Project website[/ref]\"\n        width: root.width/3.0\n        on_ref_press:root.openProjectWebsite()\n    Label:\n        color: 0.8, 0.8, 0.8, 1\n        font_size: 18\n        size_hint_x: None\n        text: \"Author: Bill (billo@qq.com)\"\n        width: root.width/3.0\n        border: 1,1,1,1\n        on_touch_move:\n"
  },
  {
    "path": "tickeys/windowManager.py",
    "content": "# coding: utf-8\nimport commands\n\nfrom logger import logger\nfrom threading import Thread\nimport os\n\n\nterminal_id = os.environ[\"HOME\"] + \"/.tickeys/tickeys_terminal_window_id\"\ngui_id = os.environ[\"HOME\"] + \"/.tickeys/tickeys_GUI_window_id\"\n\n\ndef save_terminal_window_id():\n    try:\n        stat, terminalId = commands.getstatusoutput('xdotool getactivewindow')\n        with open(terminal_id, \"w+\") as f:\n            if stat == 0:\n                f.write(terminalId)\n            else:\n                f.write(0)\n    except Exception, e:\n        logger.error(\"Save terminal window id fail:\" + str(e))\n\n\ndef read_terminal_window_id():\n    with open(terminal_id, \"r\") as f:\n        return f.read()\n\n\ndef hide_terminal():\n    try:\n        terminalId = read_terminal_window_id()\n        if not terminalId:\n            return\n        commands.getstatusoutput(\n            \"xdotool windowactivate --sync %s\" % terminalId)\n        commands.getstatusoutput(\n            \"xdotool getactivewindow windowunmap\")\n    except Exception,e:\n        logger.error(str(e))\n\n\ndef save_GUI_window_id():\n    try:\n        stat, GUIID = commands.getstatusoutput('xdotool getactivewindow')\n        with open(gui_id, \"w+\") as f:\n            if stat == 0:\n                f.write(GUIID)\n            else:\n                f.write(0)\n    except Exception, e:\n        logger.error(\"Save GUI window id fail:\" + str(e))\n\n\ndef read_GUI_window_id():\n    with open(gui_id, \"r\") as f:\n        return f.read()\n\n\ndef hide_GUI():\n    try:\n        GUIID = read_GUI_window_id()\n        commands.getstatusoutput('xdotool windowunmap --sync %s' % GUIID)\n    except Exception, e:\n        logger.error(str(e))\n\n\ndef show_GUI():\n    def show_notify():\n        try:\n            import notify2\n            notify2.init('Tickeys')\n            title = 'Tickeys'\n            body = '程序“xdotool”尚未安装, 无法隐藏窗口。'\n            iconfile = os.getcwd() + '/tickeys.png'\n            notify = notify2.Notification(title, body, iconfile)\n            notify.show()\n        except Exception:\n            return\n    try:\n        GUIID = read_GUI_window_id()\n        if not GUIID or GUIID == \"0\":\n            Thread(target=show_notify).start()\n            return\n        else:\n            # read window ids\n            command = \"xdotool windowmap --sync %s && xdotool windowactivate --sync %s\" % (GUIID, GUIID)\n            stat, output = commands.getstatusoutput(command)\n            return str(stat)\n    except Exception, e:\n        logger.error(str(e))\n        return '256'\n\n\ndef check_tickeys_running_status():\n    save_terminal_window_id()\n    stat = show_GUI()\n    if stat != \"0\":\n        return False\n    else:\n        print \"Tickeys is already running, show it\"\n        return True\n"
  }
]